The Road to Delphi

Delphi – Free Pascal – Oxygene

Using the Google Maps API V3 from Delphi – Part I Basic functionality

91 Comments

The Google Maps Javascript API Version 2 has been officially deprecated, so it’s time to update to the new version 3, this post shows how you can use the new Google maps V3 API from Delphi.

in this sample application you can use the traffic layer , Bicycling layer and the street View Control to activate the panorama view.

for additional info about the Google maps api v3 you can check these links.

Check the next full commented sample application written in Delphi 2007, the source code is available on Github

unit fMain;

interface 

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OleCtrls, SHDocVw, StdCtrls, ExtCtrls, XPMan, ComCtrls,MSHTML;

type
  TfrmMain = class(TForm)
    WebBrowser1: TWebBrowser;
    LabelAddress: TLabel;
    PanelHeader: TPanel;
    ButtonGotoLocation: TButton;
    XPManifest1: TXPManifest;
    MemoAddress: TMemo;
    ButtonGotoAddress: TButton;
    LabelLatitude: TLabel;
    LabelLongitude: TLabel;
    Longitude: TEdit;
    Latitude: TEdit;
    CheckBoxTraffic: TCheckBox;
    CheckBoxBicycling: TCheckBox;
    CheckBoxStreeView: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure ButtonGotoAddressClick(Sender: TObject);
    procedure ButtonGotoLocationClick(Sender: TObject);
    procedure CheckBoxTrafficClick(Sender: TObject);
    procedure CheckBoxBicyclingClick(Sender: TObject);
    procedure CheckBoxStreeViewClick(Sender: TObject);
  private
    { Private declarations }
    HTMLWindow2: IHTMLWindow2;
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation

uses
   ActiveX;

{$R *.dfm}

const
HTMLStr: String = //i put The code for the web page page wich load the google maps in a string const, you can use an external html file too or embed the page in a resource and then load in a stream
'<html> '+
'<head> '+
'<meta name="viewport" content="initial-scale=1.0, user-scalable=yes" /> '+
'<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script> '+
'<script type="text/javascript"> '+
''+
''+//Declare the globals vars to be used in the javascript functions
'  var geocoder; '+
'  var map;  '+
'  var trafficLayer;'+
'  var bikeLayer;'+
''+
''+
'  function initialize() { '+
'    geocoder = new google.maps.Geocoder();'+
'    var latlng = new google.maps.LatLng(40.714776,-74.019213); '+ //Set the initial coordinates for the map
'    var myOptions = { '+
'      zoom: 13, '+
'      center: latlng, '+
'      mapTypeId: google.maps.MapTypeId.ROADMAP '+ //Set the default type map
'    }; '+
'    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); '+
'    trafficLayer = new google.maps.TrafficLayer();'+ //Create the traffic Layer instance
'    bikeLayer = new google.maps.BicyclingLayer();'+ //Create the Bicycling Layer instance
'  } '+
''+
''+
'  function codeAddress(address) { '+ //function to translate an address to coordinates and put and marker.
'    if (geocoder) {'+
'      geocoder.geocode( { address: address}, function(results, status) { '+
'        if (status == google.maps.GeocoderStatus.OK) {'+
'          map.setCenter(results[0].geometry.location);'+
'          var marker = new google.maps.Marker({'+
'              map: map,'+
'              position: results[0].geometry.location'+
'          });'+
'        } else {'+
'          alert("Geocode was not successful for the following reason: " + status);'+
'        }'+
'      });'+
'    }'+
'  }'+
''+
''+
'  function GotoLatLng(Lat, Lang) { '+ //Set the map in the coordinates and put a marker
'   var latlng = new google.maps.LatLng(Lat,Lang);'+
'   map.setCenter(latlng);'+
'   var marker = new google.maps.Marker({'+
'      position: latlng, '+
'      map: map,'+
'      title:Lat+","+Lang'+
'  });'+
'  }'+
''+
''+
'  function TrafficOn()   { trafficLayer.setMap(map); }'+ //Activate the Traffic layer
''+
'  function TrafficOff()  { trafficLayer.setMap(null); }'+
''+''+
'  function BicyclingOn() { bikeLayer.setMap(map); }'+//Activate the Bicycling layer
''+
'  function BicyclingOff(){ bikeLayer.setMap(null);}'+
''+
'  function StreetViewOn() { map.set("streetViewControl", true); }'+//Activate the streeview control
''+
'  function StreetViewOff() { map.set("streetViewControl", false); }'+
''+
''+'</script> '+
'</head> '+
'<body onload="initialize()"> '+
'  <div id="map_canvas" style="width:100%; height:100%"></div> '+
'</body> '+
'</html> ';

procedure TfrmMain.FormCreate(Sender: TObject);
var
  aStream     : TMemoryStream;
begin
   WebBrowser1.Navigate('about:blank'); //Set the location to an empty page
    if Assigned(WebBrowser1.Document) then
    begin
      aStream := TMemoryStream.Create; //create a TStem to load the Page from the string
      try
         aStream.WriteBuffer(Pointer(HTMLStr)^, Length(HTMLStr)); //Copy the string to the stream
         //aStream.Write(HTMLStr[1], Length(HTMLStr));
         aStream.Seek(0, soFromBeginning);
         (WebBrowser1.Document as IPersistStreamInit).Load(TStreamAdapter.Create(aStream));//Load the page from the stream
      finally
         aStream.Free;
      end;
      HTMLWindow2 := (WebBrowser1.Document as IHTMLDocument2).parentWindow; //Set the instance of the parentWindow to call the javascripts functions
    end;
end;

procedure TfrmMain.ButtonGotoLocationClick(Sender: TObject);
begin
   HTMLWindow2.execScript(Format('GotoLatLng(%s,%s)',[Latitude.Text,Longitude.Text]), 'JavaScript');//Call the function GotoLatLng to go the coordinates
end;

procedure TfrmMain.ButtonGotoAddressClick(Sender: TObject);
var
   address    : string;
begin
   address := MemoAddress.Lines.Text;
   address := StringReplace(StringReplace(Trim(address), #13, ' ', [rfReplaceAll]), #10, ' ', [rfReplaceAll]);
   HTMLWindow2.execScript(Format('codeAddress(%s)',[QuotedStr(address)]), 'JavaScript');//Call the function codeAddress to go the address
end;

procedure TfrmMain.CheckBoxStreeViewClick(Sender: TObject);
begin
    if CheckBoxStreeView.Checked then
     HTMLWindow2.execScript('StreetViewOn()', 'JavaScript') //Activate the Street View option
    else
     HTMLWindow2.execScript('StreetViewOff()', 'JavaScript');//Deactivate the Street View option

end;

procedure TfrmMain.CheckBoxBicyclingClick(Sender: TObject);
begin
    if CheckBoxBicycling.Checked then
     HTMLWindow2.execScript('BicyclingOn()', 'JavaScript')//Activate the Bicycling View option
    else
     HTMLWindow2.execScript('BicyclingOff()', 'JavaScript');//Deactivate the Bicycling View option
 end;

procedure TfrmMain.CheckBoxTrafficClick(Sender: TObject);
begin
    if CheckBoxTraffic.Checked then
     HTMLWindow2.execScript('TrafficOn()', 'JavaScript')//Activate the Traffic View option
    else
     HTMLWindow2.execScript('TrafficOff()', 'JavaScript');//Deactivate the Traffic View option
 end;

end.

Author: Rodrigo

Just another Delphi guy.

91 thoughts on “Using the Google Maps API V3 from Delphi – Part I Basic functionality

  1. Any thoughts on how to get travel distance between 2 locations?

  2. Being pretty terrible in javascript and I sometimes wonder about my abilities in Delphi, I know that when one views maps.google.com and then enters;

    void(prompt(”,gApplication.getMap().getCenter()))

    One will retrieve the latitude and longitude of the center of the shown map.

    Played with this in Delphi and your sample code, and cannot get it towork. Ideally, it would be GREAT to show the lat and long in the tEdits in the form. Can any of this be done?

    Thanks for the tutorial! Nice to start learning this stuff!

    John J

  3. Thank you for this code,
    I use delphi 2009 and I get a java script error when I run the program after I compile it.
    Could you please help me ?
    Do you already test you code with delphi 2009 ?
    Thank you ,

  4. Thanks a lot!

  5. Run this code in Delphi2009

    try changing this line
    HTMLStr: String =
    to
    const HTMLStr :UTF8String =

  6. Pingback: Anonymous

  7. Estimado, como siempre muy buenos artículos.

    Le cuento, por cada búsqueda sale un marcador. ¿Como puedo eliminar o los marcadores anteriores en cada búsqueda o hacer que solo se muestre el último?.

    De antemano muchas gracias

    • MAXIUM, acabo de actualizar el proyecto . si lo descargas ahora podras ver que tienes la opcion “clear markers”, que limpia los marcadores de la pantalla. basicamente lo que se hace (en javascript) es crear una variable global (de tipo array) que contiene los marcadores y cuando se presiona el boton antes mencionado se limpia la variable, lo que hace desaparacer los marcadores. espero que te sirva.

      Saludos.

  8. Hi,
    Good job and keep it up.
    Trying to run the code and I got error of TwebBrowser is not found. Where can I find TwebBrowser component?

    • Ade, which version of delphi are you using? the TWebBrowser component is a standard component included in the internet palette and is part of the SHDocVw unit.

      • Rodrigo, Thanks for your response. I am using Delphi XE Stater. Now It seem like there is limitation of those components on Starter version.

  9. Rodrigo, Thanks for your response. I am using Delphi XE Stater. Now It seem like there is limitation of those components on Starter version.

    Rodrigo :
    Ade, which version of delphi are you using? the TWebBrowser component is a standard component included in the internet palette and is part of the SHDocVw unit.

    Rodrigo, Thanks for your response. I am using Delphi XE Stater. Now It seem like there is limitation of those components on Starter version.

  10. Delphi 7 personnal.
    Have installed TWebBrower component but no way to find the needed dcu.
    Just have emailed u
    Thanks

  11. Hi Rodrigo,

    Thank you for the excellent tutorial. I am using Delphi 2010, there was an complication error at HTMLWindow2.execScript(). but it is fixed by edit code HTMLStr: String = to const HTMLStr :UTF8String

  12. Nice tutorial … thanks.

    I’ve noticed that the street view no longer works. (I think google has pushed a new version)
    Any idea how to fix it?
    I’ve been trying to add the doctype tag to the html, but still no joy.

  13. Great sample Thx!!, Works fine on Delphi 7 :D

  14. Any news about how to get distance between two adress and how to display marquers on the google map in Delphi ????

  15. Hi, seems to be a great application. Any idea how to convert a mouse click on the map into corresponding coordinates ? i.e. longitude and latitude of the point clicked ?

  16. Hi all,
    For “Delphi7 users like me”, you simply make a little modification in the projects source “GoogleMapsTest.pas” :

    program GoogleMapsTest;

    uses
    Forms,
    fMain in ‘fMain.pas’ {frmMain};

    {$R *.res}

    begin
    Application.Initialize;

    //Begin
    //Remove -or comment- the following line
    Application.MainFormOnTaskbar := True;
    //End

    Application.CreateForm(TfrmMain, frmMain);
    Application.Run;
    end.

  17. It’s Great!!!

    I like it!

    Thanks a lot!

  18. Nice tutorial!

  19. hi
    Please send me source code (*.dpr — *..dproj) in email address
    Please Hint me …

  20. hi !

    this is a great code. i am using delphi 7 Ent. Everything is running fine except one minor – big problem. i try to automatically go to an address (lat,lon) that is saved in a database, when the user opens a form with the map. When i use the code on ButtonGotoLocationClick on a Button, it is ok. when i try to do the same e.g. on a tab change, i get an error 80020101. anyone knows why?

  21. Hi Rodrigo,

    Hope you are planning to start using XE2.

  22. Pingback: /*Prog*/ Delphi-Neftalí /*finProg*/ » Una quincena más… (11/04/2012)

  23. Thanks for this series of tutorials; they really help to explain the Delphi/Google workings. I have it running in both D7 and D5 (only three modifications). A question about clearing all the markers: After clearing, then adding a new marker, the sequence number starts at the highest previous number. Is there any way to initialize the marker to “number 1” after clearing? Thanks for any help.

  24. Rodrigo ante todo muy bueno lo tuyo, una consulta cuando agrego los marcadores le el titulo del mismo solo se ve con un hint , como se puede hacer para que aparesca como una etiqueta como esta en el earth.

    Saludos.

  25. Hello Rodrigo
    Any idea about using this wonderful tool behind a firewall.
    What would be the entries (sites, URLs) to open on the firewall ?

  26. This code compiled cleanly under EX2.

  27. Nice info and thanks for sharing, how about if i click the map it will give a location in a textfield?

  28. works for delphi xe5, thank you very much.

  29. The link for the source code no longer works

  30. Hi Rodrigo,

    great stuff, thx for great help.

    I have a question: Do you have the same example for Delphi-firemonkey? I tried to use some code-snippets in firemonkey, but obviously I failed in converting the code to fmx-code.

    Thx a lot and

    best wishes from Germany,

    Lars

  31. I’ll right away seize your rss feed as I can not to find
    your email subscription hyperlink or e-newsletter
    service. Do you have any? Please allow me recognize in order
    that I could subscribe. Thanks.

  32. Hello my friend, thank you very much! I was wondering if you can print the map you see??? can you do that? can you take a screen shot from delphi like a e.g png or jpeg?? I would appreciate, thank you very much

    • You can invoke the print command directly from the TWebBrowser component like so

      var
         ParamIn, ParamInOut: OleVariant;
      begin
        WebBrowser1.ControlInterface.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, ParamIn, ParamInOut);
      end:
      
  33. Heya!

    Broken since today (GMT+1)….

    Looks like there was something changed on the google side regarding the map-object?
    Chrome and IE 10+ are loading/initializing the external google scripts still fine, but the TWebbrowser component has problems, throwing an “property display not found bablabla” error.

    Could it be anychronous loading the TWebbrowser cannot handle?

    Greeting from Germany
    Richard

  34. I’m using your code in one application since 2 years but now we are getting Javascript errors and the map is not loaded.
    Can you verify?

  35. Qué tal Rodrigo, excelente información para compartir. Aprovechando de tu conocimiento, es posible que una vez que le de una dirección pueda obtener los datos de Latitud y Longitud en Delphi para poder guardar esa información y en el futuro utilizarla en vez de la dirección ?, de antemano gracias.

  36. Muchas gracias Rodrigo, con este ejemplo pude resolver mi duda. Saludos.

  37. Primera vez que veo tu página, me bajé el código, lo cargué en XE/Win7, compiló y ejecutó con cero error a la primera. Impresionante. Gracias.

  38. Uaaauuuu… Muito bom! Parabéns!

  39. Can get example (( – 404

  40. Hi Rodrigo,
    Some weeks ago I sent you a message for telling you that it seems that there is a problem with the StreetView option in your GoogleMaps in Delphi program: the close button doesn’t appear anymore. But I think you delete my message because I have not seen it here.
    Now I have a more serious problem: the window where GoogleMaps must appear remains empty… I also tried your “GoogleMapsTest.exe” on various computer and it is the same everywhere…
    Could you do something to help please? I use your powerful code for a long time but now have these problems.
    Thank you very much!

  41. Pingback: Important Note about using the Google Maps API from Desktop Apps | The Road to Delphi

  42. Rodrigo,

    Es posible guardar la imagen del mapa en un archivo jpg , que uno le pueda asignar a las variables el folder donde se va a guardar y el nombre del archivo, de tal manera que no aparezca la caja de diaalogo. De antemano gracias por la atención que des al presente. Saludos

    Fernando Vasquez

    • Hola, un par de opciones, puedes guardar una imagen del TWebBrowser usando la funcion BitBlt y el Canvas del control. o bien puedes usar la API Google Static Maps.

  43. Rodrigo,

    Gracias me funciono utilizando la función BitBlt

    Saludos
    Fernando Vasquez

  44. Rodrigo,
    your tutorial is so clearly and easy to understand.
    But, i have a trouble when I will run these. My problem is the “soFromBeginning”. My delphi said that variable hasn’t declare yet. So, where i can find that variable. I use delphi 7. win8.1 IE 11.

    thank you very much..

  45. I was just wondering why the htmlstr has to be pushed by a stream. Isn’t it possible to just open ‘about:’+htmlstr?

    • No you can’t pass the HTML content directly to the navigate method. Instead you must use a Stream because the WebBrowser control uses a stream-based interface (IPersistStreamInit) to load and save the documents.

  46. AT LAST, I figured out the problem.

    Onion.js fires the error, because it calls JSON.parse.

    JSON Parse isn’t supported by the web browser control.
    You can test this by adding this to your JavaScript (already quoted for Delphi):

    ‘var code = ””\u2028\u2029″”; JSON.parse(code); ‘ +

    Very browser should execute
    var code = ‘”\u2028\u2029″‘; JSON.parse(code);
    When executed in Delphi it fires an error instantly.

    You can avoid the whole thing with a JSON3 polyfill:

    https://cdn.jsdelivr.net/json3/3.3.2/json3.js‘ +

    Then JSON will be defined and working as expected, causing the Onion.js error to never appear again!

  47. these codes result message could not complete the operation due to error 80020101,
    for Delphi 7 or delphi xe8

  48. Hi, I get an error… ” You are using a browser that is not supported by the Google Maps JavaScript API. Consider changing your browser.” within the TWebBrowser, how do I change my default web browser within delphi?

  49. Nvm find it by changing my registry settings.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s