Twitter: raymondcamden

Address: Lafayette, LA, USA

CFMAP and Centering

12-27-2009 7,604 views ColdFusion 20 Comments

For a while now I've had two line items in my "To write about" notebook. They concerned figuring out how to use CFMAP (and Google Maps in general) to center the map on an address. Out of the box you have an immediate address that acts as the center, but I wanted to see how the center could be changed post map load.

My first attempt was to figure out a way to center the map on an marker. I began with an extremely simple script:

view plain print about
1<cfmap centeraddress="St. Louis, MO" width="400" height="400" name="mainMap">
3    <cfmapitem address="New Orleans, LA">

This generated:

Looking over both the ColdFusion docs and the Google Maps API, I began by adding ajaxOnLoad to the bottom of my script:

view plain print about
1<cfset ajaxOnLoad("init")>

And used this for my init:

view plain print about
1function init(){
2    ColdFusion.Map.addEvent("mainMap", "click", clickHandler)

This code adds a click handler for the map I created earlier. The click handler does:

view plain print about
1function clickHandler(item){
2    if (item) {
3        var map = ColdFusion.Map.getMapObject("mainMap")
4        map.setCenter(item.getLatLng())
5    }

Because I've got a click handler for the entire map, it runs whenever you click on it. However, it only passes event data when you click on one of the markers. Either the center marker (St. Louis) or New Orleans. This feels a bit.... fuzzy to me. I should probably check to see if item is an instance of a marker object. But the important part is the setCenter call. I run this on the map object returned by getMapObject. You can get fancy if you want to - change setCenter to panTo and you get a nice animation. View the Demo

Here is the complete code for that example:

view plain print about
5function clickHandler(item){
6    if (item) {
7        var map = ColdFusion.Map.getMapObject("mainMap")
8//        map.setCenter(item.getLatLng())
9        map.panTo(item.getLatLng())
10    }
13function init(){
14    ColdFusion.Map.addEvent("mainMap", "click", clickHandler)
23<cfmap centeraddress="St. Louis, MO" width="400" height="400" name="mainMap">
25    <cfmapitem address="New Orleans, LA">
32<cfset ajaxOnLoad("init")>

Ok, that works, but is a bit simplistic. I wanted to step it up a notch and add more interactivity. For my second demo, I created a list of cities. These cities were used as map markers, but I also wanted a simple HTML list as well. Clicking on the text version of the city would center the map. (I skipped making the marker work as well since I had just done that.) To begin, I created my list of cities.

view plain print about
1<cfset addresses = ["New Orleans, LA", "San Francisco, CA", "Washington, D.C.", "Houston, TX", "Miami, FL"]>

Next I wrote the code to generate the map and HTML list:

view plain print about
1<cfmap centeraddress="St. Louis, MO" width="400" height="400" name="mainMap" showcentermarker="false">
2    <cfloop index="address" array="#addresses#">
3        <cfmapitem address="#address#">
4    </cfloop>
9<cfloop index="address" array="#addresses#">
10    <cfoutput>
11    <a class="addressDisplay" href="javascript:center('#jsStringFormat(address)#')">#address#</a>
12    </cfoutput>

Notice that for each address I'm calling a JavaScript function center. Let's take a look at that:

view plain print about
1function center(s){
2    ColdFusion.Map.setCenter('mainMap',{
3        address: s
4    })

Yeah - pretty simple, right? Unfortunately, something goes wonky when you run this. The first time I ran my code, I ended up with new, green markers on the locations. This was before I added showcentermarker="false" to my map. I clicked a bunch of cities and each time it simply added green markers. It never actually centered.

When I added showcentermarker="false", it did absolutely nothing. You can see this yourself here. I'm guessing it is just a bug.

I decided to switch to the code I used in the first code sample. But to do that - I needed longitude and latitude. Normally I'd recommend always using those values (see my previous article on this linked to below), but I only had string addresses for now. I was lucky though to find a quick solution on the Google Maps API reference. They had this very simple example of using the Geolocation API:

view plain print about
1function center(address){
2    var geocoder = new GClientGeocoder();
4    geocoder.getLatLng(
5     address,
6     function(point) {
7     if (!point) {
8     alert(address + " not found");
9     } else {
10            map = ColdFusion.Map.getMapObject("mainMap")
11            map.setCenter(point);
12     }
13     }
14 )

Now the code creates a new instance of GClientGeocoder and runs getLatLng on the address. Notice the use of the inline function to handle the result and set the center. You can see this demo here: View the Demo

And here is the complete script:

view plain print about
1<cfset addresses = ["New Orleans, LA", "San Francisco, CA", "Washington, D.C.", "Houston, TX", "Miami, FL"]>
7function center(address){
8    var geocoder = new GClientGeocoder();
10    geocoder.getLatLng(
11     address,
12     function(point) {
13     if (!point) {
14     alert(address + " not found");
15     } else {
16            map = ColdFusion.Map.getMapObject("mainMap")
17            map.setCenter(point);
18     }
19     }
20 )
25.addressDisplay {
26 display: block;
27 background-color: #e0e0e0;
28 padding: 10px;
29 margin: 10px;
30 width:140px;
39<cfmap centeraddress="St. Louis, MO" width="400" height="400" name="mainMap" showcentermarker="false">
40    <cfloop index="address" array="#addresses#">
41        <cfmapitem address="#address#">
42    </cfloop>
47<cfloop index="address" array="#addresses#">
48    <cfoutput>
49    <a class="addressDisplay" href="javascript:center('#jsStringFormat(address)#')">#address#</a>
50    </cfoutput>

And finally, I decided to get crazy. I knew that Google's Streetview stuff was part of the main API. What I didn't know was how freaking easy it was to use.

view plain print about
1panoramaOptions = { latlng:point };
2var myPano = new GStreetviewPanorama(document.getElementById("streetView"), panoramaOptions);

In this snippet, point is a valid longitude/latitude pair. The call to GStreetViewPanorama simply creates the streetview within a DOM item. Now, my addresses are pretty vague so this demo ain't great, but you can imagine how cool this would be for your business if you supplied some fuller data points. View the Uber Elite Awesome Demo

Pretty cool, right?

Related Blog Entries


  • Commented on 12-27-2009 at 7:25 PM
    This is awesome and great to know that using Google Streetview with CFMap is so easy. Thanks for posting Ray!
  • Commented on 12-28-2009 at 8:46 AM
    Thats very cool.
  • Commented on 01-18-2010 at 10:05 AM
    Does CFMap support driving directions?
  • Commented on 01-18-2010 at 10:07 AM
    Nope. But you could do it manually getting the map object via the provided API.
  • Commented on 01-18-2010 at 10:27 AM
    I have a proof of concept done. Blog post in an hour.
  • Commented on 01-18-2010 at 1:17 PM
  • Matt #
    Commented on 05-17-2010 at 7:37 PM
    I've found that when you use either the mouse wheel or double click to zoom on the map, the cfmapitems are not redrawn... just a blank map. If you use the map zoom control it works, but who actually uses that? Double click seems like second nature to zoom. Any ideas how to fix this?

    For an example:
    Use your mouse wheel or double click... the map icons disappear.
  • Commented on 05-18-2010 at 4:17 PM
    I can confirm it does that. Please file a bug report for that:
  • DC #
    Commented on 09-30-2010 at 10:35 AM
    This was helpful to get me started. I'd love to see something that shows how to integrate the Map API with a control such as cfgrid.
    For instance, I've got both a cfgrid and a cfmap on my page. Both are populated with the same records (each record returned in the cfgrid has a lat/long that is displayed on the cfmap).
    I can't quite figure out how to do something like hover over a row in the cfgrid and make the map center to the corresponding point... or just temporarily change the color of the icon on the map.
    To complicate it, my cfgrid is inside a <cfform> and uses the href, hrefkey, and selectmode='row' attributes. Meaning, a URL is launched when one single clicks on a row. So I can't use the rowclick event of the grid. ugh.... stuck...
  • Commented on 10-04-2010 at 4:51 PM
    Couldn't you simply use cfajaxproxy to bind to the cfgrid? I've got a few blog entries up on that.
  • DC #
    Commented on 10-05-2010 at 12:30 PM
    Hmm.. Wish I knew. I'll go through your posts, if I can figure out where to start. I'm not sure just yet how to approach it since I'm talking about having the icon dynamically change, etc. But maybe your posts will help me understand the basics.
  • Commented on 10-05-2010 at 3:31 PM
    Ok, feel free to follow up with me via my Contact link.
  • Kent #
    Commented on 01-25-2011 at 4:25 PM
    Here I am late again. Thankyou so much for this detailed explanation and samples. One question, Will this work on CF8 as well, as my host is CF8 still. I am using the CF9 developer for tests though.
  • Commented on 01-25-2011 at 4:26 PM
    cfmap was added in CF9 so no. However, it is not hard to use Google Maps "natively". It is about 5 minutes more work.
  • Commented on 01-26-2011 at 9:47 AM
    This is very cool. I can get it to work perfectly in a stand alone page, but I am having problems displaying the street view in a cflayoutarea. Clicking on the link freezes the browser. Any ideas? Thanks!
  • Commented on 01-26-2011 at 1:13 PM
    It could be a conflict between the JS code used to generate cflayoutarea and the Google stuff. That's the best I can think of now.
  • Commented on 03-05-2013 at 4:35 PM
    how can i update this code from V2 to V3? i'm having problem since v2 was deprecated... please help.

    function buildMap()
       // figure out where service area is.
       var geocoder = new GClientGeocoder();
       <cfoutput>var zip="#zip#"</cfoutput>
       function (point)
          // create a map
           map = new GMap2(mapdiv, {draggableCursor:"auto", draggingCursor:"move"});
          // Add a div element for toolips
           tooltip = document.createElement("div");

          if (!point)
             alert ("No zip code entered, so providing large scale map.");
             map.setCenter(new GLatLng(39,-97), 4);   // middle of the country
          map.addControl(new GLargeMapControl()); // Zoom control
           // Create a hierarchical map type control
           var hierarchy = new GHierarchicalMapTypeControl();
           // make Hybrid the Satellite default
           hierarchy.addRelationship(G_SATELLITE_MAP, G_HYBRID_MAP, "Labels", true);
           // add the control to the map
           map.addControl(new GScaleControl()); // Scale bar
           // Add click listener
           GEvent.addListener(map, "click", leftClick);

           // read in points for stored polygon
           for (var pers=1; pers<4;pers++)   // for each perimeter
             for(var n=0;n<perimeters[pers].length;n++)
              leftClick ("init",perimeters[pers][n],pers,n); // produced 1st marker, but then looped in same spot
             //marker = markers[0];
             if (pers==1) polyColor=RGB2Color(255,0,0);
             if (pers==2) polyColor=RGB2Color(0,255,0);
             if (pers==3) polyColor=RGB2Color(0,0,255);
            drawOverlay(perimeters[pers],polyColor);   // creates a polygon from everything in markers
  • Commented on 03-06-2013 at 5:45 AM
    Well I'd begin by asking you which specific portion failed. If it was getX or somesuch, I'd then focus on see what I can use in the v3 API to replace that.
  • Commented on 03-06-2013 at 10:56 AM
    thanks for the reply, the whole functionality is having issue here. it was working fine until last month but now it is showing message that "Google disabled the use of v2 API" something like that.
  • Commented on 03-06-2013 at 1:04 PM
    venkat - I'm not going to rewrite the entire thing for you. What I'd recommend is starting fresh with the v3 API. Please see their getting started guide and read up a bit.

    In terms of the error you are getting with CFMAP, we released an update for that. See:

Post Reply

Please refrain from posting large blocks of code as a comment. Use Pastebin or Gists instead. Text wrapped in asterisks (*) will be bold and text wrapped in underscores (_) will be italicized.

Leave this field empty