Sep 8, 2014

Lab Coat Lesson: The Google Maps API



This blog post will discuss the various Google Maps Web API’s and their features. We will show you a few ways to use them in your next Salesforce project and give you some sample code to get you started right away. You will be able to add maps to your record details, in pdf’s, custom visualforce pages and with a little thought anywhere else you so desire within your Salesforce instance. Your best help on this adventure will be from Google itself at http://developers.google.com/maps/.

We will be covering the following Google Maps API's :
Embed - allows you to iframe a map
Geocoding - get the coordinates for an address
Static Map - create an image of a map
JavaScript - fully customizable map 

Instant Gratification: Google Maps Embed API
Do you have a record with an address field on it and desire to show it’s location on a map? The Embed API will accomplish that for you with very little effort on your part. With a couple dozen lines of code you can create an inline visualforce page on an object of your choice (such as Account or Lead) that shows the record's location! Here’s the finished product:



Here is the visualforce code that produced this: 


All we are doing here is passing in the address fields as parameters into the iframe source.

**Don’t forget to add http://maps.googleapis.com to your Remote Site Settings! We keep it simple for now and assume that the record has values for the Street Address, City, State, Zip Code, and Country fields. The controller gathers these values for the page like so:



That’s all there is to it! This can be extended further by passing the “Mode” parameter, for example directions. You could even potentially show directions based on records of a related list by passing all of their addresses as parameters to the iframe src.

Latitude and Longitude? Google Maps Geocoding API
Geocoding standardizes your addresses with high accuracy, a very important need in businesses. Slight variations in addresses can lead to dramatically different interpretations as to their physical locations. Different parts of the world build their addresses in different ways. And do we really want to keep lugging around all those various fields each time we try to map? Using a latitude and a longitude sets the frame of reference to an exact point on the sphere that is our dear planet Earth. This also serves as an address validation tool — failure to return a latitude and longitude pair would imply that the location could not be found in the Google (in this case) database. 

We’ll add this code to the page controller we created earlier so we can perform a geocode through the page while viewing the record. Let’s see how it’s done:


We added a button and an output field to see what we’re doing from the inline visualforce page we built earlier:


The result is this :


We pressed the button, geocoded the address, printed the result on the page, and also updated the record’s address field with the coordinates. Geocoded!

Need an image? Google Maps Static API
Suppose you would like to include your new map in a pdf. Well, we can’t go about embedding something dynamic like an <iframe> in a pdf, but what we can do is get an image of the map and embed that instead. The image tag could be stored somewhere like a field on the record, perhaps built in the controller from address fields in the record. Here is the result:


Image__c here is a rich text field that simply contains an image tag with an src leading to the Static Maps API endpoint, passing in lat/lng coordinates from our Address__c geolocation field as parameters. We added the following method in the controller, which is called by a button on the page:


THE Google Maps Javascript API
If you really want to unleash the potential of Google Maps look no further than the Google Maps Javascript API.  Using the Javascript API allows you to wield much greater power and control over your maps behavior, adding layers of interaction and features unavailable through just the Embed API.
First let's improve on what we did earlier with the Embedded API -- let's now show all World__c records on the map in one go:

Let’s take a look at the code used to generate the above. 

(1.) The heart of the map functionality is generated in the initialize() function, called on window load. 
-MapOptions is used to specify characteristics of the map, in this case where to center the map (location of the current record) and the zoom level
-The div to be used to contain the map is specified — the API now knows where to put the map it generates





(2.) We want to show all the World__c records on the map, so we build a list of them (AllLocations property) in the new controller we created as follows:



-This simply gathers the relevant record properties (coordinates, name) and bundles them up to be used in the script.
-A marker is instantiated for each record and its coordinates are set



Reasonable enough.. But what about actually creating the World__c records? We will create an example where we can drop a pin anywhere in the world, and create a record in salesforce right then and there — from within the map! This is what it will look like:



We want to capture the event of the user clicking on the map, get those coordinates, and have the option to create a new record from the location the user clicked on. Here is what we added to the initialize() method in the page code used to accomplish all this: 


                       

There may seem like a lot is going on there so let’s take a closer look. 


(3.) There are a multitude of events that the API could potentially respond to, one of which is a click of the mouse on the map. We use an event listener here to capture the coordinates of the mouse click to help us build a record from it later.

(4.) We create a marker on the spot where the mouse was clicked. 
-We add a click listener on the marker so that we can show a popup dialog (called an infobox) 
-We define the infobox to have an input field, a button, and the lat/lng coordinates. We used the counter here to uniquely identify the infobox being used, as the user can add multiple pins to the map (and hence have multiple infoboxes in the DOM). For each marker added in this way, we increment the counter to keep track of the input field. 

(5.) Once the user clicks the save button in the infobox, we pass the latitude, longitude, and counter to a javascript method
- The method gets the value of the inputted name based on the counter passed to it (id of the element is a concatenation of “name” + “ counter” ex: “name4” for the 4th marker created this way
- Call a method in the controller to create the record with the coordinates and name specified : 

*The method is marked as global to allow it to be called from within the inline page

And voila! We have created a new record from the map! 




While this post only skimmed the surface of the APIs, we hope that it has set you in the right direction in beginning your own explorations of them. Try creating directions between records in your org by using a polyline, or adding record details to an infobox, perhaps an image roll.. There are any number of things you can do still that are fun to try and thankfully are also very well documented.