Technical Overview: Mapstraction

Mapstraction is a JavaScript toolkit that provides an common API to eleven different mapping providers. This allows a developer to create an application that can be easily switched between different base map providers. This could be at development time (eg. if a provider introduces better data) or at runtime (eg. according to region or the whim of the end user).

Mapstraction introduces a layer of abstraction between the developer and the various map provider APIs. This allows the developer to write the application only once (for the abstration layer) and support all of the APIs simultaneously. It also allows the map provider to be chosen at runtime – eg. by region according to data coverage, or the end user’s personal choice.

The Mapstraction project is under continuous development, with progress recorded in a roadmap and a feature matrix. Despite the appearance of being partially developed, Mapstraction already supports eleven “providers”:

  • FreeEarth
  • Google
  • Map24
  • MapQuest
  • Microsoft Bing Maps (nee Virtual Earth)
  • MultiMap – both the commercial and OpenAPI interfaces
  • OpenLayers
  • OpenSpace  (British Ordnance Survey)
  • OpenStreetMap
  • ViaMichelin
  • Yahoo

 

Note that not all of these are data providers as such. For example, OpenLayers is a popular JavaScript toolkit. Similarly, OpenStreetMap is a data source and not a JavaScript API.

Supported features currently include: map size/zoom/pan, add/remove controls, add/remove/declutter markers, add/remove polylines, image overlays, JSON, tile layers, and various marker & polyline attributes (icons, text, color, etc).

Mapstraction has an interactive API “sandbox”. This is similar to the increasingly popular “interactive SDKs” that are often included in online documentation, but it also allows the reader to edit the code. The interactive API “sandbox” can be found at http://mapstraction.appspot.com/ .

So how easy is it switch between different map providers ‘on the fly’? Very easy as it turns out. The following example (from the interactive API sandbox) implements a set of radio buttons allowing the user to change map providers:

<!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" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
  <title>Mapstraction API Sample</title>
  <script src="http://maps.google.com/maps?file=api&v=2&key=INSERT_KEY_HERE"></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   src="http://btilelog.beta.mapquest.com/tilelog/transaction?transaction=script&key=INSERT_KEY_HERE&itk=true&v=5.3.0_RC5&ipkg=controls1" type="text/javascript"></script>
  <script type="text/javascript" charset="utf-8" src="http://mapstraction.com/mapstraction-js/mapstraction.js"></script>
  <script type="text/javascript">

  var mapstraction;
  function initialize() {
        mapstraction = new Mapstraction('google','google');
        var myPoint = new LatLonPoint(38.8971, -77.070857);
        mapstraction.setCenterAndZoom(myPoint, 13);
        my_marker = new Marker(myPoint);
        var text = "Swapping with Mapstraction";
        my_marker.setInfoBubble(text);
        mapstraction.addMarker(my_marker);
      
  }

  </script>
  <style type="text/css" media="screen">
  .mapstraction {
    height: 300px;
    width: 100%;
    z-index: 1;
  }

  </style>
</head>
<body onload="initialize()" style="font-family: Arial;border: 0 none;">
  <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 style="margin-left: 150px; height: 100%; width: 300px;"><div id="mapquest" class="mapstraction" style="display:none;height: 100%; width: 100%;"></div></div>
  <form action="get">
    <input type="radio" name="api" value="google" CHECKED onClick="mapstraction.swap('google','google')"> Google<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>    
</body>
</html>

Note that the Mapstraction code only has two parts. First there is the initialize() callback function which creates the map. The second part is in the radio button HTML. Each of the onclick handlers simply calls the mapstraction.swap() method to swap the base map provider. Here are the results:

Mapstraction sample image

Adding pushpins and other features is just as simple. The following code adds a customized marker (pushpin) with data:

mapstraction.addMarkerWithData (
  new Marker( new LatLonPoint(47.4004,153.1435)),
       {
         infoBubble : "Advanced Marker",
         label : "tooltip",
         date : "new Date()",
         marker : 4,
         iconShadow: "http://mapufacture.com/images/providers/blank.png",
          iconShadowSize : [0,0],
         icon : "http://assets1.mapufacture.com/images/markers/usgs_marker.png",
         iconSize : [20,20],
         draggable : false,
         hover : true
       }
  );

So overall, Mapstraction shows a lot of promise and could be a very useful toolkit for the future. Abstraction could help to make it easier to provide rich map applications that use the best map providers for the day, region, application, and/or user in question.

The biggest potential problem with an API that implements an abstraction layer that hides multiple underlying interfaces, is that the calling application will tend to default to the lowest common denominator. A good example of this in the PC world is that of the ODBC database interface. This is potentially very powerful, but in the real world it is difficult and cumbersome to use the most sophisticated features of the API effectively. This is because there is no guarantee that the features are available without a complex set of capability queries. In addition, alternative code has to be provided for cases where the features are missing. In effect, you end up writing your own code to “de-abstract” the API. Ie. it is often easier to write directly to the underlying APIs in question. The resulting code is invariable more efficient as well.

Leave a Reply