online mapping with_the_google_maps_api
TRANSCRIPT
Online Mapping with Google Maps API v3 Michael Peterson, Chair, International Cartographic Association Commission on
Maps and the Internet University of Nebraska at Omaha
2
Introduction
Introduced in 2005, Google Maps has transformed the online mapping. No longer dependent on a simple and slow server-‐client relationship, Google Maps uses a more interactive, tile-‐based system based on AJAX to present an online map that allows for highly interactive panning and zooming. In 2006, the Google Maps Application Programmer Interface was introduced that facilitated the creation of Map Mashups – the mapping of data from online sites. Map Mashups have had a major impact in how spatial information is communicated. This workshop examines online mapping APIs from Google, Bing and Yahoo. Specific examples are presented using the Google Maps API that involves the mapping of point, line, and area data. Both in-‐code and GeoRSS data will be mapped. All examples use an HTML/JavaScript interface to the Google Maps API. Some familiarity with HTML and basic programming concepts -‐ objects, arrays, loops -‐ is expected.
After a short overview, the workshop will be conducted in a hands-‐on fashion. Participants will connect to the Internet using their own laptops and download a zip file with all of the course materials. A Windows program will be installed to edit the HTML/JavaScript code. Participants will need to have the access privilege on their own laptop to install programs. Most of the workshop will involve understanding how various Google Maps API routines are called and how they are used to make customized maps. Participants will be given a complete hand-‐out and all necessary coding examples.
Mashups
Mashups are an integral part of what is commonly referred to as Web 2.0. Introduced in 2004, Web 2.0 represents a variety of innovative resources, and ways of interacting with, or combining web content. In addition to mashups, Web 2.0 also includes the concept of wikis, such as Wikipedia, blog pages, podcasts, RSS feeds, and AJAX. Social networking sites like MySpace and Facebook are also seen as Web 2.0 applications.
Central to mashups are Application Programming Interfaces (APIs), online libraries of functions that are made available at no cost to website designers. Many different API libraries have been written for the user-‐driven web. APIs are the tools that facilitate the fusion of data and resources from multiple web resources by providing tools to acquire, manipulate and display information from a variety of sources. In a strict sense, a map mashup combines data from one website and displays it with a mapping API. The term has come to be used for any mapping of data using an API, even data supplied by the user. It should not be surprising that maps figure prominently as mashups. There is a great deal of data presented on web pages that has a locational component. The relative ease of overlaying all types of information with online mapping tools has further transformed cartography from a passive to an active enterprise.
3
The advantage of using a major online mapping site is that the maps represent a common and recognizable representation of the world. Overlaying features on top of these maps provides a frame of reference for the map user. A particular advantage for thematic mapping is the ability to spatially reference thematic data. To emphasize patterns, thematic maps have limited the display of spatial reference data such as the location of cities and transportation networks.
This chapter demonstrates the use of the Google Maps API, the most commonly used API for mapping. Other APIs exist for other online mapping, including those from Yahoo and Microsoft, and all are in a continual state of development. Most APIs are designed for use with JavaScript. Before examining mashup procedures with Google maps, it is important to examine programming with JavaScript in more detail.
JavaScript
JavaScript, introduced briefly in the last chapter, is a compact, object-‐based language for developing client-‐side applications. It is not a computer language that makes executable code, like C++ or Java. Rather, the browser interprets JavaScript statements that are embedded in, or referenced from, an HTML page. The JavaScript program is executed when the browser page is opened. This was initially viewed as a problem because it slowed down the execution of the program. Compiled programs execute more quickly. Computers are becoming faster so there is no longer a major advantage to pre-‐compiling computer code.
From a commercial standpoint, the major disadvantage of JavaScript is that the code is open and readable. Anyone can view the JavaScript code by simply choosing Page Source or View Source from the browser. This, combined with the lack of a debugging program and slow processing speeds, has limited the acceptance of the language, although most major websites use some form of JavaScript. The language is ideal for educational purposes because the code is freely accessible and functions can be easily integrated.
The example in Figure 1 defines a simple function in the HEAD section of an HTML document. The function is then called in the BODY of the document. The function square takes one argument, called number, and the function consists of one statement:
return number * number
that indicates it should return the argument of the function multiplied by itself. The return statement specifies the value that is returned by the function.
Code Result
<HEAD> <SCRIPT LANGUAGE="JavaScript"> function square(number) { return number * number } </SCRIPT>
The function returned 25.
4
</HEAD> <BODY> <SCRIPT> document.write("The function returned ", square(5), ".") </SCRIPT> <P> All done. </BODY>
All done.
Figure 1. This function squares the number passed to it by a call to the function.
Rather than embedding the JavaScript in the HTML file, either in the BODY or the HEAD, it is possible to place the JavaScript functions within a separate file. The SRC attribute of the <SCRIPT> tag specifies the external file where the JavaScript code can be found. Figure 2 shows the external file called 7-‐4common.js and how it is referenced in the HEAD part of an HTML document. The external JavaScript file may contain multiple functions but no HTML code.
function square(number) { return number * number } <HEAD> <TITLE>Referencing a file of functions</TITLE> <SCRIPT SRC="7-4common.js"> </SCRIPT> </HEAD> <BODY> <SCRIPT> document.write("The function returned ", square(5), ".") </SCRIPT> <P> All done. </BODY>
Figure 2. A function is placed into an external document, 7-4common.js. The function is then referenced from the HTML file with <SCRIPT SRC=”7.4common.js”>.
Objects Objects are combinations of functions and data all packaged under a single name. Each object has properties, methods, and event handlers. An object named car, for example, would possess properties such as make, model, year, and color. Methods might be attributes like ‘go’ and ‘stop’. An event handler includes pressing a button or moving the mouse over a link. JavaScript incorporates several built-‐in objects. Figure 3 demonstrates the use of the date object.
5
Code Result
<html> <script type="text/javascript"> function Time() { var currentTime = new Date() var hours = currentTime.getHours() var minutes = currentTime.getMinutes() var seconds = currentTime.getSeconds() // call the AddZero function to add a zero in front of numbers that are less than 10 hours = AddZero(hours) minutes = AddZero(minutes) seconds = AddZero(seconds) // write out the time document.write("<b>" + hours + " hours " + minutes + " minutes " + seconds + " seconds </b>") } function AddZero(i) { if (i<10) {i="0" + i} return i } </script> </head> // call the Time function <body onload="Time()"> </body> </html>
19 hours 23 minutes 06 seconds
Figure 3. Calling the built-in Date object to determine the current time.
Calculations JavaScript includes a number of internal functions called Math Objects. Most of these are trigonometric functions that might be used to determine the distance between two points on the surface of the earth, as in Figure 4. Other functions compute numbers like the absolute value or square root.
<script type="text/javascript"> /*
6
* Use Haversine formula to Calculate distance (in km) between two points specified by * latitude/longitude (in numeric degrees) LatLon.distHaversine = function(lat1, lon1, lat2, lon2) { var R = 6371; // earth's mean radius in km var dLat = (lat2-lat1).toRad(); var dLon = (lon2-lon1).toRad(); lat1 = lat1.toRad(), lat2 = lat2.toRad(); var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon/2) * Math.sin(dLon/2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c; return d; }
Figure 4. This function calculates the distance between the two locations.
Google Maps Like other online interactive mapping sites, Google displays maps at multiple scales. These maps are in raster form and have been pre-‐made from an underlying vector database. Google offers 18 maps of the world at different scales varying from approximately 1:85 million to 1:4,800 at the equator. Each of these maps has been tiled into individual squares that are downloaded separately, often from different servers. A typical Google Map might download map tiles from seven or eight different IP addresses, each associated with a different computer that could be located at different Google data centers. A variety of AJAX methods are used to update the map.
The satellite view provided by Google is pieced together from different satellite imagery. In most cases, urban areas are shown with higher resolution data. Security concerns have led to some imagery being intentionally obscured or pixelated, such as with nuclear power plants in the United States (see, for example, Seabrook Station Nuclear Power Plant, in New Hampshire). The power plants are still visible but at a reduced resolution with obvious pixelation.
Maps and imagery in Google Maps have been projected with the Mercator projection. The attributes and limitations of this projection have been well-‐documented, and its distorted depiction of the world has been a major cause for concern among cartographers and geographers. Although the projection preserves angles and can be used with a compass over small areas, it badly distorts area – particularly at extremes in latitude. Greenland is represented as being larger than Africa when in fact Africa is 14 times larger than Greenland. Scale varies continuously from the equator to the polar areas. Changes in scale can be observed in the Google Map display by examining the scale bar for medium scale maps when moving north or south away from the equator. This change in map scale is particularly noticeable at the extreme latitudes. Mathematically speaking, the north and south pole in the Mercator
7
projection are at infinity. Therefore, Google Maps, along with many other online maps that use the Mercator projection, do not show either pole.
Google Maps API The Google Map API consists of a series of map-‐related functions that may be invoked by the user. These functions control the appearance of the map, including the scale, position, and any added information in the form of points, lines or areas. The purpose of the API is to make it possible to incorporate Google Maps on websites, and to overlay information from another source.
Basic Google Map The example in Figure 5 shows the Google Map and JavaScript code for displaying a simple map centered at a specific latitude and longitude. The zoom level, which ranges from 0 to 17, is set to 15. The example in Figure 5, adds both the vertical zoom slider in the upper-‐left corner and the map type control buttons in the upper-‐right corner. Scroll button zooming is also enabled and the map is displayed in hybrid form with a background satellite image.
Determining the latitude/longitude can be done in at least four different ways. With Google Maps, zoom-‐in as far as possible to increase the accuracy of the point and then right-‐mouse click (control-‐click with a Mac) on the point of interest and select “Directions from here” or “Directions to here” from the pop-‐up menu. The latitude and longitude of the point will appear in the Start Address or End Address form at the top of the page. This will only work if the point is not positioned on a street. The latitude / longitude for a point may also be determined using Google Earth, a separate program available from Google. To display the coordinates in the decimal degrees format required for Google Maps, select Tools / Options and click on the decimal degrees option. A utility called LatLongGrabber is available in the code examples. This utility returns latitude and longitude values for points clicked. The fourth approach involves activating a Google Labs feature that displays these values in a tooltip.
<!DOCTYPE html> <html>
<head> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <style type="text/css">
html { height: 100% } body { height: 100%; margin: 0px; padding: 0px } #map_canvas { height: 100% }
</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(41.258531,-96.012599); var myOptions = { zoom: 15, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP }; var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); }
</script> </head>
8
<body onload="initialize()"> <div id="map_canvas" style="width:100%; height:100%"> </div>
</body> </html>
Figure 5. A basic Google map.
Point Maps Google Maps excels at showing the location for points of interest (POI). By default, this point is symbolized with an upside-‐down raindrop symbol (see Figure 6) but a large number of alternative symbols are available, and it is even possible to design your own. The marker may also be made clickable so that text, a picture, or a small video displays within bubble near the symbol. The symbol may also be graduated, increasing in size to show quantitative data by location.
<html> <head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <style type="text/css">
html { height: 100% } body { height: 100%; margin: 0px; padding: 0px } #map_canvas { height: 100% }
</style> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"> </script> <script type="text/javascript">
function initialize() { var myLatlng = new google.maps.LatLng(41.258531,-96.012599); var myOptions = { zoom: 15, center: myLatlng, mapTypeId: google.maps.MapTypeId.HYBRID } var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); var myLatLng = new google.maps.LatLng(41.258531,-96.012599); var beachMarker = new google.maps.Marker({ position: myLatLng, map: map, }); }
</script> </head> <body onload="initialize()">
<div id="map_canvas" style="width:600px; height:300px"> </div>
</body> </html>
9
Figure 6. A single marker on a Google Hybrid map.
10
Clickable Markers
All of the markers defined to this point have been passive – they do not respond to user actions. The advantage of a clickable marker is that they can provide information about the marker. In the example in Figure 7, html formatted text is associated with a variable called “html”. The GEvent.addListener then ties this text to the marker. When the user clicks on the marker, the text is displayed in a pop-‐up bubble. To describe each marker on the map, an array of text strings could be defined and associated with every location.
function initialize() { var myLatlng = new google.maps.LatLng(41.258531,-96.012599); var myOptions = { zoom: 9, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP } var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); var contentString = 'Durham Science Center<br />University of Nebraska at Omaha<br />Cartography and GIS Laboratory' var infowindow = new google.maps.InfoWindow({ content: contentString }); var marker = new google.maps.Marker({ position: myLatlng, map: map, title:"Omaha" }); google.maps.event.addListener(marker, 'click', function() { infowindow.open(map,marker); }); }
Figure 7. Example of a clickable marker. The contentString text variable is defined with HTML formatted text.
11
Mapping Random Points The example in Figure 8 computes the location and maps five random points using the JavaScript random number function Math.random. This function returns values between 0 and 1. Multiplying the result of the random number generator times the difference between the longitude values (longspan) and latitude (latspan)values, respectively, and adding this to the current corner latitude and longitude values gives the location of the random point.
<script type="text/javascript">
var map; function initialize() { var myLatlng = new google.maps.LatLng(41.258531,-96.012599); var myOptions = { zoom: 18, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP } map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); // Add 5 markers to the map at random locations var southWest = new google.maps.LatLng(41.152446,-96.252708); var northEast = new google.maps.LatLng(41.36150, -95.8579); var bounds = new google.maps.LatLngBounds(southWest,northEast); map.fitBounds(bounds); var lngSpan = northEast.lng() - southWest.lng(); var latSpan = northEast.lat() - southWest.lat(); for (var i = 0; i 5; i++) { var location = new google.maps.LatLng(southWest.lat() + latSpan * Math.random(), southWest.lng() + lngSpan * Math.random()); var marker = new google.maps.Marker({ position: location, map: map }); var j = i + 1; marker.setTitle(j.toString()); attachMessage(marker, i); } } // The five markers show the number of the marker when clicked function attachMessage(marker, number) { var message = ["Marker One","Marker Two","Marker Three","Marker Four","Marker Five"]; var infowindow = new google.maps.InfoWindow( { content: message[number], size: new google.maps.Size(50,50) }); google.maps.event.addListener(marker, 'click', function() { infowindow.open(map,marker); }); }
</script>
12
Figure 8. Randomly positioned markers.
13
Mapping Points from an xml file If more than one point is to be mapped, it would be good to store the points in an external file. In the example in Figure 9, the file is formatted in xml and read using the downloadUrl function that is located in an external .js file. In this case, example.xml contains three points defined as latitude/longitude with bubble text formatted in html and a tooltip label that appears when the mouse is positioned over the point.
function initialize() { // create the map var myOptions = { zoom: 8, center: new google.maps.LatLng(43.907787,-79.359741), mapTypeControl: true, mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}, navigationControl: true, mapTypeId: google.maps.MapTypeId.ROADMAP } map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); google.maps.event.addListener(map, 'click', function() { infowindow.close(); }); // Read the data from example.xml downloadUrl("example.xml", function(doc) { var xmlDoc = xmlParse(doc); var markers = xmlDoc.documentElement.getElementsByTagName("marker"); for (var i = 0; i markers.length; i++) { // obtain the attribues of each marker var lat = parseFloat(markers[i].getAttribute("lat")); var lng = parseFloat(markers[i].getAttribute("lng")); var point = new google.maps.LatLng(lat,lng); var html = markers[i].getAttribute("html"); var label = markers[i].getAttribute("label"); // create the marker var marker = createMarker(point,label,html); } // put the assembled side_bar_html contents into the side_bar div document.getElementById("side_bar").innerHTML = side_bar_html; }); }
example.xml <markers>
<marker lat="43.65654" lng="-79.90138" html="Some stuff to display in the<br>First Info Window" label="Marker One"> </marker> <marker lat="43.91892" lng="-78.89231" html="Some stuff to display in the<br>Second Info Window" label="Marker Two"> </marker> <marker lat="43.82589" lng="-79.10040" html="Some stuff to display in the<br>Third Info Window" label="Marker Three"> </marker>
</markers>
14
Figure 9. Displaying multiple markers with a sidebar. The position for each marker along with the associated bubble text and tooltip text is defined in an xml file.
15
Mapping Points through RSS from a KML file RSS is a web format used to publish frequently updated data such as news and other types of frequently updated information. RSS feeds include content and metadata such as the date and author. Publishers benefit by syndicating content automatically. Consumers benefit through timely updates from favored websites. A standardized XML file format allows the information to be published once and viewed by many different programs.
KML, Keyhole Markup Language, is an XML based format for describing two-‐ and three-‐dimensional space. The format specifies features such as places marks, images, polygons, and 3D models. Places are always specified with latitude and longitude. Some KML features may not be viewable with Google Maps.
The google.maps.KmlLayer function reads a KML-‐formatted RSS feed (see Figure 10). The feed is specified with an http address. The address used in this example comes from flickr, an image hosting website. In this case, a user has geocoded a series of photos and has made the feed available for syndication. RSS is an efficient form of data distribution and maps made in this way are usually displayed faster than if read from an XML file, as in the example above.
<script type="text/javascript">
function initialize() { var myLatlng = new google.maps.LatLng(49.496675,-102.65625); var myOptions = { zoom: 4, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP } var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); var georssLayer = new google.maps.KmlLayer('http://api.flickr.com/services/feeds/geo/?g=322338@N20&lang=en-us&format=feed-georss'); georssLayer.setMap(map); }
</script>
Figure 10. Displaying a RSS feed defined in KML format from the flickr website.
16
Mapping RSS Points with Layer Side Info The example in Figure 11 reads an RSS file from Searcharoo.net, a site that provides an open-‐source C#/ACP.NET implementation of a search engine that you can download and use on your website. The “newyork.kml” that they make available is a result of a search for geocoded information, including a picture. A part of the KML file is shown in Figure 10. Clicking on a map maker displays this information in a sidebar div layer on the side of the map.
<script type="text/javascript">
function initialize() { var myLatlng = new google.maps.LatLng(40.65, -73.95); var myOptions = { zoom: 12, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP }; var map = new google.maps.Map( document.getElementById("map_canvas"), myOptions); var nyLayer = new google.maps.KmlLayer( 'http://www.searcharoo.net/SearchKml/newyork.kml', { suppressInfoWindows: true, map: map}); google.maps.event.addListener(nyLayer, 'click', function(kmlEvent) { var text = kmlEvent.featureData.description; showInContentWindow(text); }); function showInContentWindow(text) { var sidediv = document.getElementById('content_window'); sidediv.innerHTML = text; } }
</script> </head> <body onLoad="initialize()">
<div id="map_canvas" style="width:79%; height:100%; float:left"> </div> <div id="content_window" style="width:19%; height:100%; float:left"> </div> </body>
KML File <?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2">
<Document> <Placemark>
<description> <![CDATA[ Cable ties on Brooklyn Bridge <b>newyork </b>brooklyn brooklynbridge <br /> <a href="http://searcharoo.net/searcharoov6/testfiles/brooklynbridge%20(perspective).jpg">
<img src="http://searcharoo.net/searcharoov6/testfiles/brooklynbridge%20(perspective).jpg" width="120" />
</a> <br /> Tags: newyork, brooklyn, brooklynbridge, , manhattan <br /> Size: 121975 <br /> Crawled Date: 3/6/2009 3:31:58 AM <br /> Rank: (1) ]]>
</description> <Style>
<IconStyle> <Icon>
17
<href> http://searcharoo.net/searcharoov6/testfiles/brooklynbridge%20(perspective).jpg
</href> </Icon>
</IconStyle> </Style> <Point>
<extrude> 1
</extrude> <altitudeMode>
relativeToGround </altitudeMode> <coordinates>
-73.9955001666667,40.7050708333333,0 </coordinates>
</Point> </Placemark>
Figure 11. Displaying a RSS feed defined in KML format from the flickr website.
18
Mapping data from Fusion tables Fusion Tables is a free Google service for storing and managing tabular data in the cloud. Data sets up to 100MB can be uploaded and shared with collaborators or made public. Once uploaded, data may be filtered, aggregated, merged, and exported in multiple formats. It is also possible to display the data in charts and maps. Part of a Fusion Table of crime in Chicago is shown in Figure 12. This data is accessed with the Google Maps API using the google.maps.FusionTablesLayer(139529) function, where 139529 is the name of the Fusion Table.
Fusion Tables are managed through the Google Fusion Tables API. This API makes it possible to upload data by row, from a single row to hundreds at a time. Functions are available for data querry based on a subset of the SQL querrying language. Finally, a Fusion Table may be synchronized with an offline respository.
<html> <head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <style type="text/css">
html { height: 100% } body { height: 100%; margin: 0px; padding: 0px } #map_canvas { height: 100% }
</style> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"> </script> <script type="text/javascript">
function initialize() { var chicago = new google.maps.LatLng(41.850033, -87.6500523); map = new google.maps.Map(document.getElementById('map_canvas'), { center: chicago, zoom: 10, mapTypeId: 'roadmap' }); // View this table in a webpage: http://tables.googlelabs.com/DataSource?dsrcid=139529 layer = new google.maps.FusionTablesLayer(139529); layer.setMap(map); }
</script> </head> <body onload="initialize()">
<div id="map_canvas" style="width:600px; height:300px; float:left"> </div>
</body> </html>
19
Figure 12. Displaying a RSS feed defined in KML format from the flickr website.
20
Marker based on Street Address One of the most powerful functions of Google Maps is the geocoding of addresses. Figure 13 shows how a single address is geocoded using the geocoder.geocode function. This location is then shown with a marker on the map.
<script type="text/javascript"> var geocoder; var map; function initialize() { geocoder = new google.maps.Geocoder(); var latlng = new google.maps.LatLng(41.258531,-96.012599); var myOptions = { zoom: 13, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP } map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); } function codeAddress() { var address = document.getElementById("address").value; geocoder.geocode( { 'address': address}, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { map.setCenter(results[0].geometry.location); 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> <input id="address" type="textbox" value="6001 Dodge, Omaha, NE" /> <input type="button" value="Geocode" onclick="codeAddress()" />
</div> <div id="map_canvas" style="height:90%"> </div>
</body>
Figure 13. Placing a marker based on a street address.
21
Custom Markers Markers are small graphic files defined in the PNG graphic file format that are normally 32x32 pixels, but can be of any size. A large number of different icons are available that can be used to denote the location of almost any type of feature, including icons for restaurants, airports, bathrooms, etc. (see Figure 14). A shadow is usually also associated with the icon to provide a 3-‐D appearance, as shown with the restaurant symbol at the bottom of Figure 9. Icons are designed using a pixel-‐based graphic editing program such as Adobe Photoshop.
Figure 14. Alternative Google Maps point symbols.
Graduated Symbols Graduated symbols are used to depict the magnitude of a variable at a point. The symbols are made progressively larger to show increases in quantity, such as population. The size of any type of symbol can be varied, but usually geometric shapes are used like circles or squares.
There are a variety of ways to create symbols of varying sizes with Google Maps. One way would be to define a series of icons with different sizes. Ten icons could be defined from a small 4x4 grid to a size of 256x256 pixels or more. The data to be mapped would then be classified into ten categories and assigned to one of the symbols sizes.
An alternative method is to draw the symbol at a specified size, as with the circle in Figure 15. Here, a google.maps.Circle function is called with a radius of 3000 KM. Multiple circles could be drawn at different locations to represent a distribution such as the population of cities, and the circles could be made proportional to population. It has been shown that circle sizes are perceptually underestimated requiring the map maker to compensate by adjusting the size of the circles upward with an exponent.
22
<html> <head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>
Circle Overlay </title> <style type="text/css">
#map { width: 800px; height: 500px; }
</style> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"> </script> <script type="text/javascript">
/** * Called on the initial page load. */ function init() { var mapCenter = new google.maps.LatLng(0, 0); var map = new google.maps.Map(document.getElementById('map'), { 'zoom': 1, 'center': mapCenter, 'mapTypeId': google.maps.MapTypeId.ROADMAP }); // Create a draggable marker which will later on be binded to a // Circle overlay. var marker = new google.maps.Marker({ map: map, position: new google.maps.LatLng(35, 0), draggable: true, title: 'Drag me!' }); // Add a Circle overlay to the map. var circle = new google.maps.Circle({ map: map, radius: 3000000; // 3000 km
fillColor: "#3da5e1", fillOpacity: 0.5, strokeColor: "#2b546b", strokeWeight: 1
}); // Since Circle and Marker both extend MVCObject, you can bind them // together using MVCObject's bindTo() method. Here, we're binding // the Circle's center to the Marker's position. // http://code.google.com/apis/maps/documentation/v3/reference.html#MVCObject circle.bindTo('center', marker, 'position'); } // Register an event listener to fire when the page finishes loading. google.maps.event.addDomListener(window, 'load', init);
</script> </head> <body>
<h1> Drag the marker to move the circle
</h1> <div id="map"> </div>
</body> </html>
23
Figure 15. Draggable circle drawn on a world map. Defined with a radius of 3000 KM, the circle changes shape because of the use of the Mercator projection.
24
Line Maps The google.maps.Polyline is used to draw lines with Google Maps. In Figure 16, the PolyLine function is used to connect points input by the user. Options include strokeColor, strokeOpacity, and strokeWeight.
<script type="text/javascript"> var poly; var map; function initialize() { var omaha = new google.maps.LatLng(41.258531,-96.012599); var myOptions = { zoom: 9, center: omaha, mapTypeId: google.maps.MapTypeId.ROADMAP }; map = new google.maps.Map(document.getElementById('map_canvas'), myOptions); var polyOptions = { strokeColor: '#000000', strokeOpacity: 1.0, strokeWeight: 3 } poly = new google.maps.Polyline(polyOptions); poly.setMap(map); // Add a listener for the click event google.maps.event.addListener(map, 'click', addLatLng); } /** * Handles click events on a map, and adds a new point to the Polyline. * @param {MouseEvent} mouseEvent */ function addLatLng(event) { var path = poly.getPath(); // Because path is an MVCArray, we can simply append a new coordinate // and it will automatically appear path.push(event.latLng); // Add a new marker at the new plotted point on the polyline. var marker = new google.maps.Marker({ position: event.latLng, title: '#' + path.getLength(), map: map }); }
</script>
25
Figure 16. The polyLine function is used to draw lines on the map to connect points input by the user.
26
Area Maps The final symbol type to be examined here is the area symbol, used to make the choropleth map. The choropleth method uses shadings to indicate the quality or value over an area. A qualitative choropleth map would indicate nominal differences like zoning areas, or soil types. A quantitative choropleth map would display differences in the quantity of a variable as with a map that shows the percent of votes received by a candidate by election precincts. Quantitative choropleth maps are by far the most common of the two types.
The making of a choropleth map with Google Maps would involve the use of the Polygon function (see Figure 17). The function is essentially identical to Polyline except that a fill color and opacity is also defined. As with the Polyline, the function is provided an array of coordinates that outline the area. But, with Polygon, the first and last points are identical, thus closing the polygon.
<script type="text/javascript"> function initialize() { var myLatLng = new google.maps.LatLng(24.886436490787712, -70.2685546875); var myOptions = { zoom: 5, center: myLatLng, mapTypeId: google.maps.MapTypeId.TERRAIN }; var bermudaTriangle; var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); var triangleCoords = [ new google.maps.LatLng(25.774252, -80.190262), new google.maps.LatLng(18.466465, -66.118292), new google.maps.LatLng(32.321384, -64.75737), new google.maps.LatLng(25.774252, -80.190262) ]; // Construct the polygon bermudaTriangle = new google.maps.Polygon({ paths: triangleCoords, strokeColor: "#FF0000", strokeOpacity: 0.8, strokeWeight: 2, fillColor: "#FF0000", fillOpacity: 0.35 }); bermudaTriangle.setMap(map); }
</script>
27
Figure 17. The Google Polygon function is used to draw a polygon. Options include strokeColor, strokeOpacity, strokeWeight, fillColor and fillOpacity.
28
Heat Maps The so-‐called heat map is a product of the mashup era. It is essentially a density map where a higher density of points is given a red color. As the density declines, the color changes to orange and red. Figure 18 shows a density map of beaches in Brazil. Data is provided through a Fusion Table.
</script> <script type="text/javascript">
function initialize() { var brazil = new google.maps.LatLng(-18.771115, -42.758789); map = new google.maps.Map(document.getElementById('map_canvas'), { center: brazil, zoom: 4, mapTypeId: 'roadmap' }); // Table 136705 has beaches along Brazil's coastline // View this table in a webpage: http://tables.googlelabs.com/DataSource?dsrcid=136705 layer = new google.maps.FusionTablesLayer(136705, { heatmap: true }); layer.setMap(map); } </script>
29
Figure 18. A “Heatmap” generated from the density of points defined in a Fusion Table.
Yahoo Maps and Bing Maps Competing with MapQuest, Yahoo! provided an online mapping service that used the older client/server model. The server responded with a user-‐requested map that was embedded within a web page. Soon after the introduction of Google Maps in 2005, Yahoo changed it’s online mapping service to incorporate an AJAX-‐type interface that worked with Flash. By 2006, Yahoo! had released its own API. The Yahoo! Maps API is much the same as Google’s implementation but does not support polygons and requires the use of an electronic key.
In mid-‐2009, Microsoft re-‐labeled its Live Local web mapping service to Bing Maps, a part of the companies search engine services. Bing Maps includes a street map, an aerial view, Bird’s-‐Eye view, StreetSide view, and 3D Maps. The oblique Bird’s Eye view has more detail than Google’s satellite view. In contrast to the Yahoo! Maps API, Bing Maps does support polygons.
Figure 19 compares the code between Yahoo! and Bing maps.
30
Figure 19. Example of code for Yahoo! Maps API and Bing Maps API.
31
Mapstraction
Mapstraction is an open-‐source library that provides a common API for various JavaScript mapping APIs. The purpose is to make it possible to easily switch between the different APIs without having to worry about the unique implementation. The example in Figure 20 shows a Mapstraction implementation that creates a map with six different mapping APIs.
<html> <head>
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAKRwVKGgdK08PzFOkI4mzwBSxwhHJj4F5mVjLsNT2AfMLlpoynxTk5g96WAoVkzIABODCjMST2qhLwg" type="text/javascript"> </script> <script type="text/javascript" src="http://api.maps.yahoo.com/ajaxymap?v=3.0&appid=MapstractionDemo"> </script> <script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6"> </script> <script type="text/javascript" src="http://developer.multimap.com/API/maps/1.2/OA070606486554191"> </script> <script src="http://btilelog.beta.mapquest.com/tilelog/transaction?transaction=script&key=mjtd%7Clu6t210anh%2Crn%3Do5-labwu&itk=true&v=5.3.0_RC5&ipkg=controls1" type="text/javascript"> </script> <script type="text/javascript" src="mapstraction-js/mapstraction.js"> </script> <style type="text/css">
.mapstraction { height: 100%; width: 100%; z-index: 1; } #map_select { bottom:40px; left:25px; position:absolute; background-color:white; padding: 5px; border:2px solid black; z-index: 1000; }
</style> </head> <body>
<div id="google" class="mapstraction"> </div> <div id="multimap" class="mapstraction" style="display:none"></div> <div id="yahoo" class="mapstraction" style="display:none"></div> <div id="microsoft" class="mapstraction" style="display:none"></div> <div id="freearth" class="mapstraction" style="display:none"></div> <div id="mapquest" class="mapstraction" style="display:none"></div> <div id="openstreetmap" class="mapstraction" style="display:none"></div> <div id="mapquest" class="mapstraction" style="display:none;height: 100%; width: 100%;"></div> <script type="text/javascript">
// initialise the map with your choice of API var mapstraction = new Mapstraction('google','google'); // create a lat/lon object var myPoint = new LatLonPoint(38.8971, -77.070857); // display the map centered on a latitude and longitude (Google zoom levels) mapstraction.setCenterAndZoom(myPoint, 13); // create a marker positioned at a lat/lon my_marker = new Marker(myPoint); // add info bubble to the marker var text = "Rock it out at JSConf!"; my_marker.setInfoBubble(text);
32
// display marker mapstraction.addMarker(my_marker);
</script> <div id="map_select">
<form action="get"> <input type="radio" name="api" value="google" CHECKED="1" onClick="mapstraction.swap('google','google')" /> Google<br /> <input type="radio" name="api" value="multimap" onClick="mapstraction.swap('multimap','multimap')" /> MultiMap<br /> <input type="radio" name="api" value="yahoo" onClick="mapstraction.swap('yahoo','yahoo')" /> Yahoo<br /> <input type="radio" name="api" value="microsoft" onClick="mapstraction.swap('microsoft','microsoft')" /> Microsoft<br /> <input type="radio" name="api" value="openstreetmap" onClick="mapstraction.swap('openstreetmap','openstreetmap')" /> OpenStreetMap<br /> <input type="radio" name="api" value="mapquest" onClick="mapstraction.swap('mapquest','mapquest')" /> MapQuest<br />
</form> </div>
</body> </html>
Figure 20. An implementation of Mapstraction, an open-source API that provides a common interface to multiple online mapping sites.