5 ways to make your web mapping fly!

map paper planeOver the past four years here at Earthware we have encountered a number of performance challenges when creating mapping applications on the web. We thought it might be helpful to bring together the 5 most common issues we’ve encountered, both when helping other developers or in some of our older mapping projects.

It’s unfair to call these mistakes, rather they are missed opportunities to make your mapping really fly. They are not exclusively focused on specific mapping API’s or web programming languages / frameworks so they should be applicable to the majority of web mapping applications with a little translation.

So in no particular order:

1. How accurate do you really need to be?

We often come across systems or code samples that both store, but more importantly transfer their position data (usually pairs of lat/lon) to very high levels of decimal places (often 13 or more decimal places). Did you know that 8 decimal places of accuracy is a real world value of 1.11 millimetre (at worst when on the equator). How many systems have you worked on that require you to map to 1.11 millimetre accuracy?

So assuming that for most of us meter accuracy is plenty enough we can reduce our values to only use 5 decimal places (1.11 metre accuracy). When transferring either points, or more importantly polygon data reducing your data from 13 to 5 decimal places is likely to decrease the amount of data you are transferring by at least half.

Typical speed improvement: 50%!

2. Load small, load often

Many mapping applications allow the user to drill into the detail of the data shown on the map. In the majority of cases the user does not require the full details of every single piece of data so why bother loading them all?

Typically in the mapping applications we encounter the initial view a user is presented with has a number of pushpins / polygons maybe with a text label and or an icon representing the ‘type’ of data shown (like a hotel, house, pipe etc). So the data we need to initially load for each point is a title, latitude, longitude, type and unique id. We don’t need to load all the description, photos, links or other data that will not be shown until the user clicks the icon/polygon.

At Earthware, the way we normally handle this is to have two services, one that returns the initial map data that matches our query, and one that returns the full details for a single selected entity. You can code your map so that it makes a call to the “full details” service when a user clicks a map entity and in our experience returning the data for a single entity is usually so quick the user doesn’t even notice the slight pause.

To see an example of this service architecture using asp.net and Bing Maps see http://bingmaps.codeplex.com/wikipage?title=Getting%20Started%20in%20Web%20Services&referringTitle=Home

Typical initial map load improvement: > 500%

3. Don’t repeat yourself

Often when helping developers improve their JavaScript map performance we come across an approach to loading the map data that we don’t recommend except in the most simplistic applications. That approach is to generate the JavaScript code on the web server that is used to create entities on the map and to pass this chunk of JavaScript back to the client and execute it there. For example, we see a service return the following JavaScript:

var pin = new Microsoft.Maps.Pushpin(52.011,-0.221, {text: '1'});
map.entities.push(pin);
pin = new Microsoft.Maps.Pushpin(53.011,-0.121, {text: '2'});
map.entities.push(pin);
pin = new Microsoft.Maps.Pushpin(51.011,-0.251, {text: '3'});
map.entities.push(pin);
pin = new Microsoft.Maps.Pushpin(50.011,-0.321, {text: '4'});
map.entities.push(pin);
pin = new Microsoft.Maps.Pushpin(54.011,-0.143, {text: '5'});
map.entities.push(pin);
pin = new Microsoft.Maps.Pushpin(55.011,-0.0123, {text: '6'});
map.entities.push(pin);

This approach seems to be popular with developers because it’s quick and simple to achieve. However, the downside is that you are constantly repeating the same long text phrases and transferring all these repeats to your user, thus slowing down their mapping experience to make it easier for you to code. This data could be sent in a simple data structure, like JSON, and with some simple code looped through and added to the map. The same data above in JSON would look like:

{points:{point:[{title:1,lat:52.021,lon:-0.211},
  {title:2,lat:53.011,lon:-0.121},
  {title:3,lat:51.011,lon:-0.251},
  {title:4,lat:50.011,lon:-0.321},
  {title:5,lat:54.011,lon:-0.143},
  {title:6,lat:55.011,lon:-0.0123}

]}}

To see an example of this data transfer architecture using Asp.net, JSON and Bing Maps see http://bingmaps.codeplex.com/wikipage?title=Getting%20Started%20in%20Web%20Services&referringTitle=Home

Typical map data load improvement: > 100%

4. Some data you just can’t load fast enough

As we have recently blogged the latest Bing Maps AJAX API is now even faster at showing pushpins on a map, but there is still a limit especially when you are working with older browsers. If your data consists of thousands of entities then it won’t take long before you either cannot transfer the data fast enough or the performance of your map is too slow.

So what can you do? Your users still need to be able to search all the data so you cannot just remove some. The most common solution to this problem is ‘clustering’ of map entities. This is where you group together nearby or overlapping entities and only show individual entities once the user has zoomed in. This can be achieved either using client side code (see http://rbrundritt.wordpress.com/2011/03/02/client-side-clustering-in-v7/) or on the server side before you transfer the data to the client (see http://www.viawindowslive.com/Articles/VirtualEarth/ClusteringVirtualEarthwithMSAJAXandC.aspx). The advantage of doing this on the server side is that you do not have to transfer the data for each individual entity but instead can just transfer the data required to show the ‘clustered’ entity.

There are other approaches to this problem including generating rasterised image tiles of your data and only showing interactive map elements once the user has zoomed in. This works just as well for pushpins as it does polygons. A good example of this ‘hybrid’ approach is the open source ajax map data connector project on codeplex: http://ajaxmapdataconnector.codeplex.com/

5. Transferring data as plain text is soooo slooowwwww

We have already discussed ways of optimising the data you send your clients (in 3.) above but that approach still ends up transmitting plain text data to your clients. There are much better binary formats you could transfer the data in that would massively reduce the size of your transfers.

The first and easiest of these is to use a compression format called Gzip that is seamlessly built into all modern web browsers and plugins (Flash and Silverlight). If on your web service you compress all your map data using Gzip your clients browser will be able to atomically decompress the data ready for you code to use without you having to change you client side code at all. Gzip compression is usually very simple to enable on your web service (see these links for apache, iis6 and iis7).

This approach doesn’t just apply to data transfer or mapping and (if you are not already) you should look at compressing other ‘static’ files like your JavaScript and css.

If you are using Silverlight to load data from WCF services then an even better solution is to use the built in binary http protocol.

There is usually a slight CPU cost to compressing the data but on a modern processor this is minimal and well worth the decrease in data transfer sizes.

Typical map data load improvement: > 50%

In Summary

Hopefully some or all of these issues might help you make a real, measurable difference to your applications performance and many of them are quick and simple to achieve. We would love to hear your real world performance improvements if you do use any of these tips so please feel free to share them in the comments section below.