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 Object

map.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 marker pointing 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="'>

About This Tutorial
Author: Megan Garrison
Skill Level: Beginner 
 
 
 
Platforms Tested: CFMX
Total Views: 85,572
Submission Date: September 06, 2005
Last Update Date: June 05, 2009
All Tutorials By This Autor: 4
Discuss This Tutorial
  • I've tried samples from the google and those work. I're tried adding db query for map points and that's when I loose the whole map

  • Ps - Ak, I have not worked with this at all since shortly after the tutorial was posted (other things going on) so double check that there have not been changes to the api since the tutorial's post date - you did not say if the sample code generated by google maps when you got your key worked - did it?? ~ megan

  • Try posting this on the google maps discusion groups - also it is hard to try and determine what is going on with out more specifics so when you post to the group, be sure to include details and code samples google maps api group: http://groups.google.com/group/Google-Maps-API hth ~megan

  • I've generated my own key and tried all of the exampleas but all my pages are comming back blank! Anyone knows why?

  • Ok - I just re-read the terms of use at http://www.google.com/apis/maps/terms.html and could find nothing that expressly forbids looking up longitude and latitude on google maps itself, just the general good conduct stuff, no illegal activities, or copyright infringement, and use of the google maps api may be used only for services that are generally accessible to consumers without charge. Also, it is just for showing maps but not for local search or directions or real time route guidance (any of those actual/official services provided by Google). just as a side note, if I (personally) was to use google maps on a commercial site that received a lot of traffic, I would opt to use a service such as geocoder.us or servicesobjects.com's geocoding service http://www.serviceobjects.com/products/geocode_web_service.asp hope this clears things up ~megan

  • I'll look into this further tomorrow and post back what I find out. regards, megan

  • Jeremy - Hi - I thought I had read through everything and would like to see where I might have missed anything that specifically says this is not allowed (or at least I did not see anywhere where they said it was not allowed when I was first reading their info). Also I found this solution via a couple other places using it (getting longitude and latitude from google maps itself - one was providing a service using this method). If you had left your email address I would ask you to show me what/where I missed this. My understanding was that they said they did not provide a geocoding service per se which was why I used the term "unofficial" thanks megan

  • Just to be clear you refer to hacking into Google's geocode results as "unofficial", when in fact it is a violation of their terms of service and should really not be used on a production Web site.

  • Take a look at this screencast where Jon Udell demonstrates an interactive walking tour he created using Google Maps http://weblog.infoworld.com/udell/2005/02/25.html#a1185

  • Ran across this javascript library (TPhoto) that allows you to embed alternate aerial photographs inside your Google Maps without interfering with any clicks on the map. Include it after you include the Google Maps API javascript. Tested by the author in Windows IE6 and Firefox; other combinations that reportedly work: Win Opera 8, Mac Safari 2, Linux Firefox. URL: http://gmaps.tommangan.us/tphoto.html Author also has a label extension (http://gmaps.tommangan.us/tlabel.html) for using small transparent labels instead of Google Maps larger InfoWindows

Advertisement

Sponsored By...
Powered By...