Google Maps heat maps
We recently received a question whether TMS FNC Maps supports heat maps. Heat maps are supported in Google Maps and we immediately went exploring the capabilities upon this request. More info and a sample about heat maps can be found here: https://developers.google.com/maps/documentation/javascript/examples/layer-heatmap. TMS FNC Maps comes with a lot of great functionality as well as a (lesser visible) customization events and methods to add your own extensions. To add support for heat maps, we had to override 2 virtuals and we can do this by inheriting from the TTMSFNCGoogleMaps class.
Customizing the API URL
TTMSFNCMaps (and TTMSFNCGoogleMaps), expose a lot of virtuals to extend and customize existing or new functionality. To support heat maps, we needed to add an extra parameter to the URL that is required to load the Google Maps JavaScript API. This can be done by overriding the GetHeadLinks procedure.
procedure GetHeadLinks(AList: TTMSFNCMapsLinksList; ACheckReady: Boolean = True); override;
Additionally, we need to change the link to include an additional parameter: “libraries=visualization” to enable the library required to load the heat map layer.
procedure TTMSFNCGoogleMapsEx.GetHeadLinks(AList: TTMSFNCMapsLinksList; ACheckReady: Boolean); begin AList.Add(TTMSFNCMapsLink.CreateScript('https://maps.googleapis.com/maps/api/js?key=' + MapsProperties.GetAPIKey + '&language=' + MapsProperties.GetLocale + '&libraries=visualization', 'text/javascript', 'utf-8', '', True, True)); end;
Adding additional JavaScript functionality
After extending the API URL to load the required libraries we need to add custom JavaScript to visualize the heat map. According to the sample (following the link at the top), we need to add code to visualize heat maps in San Francisco. To add custom JavaScript functionality, override the DoCustomizeMap virtual.
procedure DoCustomizeMap(var ACustomizeMap: string); override;
The code specified in the sample translated to Delphi code is shown below.
procedure TTMSFNCGoogleMapsEx.DoCustomizeMap(var ACustomizeMap: string); var h: string; begin h := 'var heatMapData = [' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.447), weight: 0.5},' + LB + 'new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.445),' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.443), weight: 2},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.441), weight: 3},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.439), weight: 2},' + LB + 'new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.437),' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.435), weight: 0.5},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.447), weight: 3},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.445), weight: 2},' + LB + 'new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.443),' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.441), weight: 0.5},' + LB + 'new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.439),' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.437), weight: 2},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.435), weight: 3}' + LB + '];' + LB + 'var heatmap = new ' + MAPSERVICEVAR + '.visualization.HeatmapLayer({' + LB + ' data: heatMapData' + LB + '});' + LB + 'heatmap.setMap(' + MAPVAR + ');'; ACustomizeMap := h; inherited; end;
Bundling this all together produces the following result.
The complete code snippet (written in FMX, but can be used in any framework)
unit UGoogleMapsHeatMap; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.TMSFNCGoogleMaps, FMX.TMSFNCMaps; type TTMSFNCGoogleMapsEx = class(TTMSFNCGoogleMaps) protected procedure GetHeadLinks(AList: TTMSFNCMapsLinksList; ACheckReady: Boolean = True); override; procedure DoCustomizeMap(var ACustomizeMap: string); override; end; TFormHeatMap = class(TForm) procedure FormCreate(Sender: TObject); private g: TTMSFNCGoogleMapsEx; { Private declarations } procedure DoMapInitialized(Sender: TObject); public { Public declarations } end; var FormHeatMap: TFormHeatMap; implementation uses FMX.TMSFNCMaps.GoogleMaps, FMX.TMSFNCMapsCommonTypes; {$R *.fmx} procedure TFormHeatMap.DoMapInitialized(Sender: TObject); begin g.SetCenterCoordinate(CreateCoordinate(37.774546, -122.433523)); //San Francisco end; procedure TFormHeatMap.FormCreate(Sender: TObject); begin g := TTMSFNCGoogleMapsEx.Create(Self); g.Parent := Self; g.APIKey := MY API KEY; g.OnMapInitialized := DoMapInitialized; end; { TTMSFNCGoogleMapsEx } procedure TTMSFNCGoogleMapsEx.DoCustomizeMap(var ACustomizeMap: string); var h: string; begin h := 'var heatMapData = [' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.447), weight: 0.5},' + LB + 'new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.445),' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.443), weight: 2},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.441), weight: 3},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.439), weight: 2},' + LB + 'new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.437),' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.782, -122.435), weight: 0.5},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.447), weight: 3},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.445), weight: 2},' + LB + 'new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.443),' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.441), weight: 0.5},' + LB + 'new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.439),' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.437), weight: 2},' + LB + '{location: new ' + MAPSERVICEVAR + '.LatLng(37.785, -122.435), weight: 3}' + LB + '];' + LB + 'var heatmap = new ' + MAPSERVICEVAR + '.visualization.HeatmapLayer({' + LB + ' data: heatMapData' + LB + '});' + LB + 'heatmap.setMap(' + MAPVAR + ');'; ACustomizeMap := h; inherited; end; procedure TTMSFNCGoogleMapsEx.GetHeadLinks(AList: TTMSFNCMapsLinksList; ACheckReady: Boolean); begin AList.Add(TTMSFNCMapsLink.CreateScript('https://maps.googleapis.com/maps/api/js?key=' + MapsProperties.GetAPIKey + '&language=' + MapsProperties.GetLocale + '&libraries=visualization', 'text/javascript', 'utf-8', '', True, True)); end; end.
Explore!
Want to rebuild this sample? Download TMS FNC Maps today. Already have TMS FNC Maps installed? There are no additional requirements, the above code can be applied as-is on the TTMSFNCGoogleMaps class.