Hi Bruno (Happy New Year).
We were in a situation were we kind of needed this sooner than later, so I took the liberty to make some changes to some of TMS source files and implemented that feature for you (please feel free to tear it apart and enhance it as you see fit, but at the moment, this works for us). So for whoever else would need this, here's how it goes:
I added a JavaScript function called printallpolygons. I also added a hidden input field where the result of the function is to be saved.
So, in UWebGMapsConst.pas, I added the following:
(my Javascript changes are between <RD>MyChanges</RD>)
...
<script type="text/javascript">' + #13 +
' var map;' + #13 +
' var streetviewService;' + #13 +
' var streetviewPanorama;' + #13 +
' var allclusters = [];' + #13 +
' var clusterstyles = [];' + #13 +
' var allmarkers = [];' + #13 +
' var alllabels = [];' + #13 +
' var allpolylines = [];' + #13 +
' var allpolygons = [];' + #13 +
' var allkmllayers = [];' + #13 +
' var allinfowindows = [];' + #13 +
' var trafficLayer;' + #13 +
' var bicyclingLayer;' + #13 +
' var panoramioLayer;' + #13 +
' var cloudLayer;' + #13 +
' var weatherLayer;' + #13 +
' var directionsDisplay;' + #13 +
' var directionsService = new google.maps.DirectionsService();' + #13 +
//<RD>
' function printallpolygons(){' + #13 +
//'alert(" printallpolygons: " + allpolygons.length);'+
' var str = "";' + #13 +
' for (var i = 0; i < allpolygons.length; i++){' + #13 +
// 'alert(" forloop: " + i);'+
' var polygonBounds = allpolygons.getPath();' + #13 +
' var xy;' + #13 +
{ Iterate over the polygonBounds vertices and build a string
that will contain the lat and long of all the polygons. Each
value (rows) will be delimited by a semi-colon ";".
Ex:
Polygone[0] Coordinate[0] LAT[44.1234567] LNG[103.123456887];
Polygone[0] Coordinate[1] LAT[44.1345566] LNG[103.231234567];
Polygone[0] Coordinate[2] LAT[44.4567889] LNG[103.451234567];
Polygone[0] Coordinate[3] LAT[44.5757567] LNG[103.671244567];
Polygone[1] Coordinate[0] LAT[44.1234567] LNG[103.89345367];
Polygone[1] Coordinate[1] LAT[44.7574565] LNG[103.103463567];
Polygone[1] Coordinate[2] LAT[44.0984233] LNG[103.118842567];
}
' for (var j = 0; j < polygonBounds.length; j++) {' + #13 +
' xy = polygonBounds.getAt(j);' + #13 +
' str += "Polygon[" + i + "] Coordinate[" + j + "] LAT[" + xy.lat() + "] LNG[" + xy.lng() + "];";' + #13 +
' }' + #13 +
' }' + #13 +
// Save the result string into our hidden input (i.e. "result")
' document.getElementById("result").value = str;' + #13 +
'}' + #13 +
//</RD>
' function setzoommap(newzoom) {' + #13 +
...
Then at the very bottom of the unit, the hidden input field:
...
<body>' + #13 +
' <div id="map_canvas"></div>' + #13 +
//<RD>
// Hidden input that will be used to get the result from Javascript
// See the printAllPolygons Javascript function defined above.)
' <input type="hidden" name="result" id="result" value="" />' + #13 +
//</RD>
'</body>' + #13 +
'</html>';
...
In WebGMaps.pas:
...
interface
public
//<RD>
function InvokeScript(const AScript: String): String;
procedure GetAllPolygonsFromJavascript( var AllPolygons: TStringlist );
//</RD>
...
implementation
//<RD>
function TWebGMaps.InvokeScript(const AScript: String): String;
{Use InvokeScript when you need the result from a JavaScript function.
It first calls/uses ExecJScript to execute the function, then saves the result
into a hidden input (i.e. "result") that has been declared in
UWebGMapsConst.pas (see const HTML_FILE_1). }
function GetElementIdValue(AWebBrowser: TWebBrowser;
TagName, TagId, TagAttrib: string):string;
var
Document: IHTMLDocument2;
Body: IHTMLElement2;
Tags: IHTMLElementCollection;
Tag: IHTMLElement;
I: Integer;
begin
Result:='';
if not Supports(AWebBrowser.Document, IHTMLDocument2, Document) then
raise Exception.Create('Invalid HTML document');
if not Supports(document.body, IHTMLElement2, Body) then
raise Exception.Create('Can''t find <body> element');
Tags := body.getElementsByTagName(UpperCase(TagName));
for I := 0 to Pred(Tags.length) do begin
Tag:=Tags.item(I, EmptyParam) as IHTMLElement;
if Tag.id=TagId then Result := Tag.getAttribute(TagAttrib, 0);
end;
end;
begin
Result := '';
// Run the script
if ExecJScript( AScript { 'Ex: printallpolygons();' } ) then
begin
// Get the result
Result := GetElementIdValue(FWebBrowser, 'input', 'result', 'value')
end;
end;
procedure TWebGMaps.GetAllPolygonsFromJavascript(var AllPolygons: TStringlist);
begin
AllPolygons.Clear;
AllPolygons.Delimiter := ';';
AllPolygons.StrictDelimiter := True;
AllPolygons.DelimitedText := Trim( InvokeScript( 'printallpolygons();' ) );
end;
//</RD>
I also created a couple utility methods:
function GetPolygonItemById( AWebGMaps: TWebGMaps; AId: Integer): TPolygonItem;
{Iterates through the Polygons of given WebGMaps (AWebGMaps) and returns the
PolygonItem with the specified AId.
Returns nil if the itenm cannot be found. }
var
Index: Integer;
begin
Result := nil;
if Assigned( AWebGMaps ) then
begin
Index := -1;
while ( Result = nil ) and ( Index < AWebGMaps.Polygons.Count -1 ) do
begin
Inc( Index );
// WebGMapsPolygonClickEvent has an "AId" parameter which can lead to some
// confusion. Although they named it "AId", I think they really meant "AIndex"
// (they are really referring to the Index of the Collection Item in it's
// natural order, not the "Id" of the Collection.
if Index = AId then
Result := AWebGMaps.Polygons[ Index ];
end;
end;
end;
procedure LoadPolygonFromAllPolygons( var APolygonItem: TPolygonItem;
const AllPolygons: TStringList );
var
Index: Integer;
TempStr: String;
PolyGonIndex: String;
Latitude, Longitude: Double;
begin
APolygonItem.Polygon.Path.Clear;
for Index := 0 to AllPolygons.Count -1 do
begin
//TempStr will be like: "Polygon[0] Coordinate[0] LAT[44.123456] LNG[103.123456];"
TempStr := AllPolygons[ Index ];
// Get the PolygonIndex
Delete( TempStr, 1, Pos( 'Polygon[', TempStr ) +7 );
PolyGonIndex := Copy( TempStr, 1, Pos( ']', TempStr ) -1 );
Delete( TempStr, 1, Pos( ']', TempStr ) );
// If this is the Polygon we are interested in...
if ( StrToIntDef( PolyGonIndex, -1 ) = APolygonItem.Index ) then
begin
// Get the Latitude
Delete( TempStr, 1, Pos( 'LAT[', TempStr ) +3 );
Latitude := StrToFloatDef( Copy( TempStr, 1, Pos( ']', TempStr ) -1 ), -1 );
Delete( TempStr, 1, Pos( ']', TempStr ) );
// Get the Longitude
Delete( TempStr, 1, Pos( 'LNG[', TempStr ) +3 );
Longitude := StrToFloatDef( Copy( TempStr, 1, Pos( ']', TempStr ) -1 ), -1 );
Delete( TempStr, 1, Pos( ']', TempStr ) );
if ( Latitude <> -1 ) and ( Longitude <> -1 ) then
APolygonItem.Polygon.Path.Add( Latitude, Longitude );
// Do not be tempted to break out of the loop as we have to identify all
// the coordinates that belong to this one polygon. Keep looping.
end;
end;
end;
Now let's use it, all you have to do is to add some code in the PolygonMouseExit event( or where ever you need it: for example I have a right click popup where the user can edit the specific lats and longs):
procedure TMapViewer.WebGMapsPolygonMouseExitEvent(Sender: TObject;
IdPolygon: Integer);
var
AllPolygons: TStringList;
PolygonItem: TPolygonItem;
begin
PolygonItem := GetPolygonItemById( FWebGMaps, IdPolygon );
if Assigned( PolygonItem ) then
begin
AllPolygons := TStringList.Create;
try
WebGMaps.GetAllPolygonsFromJavascript( AllPolygons );
// Refresh our Polygon from the StringList we got back from
// the call to GetAllPolygonsFromJavascript.
LoadPolygonFromAllPolygons( PolygonItem, AllPolygons );
finally
FreeAndNil( AllPolygons );
end;
end;
end;
I hope that helps.
Richard