+ Start a Discussion
HL-DevHL-Dev 

What's the most efficient way to implement Google Maps mashups?

I've implemented a simple Google Map application that plots the top producers of a territory. Currently, the map is associated at the contact record level and it's set up as an S-Control that's attached to a custom button on the contact detail page.
 
I've started geocoding the contacts' addresses using the Google Map GClientGeoCoder class, which makes a call to the Google servers (I send the address to it and it returns the coordinates back). This process is very inefficient and overhead heavy, especially with multiple addresses. Plus, there's really no need to geocode an address if it has been previously, unless the address on the contact record has changed.
 
For anyone that has worked on integrating SF with GoogleMaps before: what's the best way to get the coordinates from an address? I've seen a previous thread that seems to store the coordinates into custom fields, but I cannot find the source code to understand how the storage-goecoding is done.
 
Any insights will be appreciated, thanks!
HL-DevHL-Dev
Ok, I've made some progress, but still need to know how to update the coordinates when an address has changed.
 
I have a custom S-Control that grabs all the addresses I need the coordinates for and sends it over to the Google server. If the addresses are successfully processed by Google, then I store the coordinates into 2 custom fields (latitude and longitude). Since the coordinates are now stored within SF, I can simply use these (instead of making a call to Google) to build my map.
 
This is working great so far, but I still need to handle the case when an address has changed and make a call to Google to update the stored coordinates in SF. Is there an Ajax toolkit function (like the ISCHANGED formula) that recognizes if a field value has changed?
 
Thanks in advance.  


Message Edited by HL-Dev on 05-02-2008 09:41 AM
The DevLife.ax318The DevLife.ax318

HL-Dev,

You have a couple of choices here:

1) User an Apex trigger to reset a flag on the record every time the address changes. The S-Control then uses the flag to determine which records need to be geocoded again.  This is pretty easy to do and provides the best performance.

2) You could use some type of hash function on the address and store the hash result in the data record.  Each time you can compute the hash of the address and see if it matches the one stored on the record, if not, you geocode. This works as well but may not be as performant since you need to compute the hash and compare everytime you map. You will want to keep your hash function as simple as possible.

Hope this helps!

 

Randy

HL-DevHL-Dev
The DevLife,
 
Thanks for your suggestions.
 
This is the difficulty I'm having so far:
1) As you suggested, I could write a trigger to reset a flag on the record when it changes. But in order for the S-Control to start processing the address after it has changed, that particular record would have to be accessed (as in a user accessing that record), since the S-Control's execution is tied to the client browser.
 
2) Again, I can write a trigger that will catch the address change event, but how would I go about sending a geocode request (client side JS)  from the Apex trigger or class? Since Apex code executes within SF servers, I don't think it's possible to execute an S-control from it.
 
Please let me know if you had a specific way of achieving this. And thanks for your suggestions again.
The DevLife.ax318The DevLife.ax318

HL-Dev,

Ideally, the best way to handle the address change is to use a Apex trigger that calls out to Google's geocoding service to geocode it in real time. Google does provide a HTTP interface to their geocoding service (http://code.google.com/apis/maps/documentation/services.html#Geocoding_Direct) and Apex code does allow you to make HTTP calls. However, their is a limitation right now that you cannot make HHTP calls from a Apex trigger. Until this limitation is resolved, this method won't work.

So, the way I have gotten around this is the S-Control that does the mapping does the geocoding in realtime as it maps. So in my mashup, I'm mapping accounts. I query salesforce for the accounts including the lat and long fields.  As I'm creating the map, I check to see if lat and long are null, if so, I call Googles gecoding service to get the lat, lon and then update the record with lat and lon. This works pretty good. Initially you may want to geocode the contacts seperetly so when the S-Control runs, it only has to geocode a few records. I have not tested this with geocoding thousands of records.

 

Now to deal with address changes, you could write an Apex trigger that when the addresses changes, simply set the lat and long field to null. When someone views the map, then lat and long will get updated. Or you could store some type of hash of the address and then compare the hashes as you do the mapping. This method tends to become a bit more compute intensive so you may want to go witht he Apex code if you can.

I hope this helps,

Randy

 

HL-DevHL-Dev

The DevLife,

I agree that the best approach to handle address change will be to use an Apex trigger/class that calls out to Google's geocoding service. I hope some time in the near future, SF adds a way to maky HTTP calls from Apex (maybe with the release of VisualForce?)

By reading your setup, I see that it's very similar to mine. I plot contact records according to a certain criteria and the S-Control is associated to a custom button. I have a second button that's dedicated to geocoding only if needed (calls out to Google only if any of the coordinates are null). The button that displays the map shows when the time of the last geocoding was, just to give the user an idea of how accurate the map is.

I'll try what you had suggested: to create an Apex trigger when an address has changed that will reset the coordinates to null. Since this change is done server side, the S-Control should be able to see the updated values of the coordinates (null) and execute the geocoding.

Thank you for your  input!