How to build a Maps Mash-up

Maps are cool! Not only do they provide better aerial images, what makes a map even more valuable is to add data to it. This HowTo describes how this can be done and how to overcome the XmlHttpRequest cross-domain restriction.

This post will discuss the following parts needed for the Mash-up:

  • Map API that lets you embed a map into your website
  • Data source
  • Ways to get around cross-domain restriction

There are a couple of choices for embeddable Maps out there. The “oldest” one is Google Maps, but there is also Virtual Earth, and today the new Yahoo! Maps launched! This is really good stuff. Yahoo! offers different ways of working with their Maps.

  • The simple API takes a geoRSS formated XML file and overlays the data on yesterday’s YMaps technology
  • There are three ways to interact with the brand new Flash Maps. One of them is JavaScript, making it really easy to write super slick applications
  • The last one is an AJAX API that works pretty similar to what’s already out there.

The sample is located at http://theurer.cc/maps/y/ and you can have a look at the JavaScript code by viewing the page source. It uses the AJAX API and demonstrates the following:

  • Geocode an address and display on the map
  • Overlay Traffic information like accidents and construction zones
  • Overlay local search information

The data sources used are three REST Web services that Yahoo also recently opened up. They are easy to program against as it is just a URL with parameters that returns XML.

Browsers like Firefox and IE enforce a cross-domain restriction, which does not allow HTTP calls from one domain to another. Since REST works over HTTP and the services are not hosted on the same server as the Maps application, we need to find a way to get around that. There are different ways to do that.

  • Software proxy
  • Apache mod_rewrite
  • Dynamically loading .js files via script tag and pass data instead of JS code.

The easiest approach is to write a proxy that lives on the same server as the application and just pass the Request and Response to and from the web server. This has a slight security risk, but the example shows how you could limit it. For our scenario it works perfectly.

Those were the basics. Let’s look at some code! The full source:

<html>
<head>
  <script type="text/javascript"
src="http://api.maps.yahoo.com/ajaxymap?v=2.0
&appid= dantheurer"></script>
  <style type="text/css">
    #mapbox {
      height: 600px;
      width: 600px;
  } </style>
</head>
<body>
  <div id="mapbox"></div>
  <script type="text/javascript">
    //init map
    var ymap =
    new YMap(document.getElementById('mapbox'));
    //define a point to start at
    var startPoint = new YGeoPoint(37.34,-122.02);
    //center and draw map at given point
    ymap.drawZoomAndCenter(startPoint, 7);
  </script>
</body>
</html>

The appId in the script is included only for tracking purposes. Please replace it with your own. You can get an appid here. Once you have the code working, we can go ahead and add controls to the map.
//init map
var ymap = new YMap(document.getElementById('mapbox'));
//add controls
ymap.addPanControl();
ymap.addZoomLong();

All that and more can be found in the GettingStartedGuide for AJAX. It gets a little more interesting when data sources come into play. For this sample, I demonstrate the easiest way to overcome the cross-domain restriction. A PHP file will serve as a proxy. Yes, this has some security implications but the proxy is limited to a request with a specific (Yahoo!) domain. For the use case of a free Web service, this is “good enough”. This is all that’s needed:

yproxy.php
<?php
  header("Content-type: text/xml\n\n");
  $url = $_SERVER['QUERY_STRING'];
  //strpos allows only calls to specified endpoint
  if ( strpos($url,"http://api.local.yahoo.com/") === 0)
  {
    $ch = curl_init($url);
    curl_exec($ch);
  }
?>

To run the proxy, the PHP Curl extension needs to be enabled.

Now that the proxy is in place we are able to make a REST call to api.local.yahoo.com. I want to follow what happens if the ‘AddLocation’ Button is pressed. The sample has an input box where the user can input an address.

<div class="inputelement">
<button onClick="addGeocode()">
Add location</button> <input id="geoquery"
value="5th Avenue,New York" size="50">
</input> - enter an address</div>

Once the button is pressed, the function addGeocode() gets called. Yes, the name could be better… and what it does is assemble the REST query and call the function that actually calls the proxy.


var query = document.getElementById("geoquery").value;
var uri =
"http://api.local.yahoo.com/MapsService/V1/geocode?
appid=dantheurer&location=" + query;
callWS(uri, "geocode");

The callWS() does an XmlHttpRequest to the proxy with the REST URL as parameter and displays ‘Loading’ while it waits for the proxy to complete the request. The PHP proxy uses CURL to make the actual request, and the callback method parseResult() gets executed once the call has succeeded.

var url = 'yproxy.php?' + encodeURI(target);
xmlhttp.open('GET', url, true);
xmlhttp.onreadystatechange = function() {
  if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
    document.getElementById('result').innerHTML = '';
    parseResult(xmlhttp.responseText, service);
  } else {
  document.getElementById('result').innerHTML =
  "Loading...";
  }
};
xmlhttp.send(null);
}

From here, all that’s left is parsing the XML and adding the markers. In this sample I used the xmlw3cdom.js parser from SourceForge. It’s more than I need, but it makes things really easy. This DOM parser requires the following SAX parser xmlsax.js to deal with the XML object. I will not discuss how to parse the XML, because it’s easier to just look it up in the source file.

The results are used to create a Point and a String for the Smartwindow, which get passed to the createYMarker() method.


var point =
new YGeoPoint(parseFloat(lat),parseFloat(lon));
var smart = "Long: " + lon + "
" + "Lat: " + lat;
var myMarker = createYMarker(point, i, smart);

It creates the Markers on the map.


var marker = new YMarker(point,'id'+number);
marker.addLabel(number);
YEvent.Capture(marker,EventsList.MouseClick, function() { marker.openSmartWindow(msg) });
return marker;

This is a pretty simple example but this can be the foundation for a much more complex mash-ups. Once this part is done, it only gets better.

Keep mashing!

11 Responses to “How to build a Maps Mash-up”

  1. [...] How to Build a Maps Mash-up :: Dan Theurer Discusses putting together a Map API that lets you embed a map into your website, a data source, and ways to get around cross-domain restriction in order to create a mashup of your own. (tags: geocoding maps howto mashups api navigation software) Posted by Daniel Stoddart | Link to this entry [...]

  2. [...] Dan Theurer Today’s Tagline: Web services, technology and random thoughts! « How to build a Maps Mash-up [...]

  3. [...] How to build a Maps Maps are cool! Not only do they provide better aerial images, what makes a map even more valuable is to add data to it. This HowTo describes how this can be done and how to overcome the XmlHttpRequest cross-domain restriction. http://www.theurer.cc/blog/2005/11/03/how-to-build-a-maps-mash-up/ Posted by: mondfish on Dec 18, 05 | 3:15 pm [0] comments (0 views) |  [0] Trackbacks   [0] Pingbacks top [...]

  4. Andrew says:

    I would like to recommend http://www.MapBuilder.net – tool that is used to build and share custom Yahoo and Google mashups.

  5. S.E says:

    Map is great to have on a site. I am wondering the possibility to include a map (300px by 300 px) on my site, which will show a pop up message with hyperlink of breaking news across the world. The news will point to the place of the news on the map. The news pop up will remain at specific time frame and fade away in order to give way for other breaking news on the map.

    Any idea on how to do this in a simplified way?

    Thanks

  6. reyben says:

    Great but can you send me some code to be able to put amap and search box to find easily the location i want to find. Please………………

  7. Dan says:

    Hi S.E

    That is possible if you have the location information from the news story. Often you can find it in the first line of the article. “San Jose, CA – Yesterday ….” or another way you could extract the location information is the Term Extraction API (http://developer.yahoo.com/search/content/V1/termExtraction.html) You can check the results against a location database and once you have the location create a marker on the maps like explained above.

  8. Dan says:

    Hey reyben,

    You can do a view source on http://theurer.cc/maps/y/ copy the code and only use the first input field. You also need to set up the proxy mentioned above and that should do it.

  9. [...] The good news is that Yahoo! upgraded its map service and it looks very decent. The better news is that it is much easier to use the existing API to “mash” the map into your own web site. There are a lot of new terms and technologies, we can start with this nice piece of article: How to build a Maps Mash-up from Dan Theurer. [...]

  10. Hi,

    The tool at http://www.MapBuilder.net is very nice but I would pay close attention to the underlying Google licensing restrictions if your intent is a business application. Yahoo appears to be unrestricted except for the 50,000 hit/day limit.

  11. Thomas Brown says:

    Hi Dan,

    I am looking for a true “find the nearest” mapping solution that would allow me to use the Yahoo maps as a dealer locator. Rather than displaying reconrds on a map in a local view, the user would be able to enter search parameters to include business type, and radial distance from the the search center, to include results. In other words, show me all the sneaker dealers within 25 miles of zip code 85583, that handle Nike.

    Our web portal carries all the needed location data, we just need to have it geocoded then applied to the searches and mapped results.

    Thanks.

Leave a Reply