Google Mapping with Convio CMS ToolkitGoogle Maps can be used to create a compelling presentation of your organizations data. In this example, we will follow our ficticious traveler, Marcel, as makes his way around the Bay Area and chronicles his adventures on his CMS powered Web site. For each of Marcel's travel entries, we will capture the following information and use the CMS content types to store and then render the data on a Google Map. Information to capture for this content type:
Here are the steps we'll take to create the content type and then map the data:
Or jump to the finished page to see this mashup in action [See it work]
1) Create the content typeTo do this in Convio CMS, we first create a Travelogue content type: 2) Create the single display templateNext, we create a single display template for a Travelogue item. This is the page which provides the most detail about a single travelogue entry. Which looks like this when published: 3) Create the list display templateNext, we will make a chronological list of Travelogue entries by creating a list display template which repeats the contents based on the number of Travelogue entries. This can be as simple or as fancy as we want.
Which looks like this when published That is nice, but what would really be cool would be to plot all of the Travelogue items on a map. To do that, we need to make a new List Display template that includes the Google Maps API code plus the data representing the various Travelogue entries. 4) Mashup the display template with the Google Maps APITo use the Google Maps API, you need to sign up for a Google Maps API key. You can then use the API by including the following "script" tag in your code:
|
// function createMarker // point: the location of the marker // icon: the icon to use to show the marker // html: the markup for the popup info window (optional) // Returns: the marker // function createMarker(point, html) { var marker = new GMarker(point); // If there is something to show in the popup... if (html != null) { GEvent.addListener(marker, "click", &nbs p; function() { &nbs p; marker.openInfoWindowHtml(html); &nbs p; }); } return marker; } |
Now we can create some markers. Oh wait, no we can't. We don't have any data. Normally in a List Display Template, we render the data with presentation markup; however, since this time we will be using the Google Maps API for the presentation, we just need to render the data in a way that we can easily parse it in our code. We will use the built in browser DOM functions to accomplish that, but first, let's store our data in a structured way:
<div id="mapData" style="display:none"> <t:list> <div> <span>${title}</span> <span>${url}</span> <span>${firstPublicationDate}</span> <span>${location}</span> <span>${latitude}</span> <span>${longitude}</span> <span>${body}</span> </div> </t:list> </div> |
Notice the style we applied to the outer DIV tag. This causes the browser to hide the DIV so the user doesn't see our structured data in the rendered web page.
Now we have some data. We need a function to read the data, convert it into markers and add it to the map:
// Define some "constants" var TITLE = 0; var URL = TITLE + 1; var DATE = URL + 1; var LOCATION = DATE + 1; var LATITUDE = LOCATION + 1; var LONGITUDE = LATITUDE + 1; var BODY = LONGITUDE + 1; // Define a class to represent a Travelogue function Travelogue(data) { var fields = data.getElementsByTagName("SPAN"); this.title = fields[TITLE].innerHTML; this.url = fields[URL].innerHTML; this.pubDate = fields[DATE].innerHTML; this.location = fields[LOCATION].innerHTML; this.latitude = fields[LATITUDE].innerHTML; this.longitude = fields[LONGITUDE].innerHTML; this.body = fields[BODY].innerHTML; this.getTitle = function () { return this.title; } this.getURL = function () { return this.url; } this.getPubDate = function () { return this.pubDate; } this.getLocation = function () { return this.location; } this.getLatitude = function () { return this.latitude; } this.getLongitude = function () { return this.longitude; } this.getBody = function () { return this.body; } } function loadData(map) { // Find the DIV containing the data var dataDiv = document.getElementById("mapData"); if (dataDiv == null) { return; } // Get a list of all of the inner DIVs each of which contains one // data record var records = dataDiv.getElementsByTagName("DIV"); if (records.length == 0) { return; } // Iterate over each record for (var r = 0; r < records.length; r++) { // Get the fields for this record var travelogue = new Travelogue(records[r]); // we need to format some HTML for the popup var html = getInfoWindowHTML(travelogue); // Create a Google Maps point var point = new GLatLng(travelogue.getLatitude(), travelogue.getLongitude()); // create the marker var marker = createMarker(point, html); // add the new marker to the map map.addOverlay(marker); } } |
Now we are getting there! We need to get our code to run when the page is loaded. So first we'll need to update the setUp function to load the data. Then we need to get it to run when the page loads We can accomplish that (in a browser-safe manner) like so:
function setUp() { var map = new GMap2(document.getElementById('mapDiv')); map.addControl(new GLargeMapControl()); map.addControl(new GOverviewMapControl()); map.addControl(new GMapTypeControl()); loadData(map); return map; } if (window.attachEvent) { window.attachEvent("onload", setUp); window.attachEvent("onunload", GUnload); } else { window.addEventListener('load',setUp,false); window.addEventL istener('unload',GUnload,false); } |
Note the additional function registered to the unload event handlers GUnload. This is a Google Maps API call to clean up after you are done using the maps. It releases all the memory allocated to the map display code. Don't forget to include this.
Now we have a dynamic map displaying all of Marcel's travelogue posts in all of their geospatial beauty. We could call it a day and be satisfied with our accomplishments or we could make it even better. Wouldn't it be nice to use a marker icon that better reflected our website's personality? Of course it would be.
Google Map icons consist of an image and a shadow. The shadow is used to create the 3-d effect.
You can use your graphic skills to create your own images. Once you've created them and uploaded them to your website, you can tell Google to use your custom icons:
// Create a new Icon var customIcon = new GIcon(); customIcon.image = 'http://www.oursite.org/assets/maps/icons/image.png'; customIcon.shadow = 'http://www.oursite.org/assets/maps/icons/shadow.png'; // Google needs to be told the image dimensions customIcon.iconSize = new GSize(25,41); customIcon.shadowSize = new GSize(55,41); // This defines the anchor point of the info window w.r.t. the icon customIcon.infoWindowAnchor = new GSize(55,41); // create the marker using our custom marker icon var marker = createMarker(point, customIcon, html); |
If you wanted to use sequenced anchors (like this), you could create an entire set of custom icons (e.g. custom1.png, custom2.png) and then create a new GIcon for each travelogue.