Simple introduction to Google Maps

This post is more than 2 years old.

I've done quite a few blog entries on cfmap, ColdFusion's wrapper to the Google Map API. While cfmap makes using the API as easy as possible, there may be cases where you want to use the map API natively. For example, ColdFusion's use of the API is tied to version 2 of Google's API. The current version is 3. I decided to take a quick look at what's involved with working with Google's Map API by itself. Here are some examples and notes. Please note that there are multiple wrappers out there to make this process easier - including support for doing maps via a jQuery plugin. I'm intentionally avoiding these as I want a 100% pure solution.

To begin, you may want to take a look at what Google calls the Map API Family. This is a high level directory of all the Map APIs. This blog entry is concerned with the latest version of the JavaScript API. One thing I'll point out right away is that the latest version of the API does not require a developer key. That doesn't mean we get to use the service without limit (you'll see a good example of this later), but it does mean we skip signing up for a developer key. Google makes this easy - but also ties the key to a particular domain. In my cfmap examples I can't tell you how many times I got hit by a dev versus production move.

I began my research by reading the tutorial. It's a good entry, but a bit overly complex. I took their code and stripped it down a bit to make it even simpler. Here is my version of their first code block.


<!DOCTYPE html>
<html>

<head>
<style type="text/css">
  #map_canvas { width: 450px; height: 450px; }
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
function initialize() {
	var latlng = new google.maps.LatLng(31, -92);
	var myOptions = {
		zoom: 8,
		center: latlng,
		mapTypeId: google.maps.MapTypeId.ROADMAP
	};
	var map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);
}
</script>
</head>

<body onload="initialize()">

  <div id="map_canvas"></div>

</body>
</html>

The critical parts of this template are:

  • Loading the Google Maps JavaScript API. What's with the sensor=false? That tells Google to not try to load your location. This is only useful on mobile devices or geolocation enabled browsers. And let's be honest. If your intent is to show your users the location of objects, you probably don't care where they are. (At least not yet.)
  • Notice the div called map_canvas. Google Maps works by writing the map into a div. It is critical that the div have a precise size. In this case the size is set in a style block.
  • The body tag runs a function, initialize, on startup. Creating a map comes down to choosing your settings and then passing it to a Map initializer. This example just uses 3 settings - a zoom level, a center, and a map type. According to the docs these three settings are your minimum.

All in all - not a lot of code, right? You can test this here. For a slightly more advanced example, this template simply adds a bunch more options. (You can find the full list of options here.)


<!DOCTYPE html>
<html>

<head>
<style type="text/css">
  #map_canvas { width: 450px; height: 450px; }
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
function initialize() {
	var latlng = new google.maps.LatLng(31, -92);
	var myOptions = {
		zoom: 8,
		center: latlng,
		mapTypeId: google.maps.MapTypeId.HYBRID,
		panControl:false,
		zoomControl:false,
		streetViewControl:false,
		mapTypeControl:false
	};
	var map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);
}
</script>
</head>

<body onload="initialize()">

  <div id="map_canvas"></div>

</body>
</html>

You can run this demo here<. Ok - so far, I've all done is create a map at a certain longitude and latitude. (Keep watch - I'm going to typo the heck out of those words probably.) It's possible your data may contain such information already. It probably doesn't. Google does have a web service you can run to get geolocation information. (You can find a ColdFusion wrapper here.) I use this service at Adobe Groups to geolocate group data on a scheduled basis. But what if you want to geolocate on the fly? Luckily this is possible via JavaScript as well, but you are limited to 2500 requests per day. (See details here.) I'd probably suggest geocoding server side and doing it one time only as opposed to on the fly with every request. But if you do want to do it in JavaScript, here is an example.


<!DOCTYPE html>
<html>

<head>
<style type="text/css">
  #map_canvas { width: 450px; height: 450px; }
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
function initialize() {
	var address = "Lafayette, LA";
	geocoder = new google.maps.Geocoder();

	geocoder.geocode( { 'address': address}, function(results, status) {
		if (status == google.maps.GeocoderStatus.OK) {

			var myOptions = {
				zoom: 8,
				center: results[0].geometry.location,
				mapTypeId: google.maps.MapTypeId.ROADMAP
			};
			var map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);

			var marker = new google.maps.Marker({
				map: map, 
				position: results[0].geometry.location
			});
		} else {
			alert("Geocode was not successful for the following reason: " + status);
		}
	});
	
}
</script>
</head>

<body onload="initialize()">

  <div id="map_canvas"></div>

</body>
</html>

In this template, I begin with free form address string for Lafayette, LA. I create a new geocoder object and fire off the geocode request. This is asynchronous so a callback function is used to handle the result. If the result was good, we have a location object that contains our longitude and latitude. This can then be passed to the Map initializer. That by itself is it - but I went ahead and took more code from Google's doc to create a simple marker object. You can see this demo here.

Ok - can we use some ColdFusion now? I wanted to create a simple demo based on database data. I began by writing the query and a simple table output.


<cfquery name="getorders" datasource="cfartgallery" maxrows="10">
select	orderid, total, orderdate, address, city, state, postalcode
from	orders
</cfquery>

<table border="1" width="100%">
	<tr>
		<th>Order ID</th>
		<th>Total</th>
		<th>Date</th>
		<th>Shipped To</th>
	</tr>
	<cfoutput query="getorders">
	<tr>
		<td>#orderid#</td>
		<td>#dollarformat(total)#</td>
		<td>#dateFormat(orderdate)#</td>
		<td>
		#address#<br/>
		#city#, #state# #postalcode#
		</td>
	</tr>
	</cfoutput>
</table>

I assume nothing here needs explanation but if so, leave a comment. Now let's look at a modified version - one that integrates with Google maps.


<cfquery name="getorders" datasource="cfartgallery" maxrows="10">
select	orderid, total, orderdate, address, city, state, postalcode
from	orders
</cfquery>

<!DOCTYPE html>
<html>

<head>
<style type="text/css">
  #map_canvas { width: 450px; height: 450px; }
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
function showMap(address) {
	geocoder = new google.maps.Geocoder();

	geocoder.geocode( { 'address': address}, function(results, status) {
		if (status == google.maps.GeocoderStatus.OK) {

			var myOptions = {
				zoom: 8,
				center: results[0].geometry.location,
				mapTypeId: google.maps.MapTypeId.ROADMAP
			};
			var map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);

			var marker = new google.maps.Marker({
				map: map, 
				position: results[0].geometry.location
			});
		} else {
			alert("Geocode was not successful for the following reason: " + status);
		}
	});
}
</script>
</head>

<body>
<table border="1" width="500">
	<tr>
		<th width="60">Order #</th>
		<th width="100">Total</th>
		<th width="100">Date</th>
		<th>Shipped To</th>
	</tr>
	<cfoutput query="getorders">
	<tr>
		<td>#orderid#</td>
		<td>#dollarformat(total)#</td>
		<td>#dateFormat(orderdate)#</td>
		<td>
		#address#<br/>
		#city#, #state# #postalcode#<br/>
		<cfset fulladdress = address & " " & city & ", " & state & " " & postalcode>
		<a href="##" onclick="showMap('#jsStringFormat(fulladdress)#');return false">Show Map</a>
		</td>
	</tr>
	</cfoutput>
</table>

<div id="map_canvas"></div>

</body>
</html>

So what did I do? I began by adding a link to a JavaScript function called showMap. I passed in the address of the order data I am displaying. showMap is basically the same code as before except now my address value is passed in as an argument. You can see this demo here.

So - this is just scratching the surface of what's available, but as you can see it isn't too hard to use. I hope this helps - and if anyone has follow up questions, just leave a comment.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Steve &aposCutter&apos Blades posted on 2/16/2011 at 5:11 PM

Great stuff Ray. I love the v3 API, and wrote a custom tag a few months back that's on RIAForge (http://cfgmap.riaforge.org). The whole thing is heavily documented, but basically it allows one to put some config options as tag attributes, and the tag will create the initialization of the map. It takes an array of object locations to plot on the map. Any locations that are geocoded can have their lat/lng's passed back to the server via a callback option in the tag to update those location's records in the db. There's even an example script that show's how to use the custom map object for getting directions from input and links, recentering the map on specific locations, and more.

http://blog.cutterscrossing...

Comment 2 by Ed posted on 2/17/2011 at 12:30 AM

Great writeup. Have you done any work with google maps where there were too many points in an area and you showed larger icons until you zoom in? I haven't figured out how to implement something like that. That would be a blog post I would be very interested in. =)

Comment 3 by Raymond Camden posted on 2/17/2011 at 2:50 AM

@Steve: Very cool. Thats a good example of where custom tags still make a lot of sense.

@Ed: Um - not quite there yet. ;)

Comment 4 by Ed posted on 2/17/2011 at 5:25 AM

I had done some research on the too many markers issue some time ago but it looks like Google has recently documented some solutions for this:

http://code.google.com/apis...

In particular MarkerClusterer looks like what I was envisioning. We'll see how it pans out...

Comment 5 by ja posted on 3/3/2011 at 11:41 PM

Very easy to follow..Ray. Just have one issue I cannot seem to resolve..
- I'm using your code on my Spry "Map Customer" Tab to display a single cust/address.
- I have everything working fine, except my query will not refresh & grab the current customer?
- Here is my query: <cfquery name="rsCAImap" datasource="salesPipeline">
SELECT wkRptID, wkRptAcqDate, wkRptCustName, wkRptBusAdd, wkRptCustCity, wkRptBusSt, wkRptBusZip
FROM tblWeeklyRpt
WHERE wkRptCd = 'CAI' AND tblWeeklyRpt.wkRptID = <cfqueryparam value="#URL.id_com#" cfsqltype="cf_sql_numeric">
ORDER BY wkRptCustName ASC
</cfquery>
-----------------------------------------
- Here is an example of my page URL: http://192.168.1.77/COE/salespipeline_wrd.cfm?wkRptID=1825
- Is there something I can change in your "Calling Code" below to make sure the Query "grabs" the URL parameter before running?
- Here is your "calling code": <cfoutput query="rsCAImap">
<tr>
<td bgcolor="##FFFFFF"> #wkRptBusAdd#<br/>
#wkRptCustCity#, #wkRptBusSt# #wkRptBusZip#<br/>
<cfset fulladdress = wkRptBusAdd & " " & wkRptCustCity & ", " & wkRptBusSt & " " & wkRptBusZip>
<a href="##" onclick="showMap('#jsStringFormat(fulladdress)#');return false">Show Map</a></td>
</tr>
</cfoutput>
--------------------------------------------
Thanks again for a cool, quick Google map implementation..
jaa

Comment 6 by Raymond Camden posted on 3/11/2011 at 4:18 AM

So you have 2 tabs then - tab one a list with links and tab 2 the map?

Comment 7 by ja posted on 3/11/2011 at 6:23 AM

Ray, I figured it out.. just needed to reference my main form's query, didn't need the other query at all..
- To answer the question, Yes I have multiple SpryTabs, but only one main query, see image below:
- http://cerberus.clearwave.c...

By the way, I also tested your orders2.cfm Demo where it lists all customers down the page..
How does one alter that code to plot multiple addresses on a single map?

No cfmap in my CF7MX.. Thanks again.. ja

Comment 8 by Raymond Camden posted on 3/12/2011 at 12:44 AM

You need to use markers. A bit more work, but not terribly so.

Comment 9 by Adrian posted on 3/25/2011 at 2:29 AM

Hi

This is perfect for what I was thinking of doing. Quick question is, how can I modify this to accept more than 1 location, e.g. if I wanted to show all accommodation for town?
Thanks

Comment 10 by Raymond Camden posted on 3/27/2011 at 6:45 PM

You see how my code adds markers one at a time? You would just... well more. :) Does that make sense?

Comment 11 by Irv posted on 4/7/2011 at 12:43 AM

Hi, Ray

Is there a way to use the API v3 to make a map black and white based on your code (above)?
I found some code I'm using and it works, but the code seems awfully 'verbose' (at least to me). I can provide the url if necessary.

Thanks!

Comment 12 by Raymond Camden posted on 4/7/2011 at 12:54 AM

According to the API docs there is a style system you can use:

http://code.google.com/apis...

It doesn't look terribly simple - but I believe this would be the way.

Of course - if you don't mind using the Static Map API (which I've discussed many times on the blog), you can use ColdFusion to download the map and make it BW pretty quickly.

Comment 13 by Irv posted on 4/7/2011 at 3:01 AM

Thank for the quick response!

I 'm using code very similar to the one that page, but I was looking for something a little simpler. Once again, thank you for your generosity. You're one of the true gems of the Coldfusion world!

Comment 14 by Raymond Camden posted on 4/7/2011 at 5:21 PM

Going to do a blog entry today or tomorrow on simple/dumb cfimage tricks with Google Static Maps. I will probably forget to post back here - so check the RSS feed. :)

Comment 15 by Dani posted on 4/19/2011 at 11:32 PM

Hi Ray, great post. Do you have any examples using the Google Map API with cfwindow or cfdiv? I thought that re-writing my functions in this format: functionName = function(arguments) {function body} would solve the issue. However, I still haven't had luck getting a google map to render in a cfdiv or cfwindow.

Comment 16 by Raymond Camden posted on 4/19/2011 at 11:39 PM

I'd probably just use cfmap if using cfdiv as well. In general, I don't mix CF's front end ajaxy stuff with "native" JS stuff very often. That being said - how is it failing for you?

Comment 17 by Dani posted on 4/20/2011 at 12:24 AM

Thanks for responding so quickly. I borrowed some of your example code to illustrate the problem I'm having:

http://pastebin.com/kzSQvxqW

It seems like the body onload function is not working within the cfwindow. I tried calling initialize() using ColdFusion.Window.onShow(). I am not really sure where the problem is.

Comment 18 by Raymond Camden posted on 4/20/2011 at 12:34 AM

You need to move your script tag that loads google maps into your parent document.

Comment 19 by grietje goedkoop posted on 5/20/2011 at 3:52 PM

I also tried with coldfusion.navigate and cfdiv to load cfmap. Tried to put load google maps in parent, in self. Nothing happens. Perhaps cfmaps or google map api doesn't work with iframe (tested that as well with no success), or cfdiv?

Comment 20 by grietje goedkoop posted on 5/20/2011 at 4:12 PM

Sorry for the unnecessary post, found it...

Comment 21 by Matt posted on 6/20/2011 at 8:54 PM

Thanks for the post. Have you had any luck or have any knowledge how one would save the google map generated by javascript api v3 to someone's My Maps account AND how to use cf to save as pdf without resorting back to static maps.

I am trying to plot map with lots of markers and google does not give a print button or save to my maps with the map that is returned so was hoping you had some sneaky CF workarounds!

Thanks
Matt

Comment 22 by Raymond Camden posted on 6/21/2011 at 6:15 AM

As far as I know there is no way to go to PDF from the JS based map. As to your first question, I'd check the Maps API. That sounds like something that should be possible.

Comment 23 by Steve &aposCutter&apos Blades posted on 6/21/2011 at 2:08 PM

@Matt -

Client side, you can programmatically add a button or link that has the "window.print();" javascript attached to it, allowing the user to easily print the output. Since the js api is client side, there really isn't a way to use cfpdf, or something else, to generate a pdf at the server. A user with Adobe Acrobat can manually change their print driver to create a pdf, but that's about the extent of it.

Comment 24 by grietje goedkoop posted on 7/14/2011 at 6:01 PM

I experience a CFMAP mystery:

I have a page where there are 3 divs showing different parts of content. When you open the page div 1 is visible and the other 2 are hidden (style="display:none;").
You can click to open (toggle visibility) div 2 or 3.

In div 2 is a google map (cfmap script).

Now here's the mystery:
If Div 2 (with the cfmap) is NOT hidden initially, everything is fine

See: http://www.cyprustripadviso...
Here both div1 and 2 are initially visible.

If Div2 IS hidden initially and you click to toggle visibily of the divs the map has shifted left and up.
See: http://www.cyprustripadviso...
Here only div1 is initially visible. Click "LOCATION" to make visible.

Does anybody has a clue why this can happen? Or had a similar experience?

Comment 25 by Raymond Camden posted on 7/24/2011 at 6:26 PM

When I tried your site and clicked LOCATION, _nothing_ was visible. I mean below your top header.

Comment 26 by Raymond Camden posted on 7/24/2011 at 6:27 PM

I did a view source and saw this: Google Map License key is not defined.

Looks like your map key isn't rght.

Comment 27 by grietje goedkoop posted on 7/25/2011 at 10:10 AM

Hi Ray,
I've found the cause of the problem. It has nothing to do with cfdiv/cfmap but it is a problem of google map in general. Google describe what to do on http://code.google.com/apis....
I've sent an email to you with the details on 21-7.
Thanks a lot for your help,
Grietje

Comment 28 by Raymond Camden posted on 7/25/2011 at 3:28 PM

Ah ok - I see it. Still a bit buried in email. :)

Comment 29 by Randy Smith posted on 2/8/2012 at 5:47 AM

Ray,

I am still stuck in CF8 so no CFMAP for me, but I did use your examples and have expanded on them via other Google things I've found online.

One mystery though: how in the heck does one generate the tag that users can click to 'get directions'? Nothing I try seems to want to bring that little rectangle up with the get directions link.

Thanks for any light you can shed on this.
RLS

Comment 30 by Raymond Camden posted on 2/8/2012 at 9:48 PM

Hmm - not quite sure what you mean. Obviously there is a Directions API, and I've blogged on this, but you're asking about a particular UI element. Do you have an example I can look at?

Comment 31 by Randy Smith posted on 2/8/2012 at 11:39 PM

When you go to maps.google.com and enter an address, they allow you to get the links. When you grab the HTML iFrame code and put it into your site and execute it, you get the white balloon box that has the "Directions" link in it (Example: http://home.tmrme.mobi/#/in....

This white rectangle box with the Directions, Search Nearby, and More links is what I was looking for.

While waiting, I have employed a pretty robust (and cool!) solution, and, yes, it took a lot of digging to figure it out. It uses geolocation and works great in Chrome and IE9, less well on Firefox, and sucks on IE8. But that's beside the point.

So, unless there is a "widget" to produce the white rectangle box, I think I have a workable solution in place now. Still, that would be so much easier and more compatible...

Comment 32 by Raymond Camden posted on 2/10/2012 at 4:58 AM

Google Maps has an API for creating those popups. So you would need to check their docs on how to add the popups. I think - stress think - I did a blog post demo showing it. If not though it's not that difficult.

Comment 33 by Randy Smith posted on 2/10/2012 at 5:17 AM

Thanks - I looked all over for it at the time but to no avail. When I tested the early version of the site, I found a very limiting factor was that not all of the people who tested the site had geolocation capabilities or they chose to turn them off. That means the app is basically worthless.

So, I switched to generating the iFrame code the way Google does so at least most phones would be able to see a map. When I did it this way, that neat little directions link showed up just fine.

Not anywhere near as cool as what I had spent a good 12+ hours writing, but usability was primo as this is targeted for the lcd.

Thanks for your reply!
RLS

Comment 34 by Randy Smith posted on 2/10/2012 at 5:19 AM

Oh - I take that back - I could generate the popups, but the "directions" link was not a widget you could easily insert. I had to write my own "Show Directions", which turned out quite awesome. Unfortunately, functionality beat awesome this time. RLS

Comment 35 by Raymond Camden posted on 2/10/2012 at 5:30 AM

You can test for Geolocation support. If you do that, you can then show/not show the Directions link.

Comment 36 by Randy Smith posted on 2/10/2012 at 6:08 AM

Thanks - yes, I did know that, unfortunately my Java/JavaScript skills are so poor that I would have spent another 6 hours just figuring that out, and I needed to get this out the door. Fortunately, the solution I implemented is perfect for what is needed...this time.

Comment 37 by Misty posted on 1/8/2013 at 10:07 AM

Hi ray, My Situation is here bit different, I need the following items to be searched in the Google Map:

Address,City,State,Zipcode,County,SubDivision, Lat, Lon

I checked all CFC's of yours at riaforge and others but none is providing county and subdivision

Comment 38 by Raymond Camden posted on 1/9/2013 at 1:25 AM

All I can suggest is looking at Google's APIs and see if any support geocoding of county or subdivision. I'd be a bit surprised if subdivision was supported.

Comment 39 by Jose Rico posted on 8/14/2013 at 10:38 PM

What if I need to show in a MAP the available spaces in a new Township? (I'm working for a Real Estate Company in this moment).

Comment 40 by Raymond Camden posted on 8/14/2013 at 10:58 PM

Can you use markers? Or are you trying to do shapes? Google Maps has a shapes API that lets you draw ad hoc shapes for stuff like this.

Comment 41 by Asad posted on 5/24/2014 at 6:16 PM

Hello Raymond
Thanks for nice explanation. I am wondering to know is it possible to specify two or more address here and find out the distance and travel time like we did with google maps ?

Comment 42 by Raymond Camden posted on 5/24/2014 at 6:28 PM

Yes, Google has a Directions API that will do this. I've blogged on it too.

Comment 43 by Asad posted on 5/24/2014 at 6:57 PM

Hello Raymond
I am unable to find your blog on Direction API will you please provide the url here
Thanks

Comment 44 by Raymond Camden posted on 5/25/2014 at 12:51 AM

Go to the search, type directions api. I saw them immediately.

Comment 45 by Marlene Buffa posted on 9/6/2014 at 2:00 AM

Thanks Ray!
Worked like a charm the first try!

Comment 46 by Sameen Seher posted on 3/23/2020 at 12:34 PM

(can any one please guide why it is rendering this way? div height set properly)
https://uploads.disquscdn.c...

Comment 47 (In reply to #46) by Raymond Camden posted on 3/23/2020 at 1:15 PM

Can you share the complete code, even better if it's online where we can run it?