Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
487 views
in Technique[技术] by (71.8m points)

internet explorer - Use Googlemap from my Delphi application?

I'm a member in a team that maintains a quite big inhouse Delphi application. Now we have started to look at mapsupport. And we feel that Googlemap seems to be the best value for the money compared to some map components. The current solution (that is really bad) works by starting Internet Explorer from ShellExecute, load some coordinates in the Googlemap URL. Then Google map display the best direction to drive through the coordinates.

It works, but it can be slow if the the amount of coordinates is higher than say 10. Besides that there seems to big memleaks in IE...

Another option is to use TWebBrowser component instead and load a Googlemap html-file to show the same thing. Yes I know Googlemaps license policy and we are prepared to pay Google the price when the solution is used in reality.

Right now I have registed a API-key for my own site just for test. I also found that it works to load a local html-file. From Javascript I can call GUnload to eliminate the memleaks according Googlemap documentation. As the API-key is bound to a domain or a local-file I guess I have to save a javascriptfile with coordinates and then load it in TWebBrowser for every call to the map. I found this clumsy, but I see no other way... ?

Is there other options to use Googlemaps? I don't know other html-components for Delphi than TWebBrowser due to bad performance and memorymanagement. I would like to use a Mozilla component but it seems to be only for C++.

Comments and advice about this ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I've wrapped the Google Maps API some time ago. It's a component that contains a TWebBrowser that loads a local html file that contains some javascript helper functions and sets up a basic Google maps page. The HTML file is embedded into the exe as a resource for easy deployment.

It can use some work, but it has done some nice jobs for me already. It expands on the idea that was posed here: http://www.stevetrefethen.com/blog/UsingGoogleMapsFromVCLSampleApplication.aspx

I've put a demo executable and sourcecode online here: http://www.xs4all.nl/~niff/GoogleMaps.zip

On this screenshot I've switched to the Google Earth view:

image

Here are a few examples of how you can use it:

  • Center the map to some shithole in the Netherlands, with nicely rounded coordinates:

    GoogleMaps1.SetCenter(52,5,True);
    
  • Load a KML or KMZ file:

    GeoXML := TGGeoXML.Create('http://mywebsite.com/mykml.kmz');
    GeoXML.GoogleMaps := GoogleMaps1;
    GoogleMaps1.AddOverlay( GeoXML );
    
  • Switch to the embedded version of Google Earth, for fast and smooth 3d action:

    GoogleMaps1.MapType := MT_SATELLITE_3D;
    
  • Keep a list of overlays, and manage it via Delphi structures:

    GoogleMaps1.Overlays[2].hide; // hide overlay 2
    GoogleMaps1.RemoveOverlayByIndex(3); // delete overlay 3
    
  • It lets you create polygons using fast Delphi arrays and then plot that in GMaps;

MyPolygon := TGPolygon.Create(MyPointArray);
MyPolygon.Color := clBlue; 
MyPolygon.Name := 'Awesome Polygon 1';
GoogleMaps1.AddPolygon( MyPolygon );

It doesn't intend to wrap the full API; it's just to make life easier when dealing with Google maps. The unit DouglasPeuckers is not really needed. It's used to simplify a polygon when you run out of resources.

Good luck, and let me know if you've created something useful with it.

{—————————————————————————————————————————————————————————————————————————}
{ Project : uGoogleMaps.pas                                               }
{ Comment : Google Maps API wrapper                                       }
{                                                                         }
{    Date : 14 mrt 2008                                                   }
{  Author : Wouter van Nifterick                                          }
{—————————————————————————————————————————————————————————————————————————}
{ The aim of this unit is to wrap the Google Maps API in such a way that  }
{ users don't need to know that map operations end up being rendered by   }
{ a browser component and JavaScript.                                     }
{                                                                         }
{ JavaScript classes have a Delphi counterpart, and each Delphi class     }
{ takes care of proper JavaScript rendering and execution.                }
{                                                                         }
{ For many things, like constructing detailed polygons, this provides a   }
{ major performance boost and adds compile-time type checking.            }
{                                                                         }
{ A big limitation so far is that I didn't find a way to directly pass    }
{ complex types from and to the JavaScript engine in IE via COM, so for   }
{ now, everything needs to be (de)serialized to and from strings. :(      }
{—————————————————————————————————————————————————————————————————————————}
{ Last modified                                                           }
{    Date :                                                               }
{  Author :                                                               }
{—————————————————————————————————————————————————————————————————————————}

{$M+}

unit uGoogleMaps;

interface

uses
  Controls,
  Dialogs,
  ActiveX,
  StdCtrls,
  ExtCtrls,
  SysUtils,
  Classes,
  Contnrs,
  Forms,
  SHDocVw,
  MSHTML,
  StrUtils,
  DouglasPeuckers
//  ,  uGoogleEarth_intf
  ;

const
  GoogleMapsFileName = 'GoogleMaps.html';
  WGS84_MULT_FACT    = 100000; // multiply lat/lon values by this value in order to fit them into integers
  DEFAULT_SIMPLIFY_TOLERANCE = 0.5;

{$R GoogleMaps_html.res}


type


  TGoogleMapControl = (MC_NONE=1,MC_SMALL,MC_LARGE);
  TGoogleMapType    = (MT_NORMAL=1,MT_SATELLITE,MT_HYBRID,MT_PHYSICAL,MT_SATELLITE_3D);

  TGoogleMaps       = class; // forward declaration

  GIcon             = class end; // to be implemented

  IJsClassWrapper=interface(IInterface)
    function JsClassName:String;

    function GetJsVarName:String;
    procedure SetJsVarName(const aVarName:String);
    property JsVarName:String read GetJsVarName write SetJsVarName;

    function ToJavaScript:String;
  end;

  IHidable=interface(IInterface)
    procedure hide;                         // Hides the object if the overlay is both currently visible and the overlay's supportsHide() method returns true. Note that this method will trigger the respective visibilitychanged event for each child overlay that fires that event (e.g. GMarker.visibilitychanged, GGroundOverlay.visibilitychanged, etc.). If no overlays are currently visible that return supportsHide() as true, this method has no effect. (Since 2.87)
    function  isHidden           : Boolean; // Returns true if the GGeoXml object is currently hidden, as changed by the GGeoXml.hide() method. Otherwise returns false. (Since 2.87)
    procedure show;                         // Shows the child overlays created by the GGeoXml object, if they are currently hidden. Note that this method will trigger the respective visibilitychanged event for each child overlay that fires that event (e.g. GMarker.visibilitychanged, GGroundOverlay.visibilitychanged). (Since 2.87)
    function  supportsHide       : Boolean; // 
  end;


  // marker class
  GMarkerOptions=record
    icon          : GIcon;    // Chooses the Icon for this class. If not specified, G_DEFAULT_ICON is used. (Since 2.50)
    dragCrossMove : Boolean;  // When dragging markers normally, the marker floats up and away from the cursor. Setting this value to true keeps the marker underneath the cursor, and moves the cross downwards instead. The default value for this option is false. (Since 2.63)
    title         : String;   // This string will appear as tooltip on the marker, i.e. it will work just as the title attribute on HTML elements. (Since 2.50)
    clickable     : Boolean;  // Toggles whether or not the marker is clickable. Markers that are not clickable or draggable are inert, consume less resources and do not respond to any events. The default value for this option is true, i.e. if the option is not specified, the marker will be clickable. (Since 2.50)
    draggable     : Boolean;  // Toggles whether or not the marker will be draggable by users. Markers set up to be dragged require more resources to set up than markers that are clickable. Any marker that is draggable is also clickable, bouncy and auto-pan enabled by default. The default value for this option is false. (Since 2.61)
    bouncy        : Boolean;  // Toggles whether or not the marker should bounce up and down after it finishes dragging. The default value for this option is false. (Since 2.61)
    bounceGravity : Integer;   // When finishing dragging, this number is used to define the acceleration rate of the marker during the bounce down to earth. The default value for this option is 1. (Since 2.61)
    autoPan       : Boolean;  // Auto-pan the map as you drag the marker near the edge. If the marker is draggable the default value for this option is true. (Since 2.87)

    // to implement:
    //    zIndexProcess : Function; // This function is used for changing the z-Index order of the markers when they are overlaid on the map and is also called when their infowindow is opened. The default order is that the more southerly markers are placed higher than more northerly markers. This function is passed in the GMarker object and returns a number indicating the new z-index. (Since 2.98)
  end;

  TGPoint=class

  end;

  TGLatLng=class(TInterfacedObject,IJsClassWrapper)
  private
    FLat,
    FLng:Double;
    FJsVarName: String;
    function GetJsVarName: String;
    procedure SetJsVarName(const Value: String);
  published
    constructor Create(aLat,aLng:Double);
    property Lat:Double read FLat write FLat;
    property Lng:Double read FLng write FLng;
    function ToJavaScript:String;
    function Equals(const AGLatLng:TGLatLng):Boolean;
    function ToString:String;
    function JsClassName:String;virtual;
    property JsVarName:String read GetJsVarName write SetJsVarName;
  end;


  TGBounds=class(TInterfacedObject,IJsClassWrapper)
  private
    FJsVarName: String;
    FMinX, FMinY, FMaxX, FMaxY:Double;
    FMin,FMax,FMid:TGLatLng;
    function GetMax: TGLatLng;
    function GetMid: TGLatLng;
    function GetMin: TGLatLng;
    procedure SetJsVarName(const Value: String);
    function GetJsVarName: String;
  published
    destructor Destroy;override;
    property minX : Double read FMinX write FMinX;
    property minY : Double read FMinY write FMinY;
    property maxX : Double read FMaxX write FMaxX;
    property maxY : Double read FMaxY write FMaxY;
    function ToString:String;
    function Equals(aGBounds:TGBounds):Boolean;
    property Min:TGLatLng read GetMin;
    property Mid:TGLatLng read GetMid;
    property Max:TGLatLng read GetMax;
    function JsClassName:String;virtual;
    property JsVarName:String read GetJsVarName write SetJsVarName;
    function ToJavaScript:String;
  end;

  TGLatLngBounds=class
  private
    procedure setNorthEast(const Value: TGLatLng);
    procedure setSouthWest(const Value: TGLatLng);
  published
    constructor Create(sw,ne:TGLatLng);
    destructor Destroy;override;
    function contains(aLatLng:TGLatLng):Boolean; deprecated; // Returns true iff the geographical coordinates of the point lie within this rectangle. (Deprecated since 2.88)
    function containsLatLng(aLatLng:TGLatLng):Boolean; // Returns true iff the geographical coordinates of the point lie within this rectangle. (Since 2.88)
    function intersects(aGLatLngBounds:TGLatLngBounds):Boolean;
    function containsBounds(aGLatLngBounds:TGLatLngBounds):Boolean;
    procedure extend(aLatLng:TGLatLng); // Enlarges this rectangle such that it contains the given point. In longitude direction, it is enlarged in the smaller of the two possible ways. If both are equal, it is enlarged at the eastern boundary.

    function toSpan()       :   TGLatLng; //    Returns a GLatLng whose coordinates represent the size of this rectangle.
    function isFullLat()    :   Boolean ; //    Returns true if this rectangle extends from the south pole to the north pole.
    function isFullLng()    :   Boolean ; //    Returns true if this rectangle extends fully around the earth in the longitude direction.
    function isEmpty()      :   Boolean ; //    Returns true if this rectangle is empty.
    function getCenter()    :   TGLatLng; //    Returns the point at the center of the rectangle. (Since 2.52)

    function getSouthWest() :   TGLatLng; //    Returns the point at the south-west corner of the rectangle.
    function getN

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...