How it works
The component works in a simple way: it creates an HTML page with some JavaScript functions inside it, loads it in the browser, and then calls those functions with ExecuteScript whenever one of its methods is called.
If you want to look at the page, put a breakpoint in TEdgeGoogleMapViewer.ShowMap and read the HTML that is handed to the browser.
From a method to a JavaScript function
Look at GotoAddress:
procedure TEdgeGoogleMapViewer.GotoAddress(const Address: string);
var
ScriptCommand: String;
begin
FAddress := Address;
if FAddress = '' then
HideMap
else if not MapVisible then
ShowMap(FAddress)
else
begin
ScriptCommand := Format('codeAddress(%s)', [JSQuotedStr(ClearAddressText(Address))]);
ExecuteScript(ScriptCommand);
end;
end;codeAddress is a function of the page that asks Google's geocoder for the position and puts a marker there. The text of the address reaches the script through JSQuotedStr, which turns it into a JavaScript string literal: quotes, backslashes, control characters and </script> are escaped.
Adding your own JavaScript
Anything the Google Maps JavaScript API can do, you can add. The page is assembled in GetHTMLScript from the functions of the component:
function TEdgeGoogleMapViewer.GetHTMLScript: string;
var
LJSScript: string;
begin
LJSScript := GetJSVariables + sLineBreak +
GetJSInitialize + sLineBreak +
(...)
GetJSRouteAddress + sLineBreak +
GetJSCalcRoute;
if Assigned(FOnGetJavascript) then
FOnGetJavascript(Self, LJSScript);
Result :=
'<script type="text/javascript"> ' + sLineBreak +
LJSScript + sLineBreak +
'</script> ' + sLineBreak;
end;There are two ways to extend it:
- The
OnGetJavascriptevent receives the whole script in avarparameter: add your functions to it, then call them withExecuteScript. - A descendant of the component: the
GetHTML...functions and most of theGetJS...ones arevirtual. Override the one you need, or add a function toGetHTMLScript.
procedure TMainForm.EdgeGoogleMapViewerGetJavascript(ASender: TObject;
var AJavascript: string);
begin
AJavascript := AJavascript + sLineBreak +
'function ZoomToWorld() { map.setZoom(2); }';
end;
// ... later
EdgeGoogleMapViewer.ExecuteScript('ZoomToWorld()');OnGetHTMLBody does the same for the body of the page, for example to add a panel next to the map.
A script of yours can send a message to Delphi with window.chrome.webview.postMessage(...): the messages the component does not know about arrive in OnWebUnhandledMessageReceived.
See the Google Maps JavaScript API reference for what is available, and please make a pull request to the project if you add something that can be useful to everybody.
The page and the Google Maps API
The Google Maps API is loaded by the page from Google's servers, asynchronously, with the geometry and marker libraries, using the key you registered. So the map needs the internet, and the key is visible to anybody who can inspect the page: restrict it in the Google console.
The component waits for the page to tell that the map is ready (with a safety limit of 15 seconds) before it draws on it, which is why the Put... methods can be called right after GotoAddress, even when the map was hidden.