In this post I will show, how you can interact with a google map embedded in a TWebbrowser component in order to get the location ( latitude and longitude) of a point when you click in the map.
JavaScript
To get the location of the mouse when you make a click in the map you must add a Google maps Event Listener, passing a function to process the event, the values of the current location are retrieved in the event.latLng variable , the next step is store the values returned in a hidden field element to after get these values from Delphi.
Check this sample JavaScript snippet which create an event listener and store the values in the LatValue and LngValue fields.
google.maps.event.addListener(map, "click", function(event) { document.getElementById("LatValue").value = event.latLng.lat(); document.getElementById("LngValue").value = event.latLng.lng(); PutMarker(document.getElementById("LatValue").value, document.getElementById("LngValue").value,"") } );
This is the PutMarker function which creates a marker in the current location
function PutMarker(Lat, Lang, Msg) { var latlng = new google.maps.LatLng(Lat,Lang); var marker = new google.maps.Marker({ position: latlng, map: map, title: Msg+" ("+Lat+","+Lang+")" }); //put the created marker in an array markersArray.push(marker); //compute the index to associate an image to the marker index= (markersArray.length % 10); if (index==0) { index=10 } icon = "http://www.google.com/mapfiles/kml/paddle/"+index+"-lv.png"; marker.setIcon(icon); }
And this is the code to create the 2 input hidden fields in the html page to store the values returned by the Event listener
<body onload="initialize()"> <div id="map_canvas" style="width:100%; height:100%"></div> <div id="latlong"> <input id="<span class=" type="hidden" />LatValue" > <input id="<span class=" type="hidden" />LngValue" > </div> </body>
Delphi
Now from the Delphi side, you must detect the click event in the TWebBrowser component and then read the values stored in the hidden fields. Exists several ways to detect the click in the TWebBrowser, in this case I will use the OnCommandStateChange event.
Check this code which detect the click event and then read the values stored in the hidden fields.
procedure TForm1.WebBrowser1CommandStateChange(ASender: TObject; Command: Integer; Enable: WordBool); var ADocument : IHTMLDocument2; ABody : IHTMLElement2; Lat : string; Lng : string; //get the value from a field function GetIdValue(const Id : string):string; var Tag : IHTMLElement; TagsList : IHTMLElementCollection; Index : Integer; begin Result:=''; TagsList := ABody.getElementsByTagName('input'); for Index := 0 to TagsList.length-1 do begin Tag:=TagsList.item(Index, EmptyParam) As IHTMLElement; if CompareText(Tag.id,Id)=0 then Result := Tag.getAttribute('value', 0); end; end; begin //is a valid command? if TOleEnum(Command) <> CSC_UPDATECOMMANDS then //-1 Exit; //The page is loaded? ADocument := WebBrowser1.Document as IHTMLDocument2; if not Assigned(ADocument) then Exit; //the page has body? if not Supports(ADocument.body, IHTMLElement2, ABody) then exit; // get the values of the Latitude and Longitude Lat :=GetIdValue('LatValue'); Lng :=GetIdValue('LngValue'); //Now process the data if (Lat<>'') and (Lng<>'') and ((Lat<>Latitude.Text) or (Lng<>Longitude.Text)) then begin Latitude.Text :=Lat; Longitude.Text:=Lng; end; end;
Finally this is the full source code for the demo application
unit uMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, OleCtrls, SHDocVw, StdCtrls, ExtCtrls, XPMan, ComCtrls,MSHTML; type TFrmMain = class(TForm) WebBrowser1: TWebBrowser; PanelHeader: TPanel; ButtonGotoLocation: TButton; XPManifest1: TXPManifest; LabelLatitude: TLabel; LabelLongitude: TLabel; Longitude: TEdit; Latitude: TEdit; ButtonClearMarkers: TButton; ListView1: TListView; Panel1: TPanel; procedure FormCreate(Sender: TObject); procedure ButtonClearMarkersClick(Sender: TObject); procedure WebBrowser1CommandStateChange(ASender: TObject; Command: Integer; Enable: WordBool); procedure ButtonGotoLocationClick(Sender: TObject); private HTMLWindow2: IHTMLWindow2; procedure AddLatLngToList(const Lat,Lng:string); public end; var FrmMain: TFrmMain; implementation {$R *.dfm} uses ActiveX; const HTMLStr: AnsiString = '<html> '+ '<head> '+ '<meta name="viewport" content="initial-scale=1.0, user-scalable=yes" /> '+ '<script type="text/javascript">// <![CDATA[ src</span>="http://maps.google.com/maps/api/js?sensor=false&language=en"> // ]]></script> '+ //'<script type="text/javascript">// <![CDATA[ src</span>="http://maps.google.com/maps/api/js?sensor=false"> // ]]></script> '+ '<script type="text/javascript"> '+ ''+ ''+ ' var geocoder; '+ ' var map; '+ ' var markersArray = [];'+ ''+ ''+ ' function initialize() { '+ ' geocoder = new google.maps.Geocoder();'+ ' var latlng = new google.maps.LatLng(40.714776,-74.019213); '+ ' var myOptions = { '+ ' zoom: 13, '+ ' center: latlng, '+ ' mapTypeId: google.maps.MapTypeId.ROADMAP '+ ' }; '+ ' map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); '+ ' map.set("streetViewControl", false);'+ ' google.maps.event.addListener(map, "click", '+ ' function(event) '+ ' {'+ ' document.getElementById("LatValue").value = event.latLng.lat(); '+ ' document.getElementById("LngValue").value = event.latLng.lng(); '+ ' PutMarker(document.getElementById("LatValue").value, document.getElementById("LngValue").value,"") '+ ' } '+ ' ); '+ ''+ ' } '+ ''+ ''+ ' function GotoLatLng(Lat, Lang) { '+ ' var latlng = new google.maps.LatLng(Lat,Lang);'+ ' map.setCenter(latlng);'+ ' }'+ ''+ ''+ 'function ClearMarkers() { '+ ' if (markersArray) { '+ ' for (i in markersArray) { '+ ' markersArray[i].setMap(null); '+ ' } '+ ' } '+ '} '+ ''+ ' function PutMarker(Lat, Lang, Msg) { '+ ' var latlng = new google.maps.LatLng(Lat,Lang);'+ ' var marker = new google.maps.Marker({'+ ' position: latlng, '+ ' map: map,'+ ' title: Msg+" ("+Lat+","+Lang+")"'+ ' });'+ ' markersArray.push(marker); '+ ' index= (markersArray.length % 10);'+ ' if (index==0) { index=10 } '+ ' icon = "http://www.google.com/mapfiles/kml/paddle/"+index+"-lv.png"; '+ ' marker.setIcon(icon); '+ ' }'+ ''+ ''+ ''+'</script> '+ '</head> '+ ''+ '<body onload="initialize()"> '+ ' <div id="map_canvas" style="width:100%; height:100%"></div> '+ ' <div id="latlong"> '+ ' <input type="hidden" id="LatValue" >'+ ' <input type="hidden" id="LngValue" >'+ ' </div> '+ ''+ '</body> '+ '</html> '; procedure TFrmMain.FormCreate(Sender: TObject); var aStream : TMemoryStream; begin WebBrowser1.Navigate('about:blank'); if Assigned(WebBrowser1.Document) then begin aStream := TMemoryStream.Create; try aStream.WriteBuffer(Pointer(HTMLStr)^, Length(HTMLStr)); //aStream.Write(HTMLStr[1], Length(HTMLStr)); aStream.Seek(0, soFromBeginning); (WebBrowser1.Document as IPersistStreamInit).Load(TStreamAdapter.Create(aStream)); finally aStream.Free; end; HTMLWindow2 := (WebBrowser1.Document as IHTMLDocument2).parentWindow; end; end; procedure TFrmMain.WebBrowser1CommandStateChange(ASender: TObject; Command: Integer; Enable: WordBool); var ADocument : IHTMLDocument2; ABody : IHTMLElement2; Lat : string; Lng : string; function GetIdValue(const Id : string):string; var Tag : IHTMLElement; TagsList : IHTMLElementCollection; Index : Integer; begin Result:=''; TagsList := ABody.getElementsByTagName('input'); for Index := 0 to TagsList.length-1 do begin Tag:=TagsList.item(Index, EmptyParam) As IHTMLElement; if CompareText(Tag.id,Id)=0 then Result := Tag.getAttribute('value', 0); end; end; begin if TOleEnum(Command) <> CSC_UPDATECOMMANDS then Exit; ADocument := WebBrowser1.Document as IHTMLDocument2; if not Assigned(ADocument) then Exit; if not Supports(ADocument.body, IHTMLElement2, ABody) then exit; Lat :=GetIdValue('LatValue'); Lng :=GetIdValue('LngValue'); if (Lat<>'') and (Lng<>'') and ((Lat<>Latitude.Text) or (Lng<>Longitude.Text)) then begin Latitude.Text :=Lat; Longitude.Text:=Lng; AddLatLngToList(Lat, Lng); end; end; procedure TFrmMain.AddLatLngToList(const Lat, Lng: string); var Item : TListItem; begin if (Lat<>'') and (Lng<>'') then begin Item:=ListView1.Items.Add; Item.Caption:=Lng; Item.SubItems.Add(Lat); Item.MakeVisible(False); end; end; procedure TFrmMain.ButtonClearMarkersClick(Sender: TObject); begin HTMLWindow2.execScript('ClearMarkers()', 'JavaScript'); ListView1.Items.Clear; end; procedure TFrmMain.ButtonGotoLocationClick(Sender: TObject); begin if Assigned(ListView1.Selected) then HTMLWindow2.execScript(Format('GotoLatLng(%s,%s)',[ListView1.Selected.SubItems[0],ListView1.Selected.Caption]), 'JavaScript'); end; end.