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-heatmapTMS 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.

TMS Software Delphi  Components

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.