Syntax Highlighter JS

Tuesday, December 11, 2012

A follow-up on google maps

UPDATE: As this example no longer works, Please see the updated version which can be found here.

I previously posted a Geocoder example for Google maps. Since that was posted, Salesforce has added Geolocation fields to their system.  I highly recommend that you use this new field type instead of the text field type in my original post.  This is so you can query by distance as seen in the example query from Salesforce.

This class is great for coding existing data and will eventually code new data coming into the system.  However, if you want a more real time coder (i.e. based off a trigger), you can see an example of that here.  Please be sure to read my comments at the bottom of that page for some improvements you might make if you use that class alone or in combination with my scheduled class.

If you are going to use scheduled classes (such as my Geocoder) in your system, then I highly recommend that you read this very interesting scheduled apex solution by Dan Appleman.

Once you have your data geocoded, you will most likely want to create your own Goolemaps mashup.  Here is a great GoogleMaps API tutorial to get you started.

You will want to look at the source to his example page to get you started with the JavaScript required to have a mash-up that paints some static points on the map.  Once you have a static example created, then you can explore how to integrate this with visual force to paint a dynamic list on the screen.

You will need to go ahead and create your apex controller for the page. Inside of that controller populate a list of objects from SOQL.  If want to do this based on distance, be sure to look back up at the example query in the first paragraph for an example.

For this example, I am going to query for 10 random accounts.  I am sure that your final code will be much more complex but I am focusing this post on the JavaScript and Visualforce required to make this work.

Please note that I am querying the Name and ID field in addtion to the BillingLong__c and BillingLat__c fields from the Geocoder example.  This is important because any data you want to present will need to be included in the query.  Here is the example controller:
public with sharing class TestController { public List<Account> AccountsList {get;set;} public TestController() { AccountsList = [SELECT ID, Name, BillingLat__c, BillingLong__c FROM Account LIMIT 10]; } // end constructor } // end class

Please note that you cannot use the standard Salesforce css with this example. Also, this example is using V3 of Google maps API which doesn't require a key. Here is the example page: <apex:page sidebar="false" showHeader="false" cache="false" controller="Test2Controller"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>Google Maps Example</title> <script src="http://maps.google.com/maps?file=api&amp;v=3&amp;sensor=false" type="text/javascript"></script> <script type="text/javascript"> // map and geocoder vars var map = null; var geocoder = null; var BaseMarkerOptions = null; // This function should be called onload of the body of the page function initialize() { if (GBrowserIsCompatible()) { var polys = []; var labels = []; // Display the map, with some controls and set the initial location map = new GMap2(document.getElementById("map")); map.addControl(new GLargeMapControl()); map.addControl(new GMapTypeControl()); // You will need to adjust this location to be the center coordinates and zoom level that you want // You can set this using visual force if needed map.setCenter(new GLatLng(32.5206608,-86.80249),5); geocoder = new GClientGeocoder(); // use our default marker options SetMarkerOptions(); // use visualforce to pull in the data from the SOQL query and use javascript to paint the points on the screen // the funciton call is: showAddress(html, Lat, Long) // HTML is the code to be displayed in pop-up when the point/marker is clicked. // Notice that JSENCODE is used to prevent javascript errors <apex:repeat value="{!AccountsList}" var="Account"> showAddress("{!JSENCODE(Account.Name)} <br /> <a href='../{!Account.id}' target='_blank'>Details</a>", "{!Account.BillingLat__c}", "{!Account.BillingLong__c}"); </apex:repeat> // enable the mouse wheel for zooming. Alot of mash-ups don't enable this for some reason. map.enableScrollWheelZoom(); send(null); } // display a warning if the browser was not compatible else { alert("Sorry, the Google Maps API is not compatible with this browser"); } // GBrowserIsCompatible() } // function initialize() // this function sets the icon and size to be used. It is using the defaults ATM but could be changed. function SetMarkerOptions() { var baseIcon = new GIcon(G_DEFAULT_ICON); baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png"; baseIcon.iconSize = new GSize(20, 34); baseIcon.shadowSize = new GSize(37, 34); baseIcon.iconAnchor = new GPoint(9, 34); baseIcon.infoWindowAnchor = new GPoint(9, 2); BaseMarkerOptions = { icon:baseIcon }; } // SetCustomMarkerOptions // this is the function that actually adds a marker on the map from the point (long/lat) data. function createMarker(point,html) { var marker = new GMarker(point); GEvent.addListener(marker, "click", function() { marker.openInfoWindowHtml(html); }); IncrementRenderedPoints(); return marker; } function showAddress(html, Lat, Long) { var myLatlng = new GLatLng(parseFloat(Lat), parseFloat(Long)); if (myLatlng != null) { var marker = new GMarker(myLatlng, BaseMarkerOptions); GEvent.addListener(marker, "click", function() { marker.openInfoWindowHtml(html); }); map.addOverlay(marker); } // check for null myLatlng } // end show address </script> </head> <body onload="initialize()" onunload="GUnload()"> <div id="map" style="width: 1024px; height: 768px"></div> <noscript><b>JavaScript must be enabled in order for you to use Google Maps.</b> However, it seems JavaScript is either disabled or not supported by your browser. To view Google Maps, enable JavaScript by changing your browser options, and then try again. </noscript> </body> </html> </apex:page>
And here is what the example looks like:

5 comments:

  1. Very interesting post but not working with Google Chrome.

    I tried to remplace "http" with "https" but this time it requires an API key and then say that the browser is not compatible.

    Any idea to get this working on Chrome ?

    ReplyDelete
  2. In fact there's an error message :
    "Oops! 's billing address could not be found, please make sure the address is correct."

    ReplyDelete
  3. Anonymous,

    Sorry but I do not use Google Chrome as it isn't supported at my company. My example above uses the V3 of Google Maps API's free edition, which doesn't require an API key for HTTP connections.

    For HTTPS connections, you must be a Google Maps Premier customer. That is likely why you are getting the request for an API key.

    If you really need the secure connection, then it seems that you will have to pay Google or design something based on Bing Maps.

    More details are required to help you find the cause of the billing address error. Where is the error about the billing address coming from? Visualforce? JavaScript?

    I ask because the Google maps mash-up example above doesn't directly reference the billing address but instead uses custom long / lat fields.

    Thanks

    ReplyDelete
  4. Anonymous,

    It appears that Google has changed the URL of the server and some settings. This is likely the cause of error message about the browser not being compatible. I am working on a updated example that works with these changes. More to follow . . .

    ReplyDelete
  5. Please see my updated example that works with the latest changes from google.

    ReplyDelete