Jump to content

Google Maps API


Recommended Posts

It took quite a bit of trial and error due to some case sensitivity errors but I finally have a working google map which utilises Google's javascript API. I know this has been touched on in other topics on the forum but none of them had a full blown working example; so I include this here for those who come after!  Just create a new Visual Components project and replace everything in the form1 unit with the below code. Note that you will also need to obtain an API Key from Google (https://developers.google.com/maps/documentation/javascript/) and replace the dummy one in the code below. Note that I have only included a few partial classes and objects as far as the maps API is concerned but hopefully this is enough to get newcomers started. As an aside, the reference section on the above linked URL is very helpful in getting things up and running.

unit Form1;

interface

uses 
  System.Types,
  System.Types.Convert,
  System.Objects,
  System.Time,
  SmartCL.System,
  SmartCL.Time,
  SmartCL.Graphics,
  SmartCL.Components,
  SmartCL.FileUtils,
  SmartCL.Forms,
  SmartCL.Fonts,
  SmartCL.Theme,
  SmartCL.Borders,
  SmartCL.Application,
  SmartCL.Controls.Elements,
  W3C.HTML5,
  W3C.DOM,
  SmartCL.Require,
  System.JSON;

type
  JMap = partial Class external;

  JLatLngLiteral = record
    Property lat : Double;
    Property lng : Double;
  end;

  JMapOptions = record
    property Zoom : Integer;
    property Center : JLatLngLiteral;
  end;

  JMarkerOptions = record
    property position : JLatLngLiteral;
    property map : JMap;
    property title : String;
  end;

  JMarker = partial class external 'google.maps.Marker'
  Public
    Constructor Create(options:JMarkerOptions); external 'Marker';
  end;

 	JMap = partial class external 'google.maps.Map'
	public
    Constructor Create(mapDiv:JElement; options : JMapOptions); external 'Map';
	end;

  TForm1 = class(TW3Form)
  private
    {$I 'Form1:intf'}
    FMap : JMap;
    FMapDIV : TW3DIVHtmlElement;
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure Resize; override;
    procedure InitMap;
  end;

implementation

{ TForm1 }

procedure TForm1.InitializeForm;
begin
  inherited;
end;

procedure TForm1.InitializeObject;
var
   APIKey : String;
begin
  inherited;
  {$I 'Form1:impl'}
  FMapDIV := TW3DIVHtmlElement.Create(Self);
  FMapDiv.SetBounds(5,5,450,400);

  //Enter a valid API Key here. It can be obtained from
  //https://developers.google.com/maps/documentation/javascript/

  APIKey := 'YOUR API KEY HERE';

  Require(['https://maps.googleapis.com/maps/api/js?key=' + APIKey],procedure()
  begin
   InitMap;
  end);
end;
 
procedure TForm1.Resize;
begin
  inherited;
end;
 
procedure TForm1.InitMap;
var
  LUluru : JLatLngLiteral;
  LMapOptions : JMapOptions;
  LMarkerOptions : JMarkerOptions;
  LMarker : JMarker;
  LMapElement : JELement;
begin
  LUluru.lat := -25.3444;
  LUluru.lng := 131.0369;
  LMapOptions.Zoom := 13;
  LMapOptions.Center := LUluru;
  LMapElement := Document.getElementById(FMapDIV.Handle.id);
  FMap := JMap.Create(LMapElement,LMapOptions);
  LMarkerOptions.position := LUluru;
  LMarkerOptions.map := FMap;
  LMarkerOptions.title := 'Woo Hoo!';
  LMarker := JMarker.Create(LMarkerOptions);
end;

initialization
  Forms.RegisterForm({$I %FILE%}, TForm1);
end.

 

Link to post
Share on other sites

Thank You! I needed this for an app I was currently working on :)

However, for me, I needed to place the API code in its own unit...

unit GoogleMaps;

interface

uses 
  System.Types,
  System.Types.Convert,
  SmartCL.System,
  SmartCL.Components,
  SmartCL.Require,
  System.JSON,
  W3C.HTML5,
  W3C.DOM;

type
  JMap = partial Class external;

  JLatLngLiteral = record
    Property lat : Double;
    Property lng : Double;
  end;

  JMapOptions = record
    property Zoom : Integer;
    property Center : JLatLngLiteral;
  end;

  JMarkerOptions = record
    property position : JLatLngLiteral;
    property map : JMap;
    property title : String;
  end;

  JMarker = partial class external 'google.maps.Marker'
  Public
    Constructor Create(options:JMarkerOptions); external 'Marker';
  end;

     JMap = partial class external 'google.maps.Map'
    public
    Constructor Create(mapDiv:JElement; options : JMapOptions); external 'Map';
    end;

  procedure InitMap(AAPIKey, ATitle: String; ALat, ALong: Double; AControl: TW3CustomControl);

var
 Map : JMap;

implementation

procedure InitMap(AAPIKey, ATitle: String; ALat, ALong: Double; AControl: TW3CustomControl);
var
  LUluru : JLatLngLiteral;
  LMapOptions : JMapOptions;
  LMarkerOptions : JMarkerOptions;
  LMarker : JMarker;
  LMapElement : JElement;
begin
 Require(['https://maps.googleapis.com/maps/api/js?key=' + AAPIKey],procedure()
  begin
  LUluru.lat := ALat;
  LUluru.lng := ALong;
  LMapOptions.Zoom := 10;
  LMapOptions.Center := LUluru;
  LMapElement := Document.getElementById(AControl.Handle.id);
  Map := JMap.Create(LMapElement,LMapOptions);
  LMarkerOptions.position := LUluru;
  LMarkerOptions.map := Map;
  LMarkerOptions.title := ATitle;
  LMarker := JMarker.Create(LMarkerOptions);
  end);
end;

end.

 

Then I could call it on any form and Control I want  :)

unit Form1;

interface

uses
  System.Types,
  SmartCL.Application,
  SmartCL.System,
  SmartCL.Forms,
  SmartCL.Controls.Elements;

 type

  TForm1 = class(TW3Form)
  private
    {$I 'Form1:intf'}
    MapDIV : TW3DIVHtmlElement;
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure Resize; override;
  end;

implementation

uses GoogleMaps;

{ TForm1 }

procedure TForm1.InitializeForm;
begin
  inherited;
end;

procedure TForm1.InitializeObject;
begin
  inherited;
  {$I 'Form1:impl'}
  MapDIV := TW3DIVHtmlElement.Create(Self);
end;

procedure TForm1.Resize;
begin
  inherited;
  MapDiv.SetBounds(0,0,ClientWidth,ClientHeight);
  InitMap('My API Key Here!', 'Mt Marcy', 44.112917, -73.923,  MapDIV);
end;

initialization
  Forms.RegisterForm({$I %FILE%}, TForm1);
end.

 

Link to post
Share on other sites
  • 4 weeks later...

Hi IElite, I'm not 100% sure what you're asking. The schema for the gpx file format is freely available; so extracting the data shouldn't be a problem. Also the reference datum used by gpx is WGS84, as is that used by google maps; so there should be no coordinate system conversions required. Loading markers at the defined coordinates is shown above; so is the issue with loading from a local resource? If it's the latter then I expect you might have to prompt the user for the file, request it from a server or extract it from a local db? I'm afraid I don't know alot about browser security and file access but if you post a sample file I'd be happy to have a play when I get a chance.

Link to post
Share on other sites

@Daniel Eiszele

I was referring to a file of coordinates that represent a tracklog or directions


Importing data  (looks like GPX would need to be first converted to GeoJSON)

https://developers.google.com/maps/documentation/javascript/importing_data

 // Create a <script> tag and set the USGS URL as the source.
        var script = document.createElement('script');
        // This example uses a local copy of the GeoJSON stored at
        // http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_week.geojsonp
        script.src = 'https://developers.google.com/maps/documentation/javascript/examples/json/earthquake_GeoJSONP.js';
        document.getElementsByTagName('head')[0].appendChild(script);
      }

      // Loop through the results array and place a marker for each
      // set of coordinates.
      window.eqfeed_callback = function(results) {
        for (var i = 0; i < results.features.length; i++) {
          var coords = results.features[i].geometry.coordinates;
          var latLng = new google.maps.LatLng(coords[1],coords[0]);
          var marker = new google.maps.Marker({
            position: latLng,
            map: map
          });
        }

 

Link to post
Share on other sites

the google map, defaults to the roadmap view, so I added the MapTypeId to the code i posted above

just add the following to the interface section

const
  HYBRID = 'hybrid';
  ROADMAP = 'roadmap';
  SATELLITE = 'satellite';
  TERRAIN = 'terrain';

  JMapOptions = record
    property Zoom : Integer;
    property Center : JLatLngLiteral;
    property mapTypeId: String;
  end;

change the following procedure to include the MapType param

procedure InitMap(AAPIKey, ATitle: String;  AMapType: String; ALat, ALong: Double; AControl: TW3CustomControl);

and then in the implementation section, modify the require to include the mapTypeId option 

Require(['https://maps.googleapis.com/maps/api/js?key=' + AAPIKey],procedure()
  begin
  ...
  LMapOptions.mapTypeId:= AMapType;
  ...
  end);

 

In my case, i needed my map to default to the TERRAIN view

so, i used the TERRAIN const

InitMap('myApiKey', Mountain, TERRAIN, Latitude, Longitude,  FMap);

e.g.

29pyccp.png

 

Link to post
Share on other sites
  • Administrators

I was able to get the map to work on Phonegap (Android and iPad) without any problems. I used the environment and plugins and config-file from the push notification -demo I did earlier. (The one that uses the Phonegap desktop and a mobile app that connects to it)

Just copy-pasting the needed parts of @Daniel Eiszele's code along with a new API-key was enough.

Thank you Daniel for a great example :-)

Edit: I've actually tried to get the Phonegap NOT to work by removing plugins and access-origin and allow-intent -sections in the config, but was not able to screw it up. IElite, do the problems occur for you in Phonegap build or where?

Link to post
Share on other sites
13 hours ago, jarto said:

I was able to get the map to work on Phonegap (Android and iPad) without any problems. I used the environment and plugins and config-file from the push notification -demo I did earlier. (The one that uses the Phonegap desktop and a mobile app that connects to it)

Just copy-pasting the needed parts of @Daniel Eiszele's code along with a new API-key was enough.

Thank you Daniel for a great example :-)

Edit: I've actually tried to get the Phonegap NOT to work by removing plugins and access-origin and allow-intent -sections in the config, but was not able to screw it up. IElite, do the problems occur for you in Phonegap build or where?

Hmmm, what does push notifications have to do with Google Map API?

I read your post, I am not quite sure which plugin you are referring to? There are so many of them on npm

Am i suppose to choose a certain one?  and add it to the config file ?   

e.g.     

<plugin name="cordova-plugin-googlemaps-master" spec="~ 1.3.9"  source="npm">
  <variable name="API_KEY_FOR_ANDROID" value="AIzaSyCU7roAAjLtFT2ItaMLcS6WN**********" />
</plugin>

Doing this makes no difference. I still get nothing .

Do I add something to the code using

if PhoneGap.Ready then 

begin

  PhoneGap.Notification.*

end;

 

 

Link to post
Share on other sites
  • Administrators

@IElite, what I meant was that you can download the zip file from that push notification demo and use its config.xml as it is. I did not have to install any kinds extra plugins for the Google maps to get it to work in the Phonegap desktop + Phonegap mobile app -environment.

So basically, you can ignore everything else in that same demo I made about the push notifications.

I even tested that on Phonegap Build by uploading a zip file and it created a fully working apk with no problems whatsoever.

One thing that may make a difference, though: I initialize the map stuff in Form1.InitializeForm instead of Form1.InitializeObject

 

Link to post
Share on other sites
5 hours ago, jarto said:

@IElite, what I meant was that you can download the zip file from that push notification demo and use its config.xml as it is. I did not have to install any kinds extra plugins for the Google maps to get it to work in the Phonegap desktop + Phonegap mobile app -environment.

So basically, you can ignore everything else in that same demo I made about the push notifications.

I even tested that on Phonegap Build by uploading a zip file and it created a fully working apk with no problems whatsoever.

One thing that may make a difference, though: I initialize the map stuff in Form1.InitializeForm instead of Form1.InitializeObject

 

@jarto if you are referring to the pgtest.zip file located here, that does not download. I get the following message: 

Sorry, there is a problem

We could not locate the item you are trying to view.

Link to post
Share on other sites
  • Administrators
8 minutes ago, IElite said:

@jarto if you are referring to the pgtest.zip file located here, that does not download. I get the following message: 

Sorry, there is a problem

We could not locate the item you are trying to view.

Yeah, that's the one I was referring to. Apparently there's some problems with attachments now. Gonna try to find out what went wrong.

Link to post
Share on other sites
  • 2 weeks later...

@jarto

"Yeah, that's the one I was referring to. Apparently there's some problems with attachments now. Gonna try to find out what went wrong."

Were you able to fix this. I would still like to see your config file to compare with mine. I still have not gotten Map to work on my android after processing through phoneGap

 

Link to post
Share on other sites
  • Administrators
Just now, IElite said:

@jarto

"Yeah, that's the one I was referring to. Apparently there's some problems with attachments now. Gonna try to find out what went wrong."

Were you able to fix this. I would still like to see your config file to compare with mine. I still have not gotten Map to work on my android after processing through phoneGap

 

I did e-mail you the zip-file. Didn't you get it?

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...