Integrating & Customizing Google Maps Using the Google Maps API
I. Introduction
In case you haven't noticed, developers have been putting Google Maps to some very cool uses. One of my favorites is HousingMaps.com which allows users of the CraigsList database to search and map rental housing by city and price range. FoundCity.Net is described as a social mapping tool for creating a personalized map of users' "life on-the-fly." (browse: Pizza category, click on push pins, then a user name to see what they have "tagged"). Some other examples of ingenious uses are Chicago Crime, which locates exactly where all police reported crimes take place, Florida Sexual Predator, shows where sex offenders live throughout metropolitan areas, SFSurvey, San Francisco Restaurants reviews by local people, Recent Earthquakes charts earthquakes that have taken place across the globe over the past seven days, MyConcertDates.com (Live US Concerts) and Seattle Bus Monster, which, besides showing bus routes with stops and the current location of the bus, also includes traffic conditions and webcams, flags accidents and sports events that effect traffic. These developers and others are able to integrate Google maps like this by making use of the Google Maps API
The Google Maps API lets web developers embed Google Maps in their own web pages instead of just linking to them. Using the API, a developer can add overlays to the map (including markers and polylines) and display shadowed "info windows" just like Google Maps. The Google Maps API is a free beta service, available for any web site as long as the maps are freely accessible to end users. Google does, however, retain the right to put advertising on the map at any time in the future. One other thing you will want to keep in mind is that Google plans to upgrade the API periodically, which means that you might have to update your site to use the new versions of the API. The Maps team have said they will post notification of these updates on Google Code and the Maps API discussion group and will try to give API users a month to make the transition, during which both versions of the API will be available.
II. Preliminaries
So, what do you need to do to get started integrating Google Maps in your own imaginative way? The first thing you need to do is sign up to get a Google Maps API Key. (It's free, but you must have a Google Account to get a Maps API key, and your API key will be connected to your Google Account) After you sign up and get your key, some sample code will be generated for a very basic map. Copy and paste this code into a blank .cfm template. Executing the script will return a simple Palo Alto area map in the vicinity of where Google Headquarters is located. Important Note: Your template MUST reside at the exact directory address you entered when you signed up for a key. If you use, for example, both domain.com and www.domain.com, you will need two keys, one for each address. (i.e. keys are specific to case, domain, subdomain, and directory). Hopefully Google will be taking care of this in future API versions.
III. The Basic Script
First lets take a look at the basic script:
<script src="http://maps.google.com/maps?file=api&v=1&key=YOUR_API_KEY_HERE" type="text/javascript"></script>
This part makes the Google map JavaScript script available for your use. *TIP: I learned while doing research it's a good idea to put this on the BOTTOM of the page before the body close tag but after the last div so any HTML is parsed before the javascript file is called. For this basic tutorial though, we'll just leave it as is.<div id="map" style="width: 400px; height: 300px"></div>
This part sets map dimensions and creates a placeholder for the map. Wherever you place this snippet in the page, whether using tables or css, is where the map will be positioned.var map = new GMap(document.getElementById("map"));
Creates a GMap Objectmap.centerAndZoom(new GPoint(-122.1419, 37.4419), 3);
centers the map according to longitude and latitude coordinates. The second parameter (the 3) determines the visual height or zoom level. 1 displays the lowest (most detailed) view and 16 displays the highest (least detailed) view.IV. Longitude & Latitude
Ok, so you're going to need precise longitude and latitude coordinates in order to build your maps. Where do you get them? According to Google Maps documentation, at this time the Google Maps API doesn't include any official geocoding service needed to convert addresses to latitude/longitude pairs. However, they do provide a Google Search Link to number of free geocoders available online.
Most of these "Free" geocoding services are free for non-commercial use. However, if yours is a commercial application that requires a large number of repeated lookups, geocoder.us offers a Web Service where you can purchase 20,000 lookups for $50. Or, if you are the Do-It-Yourself type, geocoder.us also provides information about the Perl module they use, Geo::Coder::US along with U.S. Census Bureau TIGER/Line free data. You might also want to take a look at "Geocoding With SQL Server"
V. Grabbing Longitude & Latitude From Google Maps Itself
If none of the options in the preceding section meet your needs, then there is a way you can (unofficially) grab longitude and latitude from google maps itself using cfhttp (I bet you were wondering when I was finally going to get the the cf part of this tutorial :D)
Lets say you have your API key and now want to integrate Google Maps into a member-type website that contains an already existing database of addresses of members. You have added your longitude and latitude fields (fld_lng, fld_lat) but need the pertinent data which you noticed is available whenever you look up an address on Google Maps. So you query your database and pull physical address, city and state. This information will need to be put into the form of one continuous string. For the moment we will just cfset the address of Google Headquarters for the following cfhttp example:
<cfset qmap="1600+Amphitheatre+Parkway+Mountain+View+CA">
Next we will use cfhttp to query Google Maps
<cfhttp method="get"
url="http://maps.google.com/maps?q=#qmap#&output=js"
resolveurl="no">
</cfhttp>Notice &output=js - this is important. If you just use http://maps.google.com/maps?q=#qmap# no map info will be returned.
For now go ahead and cfoutput the cfhttp.filecontent, view source and take a look at what is returned. What you see should look something like this. Notice I highlighted a couple of nodes that will give us our latitude/longitude info, <center lat="37.422845" lng="-122.085035" /> and <point lat="37.422845" lng="-122.085035" /> Now all we need is a little regex
Since I am basically regex illiterate and all attempts at learning Regular Expressions have ended up like this, I head straight for CFLIB.org and pick up the midstring UDF which comes in very handy for isolating our longitude and latitude coordinates.
This might be a good place to stop and review code.
<!--- example1.cfm --->
<!--- the address we want to look up --->
<cfset qmap="1600+Amphitheatre+Parkway+Mountain+View+CA">
<!--- use cfhttp to get the info from google maps --->
<cfhttp method="get"
url="http://maps.google.com/maps?q=#qmap#&output=js"
resolveurl="no">
</cfhttp><!--- Bring in our UDF --->
<cfinclude template="MidString.cfm"><!--- Ok lets parse for longitude and latitude --->
<!--- Latitude first --->
<cfset string= cfhttp.filecontent>
<cfset fromstr='<center lat="'>
<cfset tostr='" lng="'>
<cfset mylat = midstring(string,fromstr,tostr)>
<!--- Longitude next --->
<cfset fromstr='" lng="'>
<cfset tostr='"/>'>
<cfset mylng = midstring(string,fromstr,tostr)><!--- Basic Google Map API Script Starts Here --->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Google Maps Example 1</title>
<script src="http://maps.google.com/maps?file=api&v=1&key=YOUR_API_KEY_HERE" type="text/javascript"></script>
</head>
<body>
<div id="map" style="width: 500px; height: 400px"></div>
<script type="text/javascript">
//<![CDATA[
// create the instance of GMap
var map = new GMap(document.getElementById("map"));
map.addControl(new GSmallMapControl());
// Output Longitude and Latitude to center and set initial starting point of the map
map.centerAndZoom(new GPoint(<cfoutput>#mylng#, #mylat#</cfoutput>), 1);
//]]>
</script>
</body>
</html>The code above basically hits Google Maps twice, once to get the longitude and latitude and then once to get the map by connecting to the API. Depending on how busy Google's servers are, this can slow things down if you have to hit it twice every time a user pulls the data for this address. In reality you only need to get the latitude and longitude info from Google once. After you get it, insert it into the database where you will keep it on hand from then on. The code for this might look something like:
<!--- example2.cfm --->
<!--- query db for member data --->
<cfquery name="qry_memberinfo" datasource="#request.dsn#">
select fld_memberID
, fld_membername
, fld_memberavatar
, fld_address
, fld_city
, fld_state
, fld_lng
, fld_lat
from tbl_members
where fld_memberID = <cfqueryparam value="#url.id#" cfsqltype="cf_sql_integer">
</cfquery><!--- set some params for longitude and latitude (mylng & mylat) --->
<cfparam name="mylng" default="#qry_memberinfo.fld_lng#">
<cfparam name="mylat" default="#qry_memberinfo.fld_lat#"><!---
test to see if the vars contain data & if no data, use cfhttp to get it from google maps
--->
<cfif len(trim(mylng)) IS 0 OR len(trim(mylat)) IS 0><!--- the address we want to look up --->
<cfset qmap="#qry_memberinfo.fld_address#+#qry_memberinfo.fld_city#+#qry_memberinfo.fld_state#">
<!--- let's get rid of any spaces first --->
<cfset qmap = replace(qmap, "chr(32)", "+", "ALL")><cfhttp method="get"
url="http://maps.google.com/maps?q=#qmap#&output=js"
resolveurl="no">
</cfhttp><!--- Bring in our UDF --->
<cfinclude template="MidString.cfm"><!--- Ok lets parse for longitude and latitude --->
<!--- Latitude first --->
<cfset string="#cfhttp.filecontent#">
<cfset fromstr='<center lat="'>
<cfset tostr='" lng="'>
<!--- Reset mylat --->
<cfset mylat = midstring(string,fromstr,tostr)>
<!--- Longitude next --->
<cfset fromstr='" lng="'>
<cfset tostr='"/>'>
<!--- Reset mylng --->
<cfset mylng = midstring(string,fromstr,tostr)><!--- Now lets update db, adding the longitude and latitude to this member record --->
<cfquery name="qry_updatecords" datasource="#request.dsn#">
update tbl_members
set fld_lat = '#mylat#'
, fld_lng = '#mylng#'
where fld_memberID = <cfqueryparam value="#qry_memberinfo.memberID#" cfsqltype="cf_sql_integer">
</cfquery><!--- Done! coordinates captured! --->
</cfif><!--- Basic Google Map API Script Starts Here --->
VI. Enhancing the Basic Map
If you tested your code at this point you might be thinking, Well, now we have our basic map, but there is nothing much on it except some little boxes with arrows. It doesn't even have one of those little orange markers pinpointing our address, much less any of the other neat stuff we saw on all those sites we viewed in the introduction.
Adding Controls
This is where the fun part starts; let's start customizing our map. Take a look at the following line in our basic code: map.addControl(new GSmallMapControl()); This line adds zoom & repositioning controls to the top left corner of the map without including the zoom scalebar (view chart) Let's change that to the large pan/zoom control that includes the zoom scalebar and also add the control that lets you toggle between Google map and satellite views<script type="text/javascript">
//<![CDATA[// create the instance of GMap
var map = new GMap(document.getElementById("map"));
// add large Map Control
map.addControl(new GLargeMapControl());
// add map/satellite toggle
map.addControl(new GMapTypeControl());
// set initial starting point of the map
map.centerAndZoom(new GPoint(<cfoutput>#mylng#, #mylat#</cfoutput>), 3);
//]]>
</script>Adding a Marker
Next we'll create an overlay of Google's default markerpointing to our location by creating a new GPoint() object AFTER centerAndZoom (or the map will be malformed). So...
map.centerAndZoom(new GPoint(<cfoutput>#mylng#, #mylat#</cfoutput>), 3);
// create the GPoint object
var point = new GPoint(<cfoutput>#mylng#, #mylat#</cfoutput>);
// create the marker
var marker = new GMarker(point);
// Add the marker as an overlay
map.addOverlay(marker);Information Windows
An information window is basically a bubble containing some kind of content. If you want to add an information window pointing to center coordinates with a simple "Hello world" message, (INSTEAD of a marker) you would do it this way:map.centerAndZoom(new GPoint(<cfoutput>#mylng#, #mylat#</cfoutput>), 3);
map.openInfoWindow(map.getCenterLatLng(), document.createTextNode("Hello world"));Usually, however, information windows are displayed when a user clicks on the corresponding marker. Lets do this and while we are at it, we will add info to the information window from our database query including an image and a clickable link:
map.centerAndZoom(new GPoint(<cfoutput>#mylng#, #mylat#</cfoutput>), 3);
// create the GPoint object
var point = new GPoint(<cfoutput>#mylng#, #mylat#</cfoutput>);
// create the marker
var marker = new GMarker(point);
//show this output in the infowindow when the pointer is clicked
<cfoutput query="qry_memberinfo">
var myhtml = "<img src='images/#fld_memberavatar#' align='left'><b>#fld_membername#</b><br>#fld_address#<br>#fld_city#, #fld_state#<br><a href='mypage.cfm'>Click Me!</a>";
</cfoutput>
// Add the marker as an overlay
map.addOverlay(marker);
GEvent.addListener(marker, 'click', function() {
marker.openInfoWindowHtml(myhtml);
});Multiple Markers
Suppose you want to create a map displaying clickable markers for several member locations, each with it's own info window. How would you do that? Well, you would have to decide how you are going to determine your map.centerAndZoom coordinates for centering the map and also for selecting addresses from your database. Let's say that for now we will just use a zip code, #myzipvar#.<!--- example7.cfm --->
<!--- set the zip code area for default map centering & use cfhttp to get latitude and longitude from Google Maps --->
<cfhttp method="get"
url="http://maps.google.com/maps?q=#myzipvar#&output=js"
resolveurl="no">
</cfhttp>
<!--- Bring in our UDF --->
<cfinclude template="MidString.cfm"><!--- Ok lets parse for longitude and latitude --->
<!--- Latitude first --->
<cfset string = cfhttp.filecontent>
<cfset fromstr='<center lat="'>
All ColdFusion Tutorials By Author: Megan Garrison
- ColdFusion on a Stick
How to Create a Portable "Plug n Play" CF Application
Author: Megan Garrison
Views: 13,053
Posted Date: Friday, March 31, 2006- In Search of Dynamic Dependent Lists
Example of how to dynamically populate a drop-down list from database tables based on a selection in another drop-down list.
Author: Megan Garrison
Views: 26,058
Posted Date: Monday, February 24, 2003- Integrating & Customizing Google Maps Using the Google Maps API
Rather long introduction to using the Google Maps API to incorporate Google Maps into your applications
Author: Megan Garrison
Views: 20,656
Posted Date: Tuesday, September 6, 2005- Simple "Call Me Back!" SMS Alert
Send a Text-Message to Cell Phone or Pager from Your Website
Author: Megan Garrison
Views: 4,432
Posted Date: Thursday, November 15, 2007- Simple Web Page Translation Widget
Make a Simple Web Page Translation Widget Using Google Translate
Author: Megan Garrison
Views: 3,984
Posted Date: Saturday, November 3, 2007