Bing Maps AJAX v7 HeatMap Library

A few months ago, I posted an article demonstrating some work I’d done creating heatmaps of crime data using the Bing Maps v7 AJAX control. At that time, my intention had originally been to package up my heatmap code and put it up on codeplex. However, I’m not sure that I can be bothered now to create a brand new codeplex project for what is essentially a single 6kb 150-line javascript file, so I’ve decided to just upload it here instead. If anybody wants to contribute improvements or additions to the code, please feel free to add them to the comments here and I’ll create new versions as I feel like it.

It’s completely unsupported, comes with no warranties whatsoever, but you’re free to use it in any projects you like. All I ask is that, if you find it helpful, please let me know (commenting on this post will do).

You can download the library itself, some sample data, and a few HTML pages illustrating different sample usage in this zip archive. Note that, since the heatmap is created using a <canvas> element, it is only supported by browsers than support HTML5 (IE9, Firefox 3.5+, Chrome, etc.).

Basic Usage

To add a new heatmap layer to a map, use the syntax as follows:

HeatMapLayer( map, locations );

  • map is the Microsoft.Maps.Map object on which to overlay the heatmap
  • locations is an array of Microsoft.Maps.Location elements

The code archive includes a set of data from Norfolk Police constabulary, which is shown below:

image

Advanced Usage

The constructor method also accepts an optional parameter in which you can specify the radius and intensity of each heat spot, as well as the colour gradient that should be applied. This is demonstrated in the following listing:

HeatMapLayer( map, locations,
{ intensity: 0.25,
radius: 25,
colourgradient: {
0.0: ‘green’,
0.5: ‘yellow’,
1.0: ‘red’
}
});

This specifies that each heat spot should have a radius of 25 pixels, with a central opacity of 0.25. The temperature gradient is such that the hottest areas appear red, the coolest areas are green, with a mid-gradient of yellow. When applied to a set of data showing the location of Morrisons supermarkets in the UK, this creates the following heatmap:

image

Compare this to a heatmap based on the same settings plotting the location of Waitrose stores (for anybody reading this from outside the UK, Waitrose is a posh, southern supermarket!). Pretty effective comparison, no?:

image

This entry was posted in Bing Maps, Spatial and tagged , , . Bookmark the permalink.

20 Responses to Bing Maps AJAX v7 HeatMap Library

  1. Anthony says:

    Unfortunately the link to the zip is giving a 404!

  2. alastaira says:

    Doh! Sorry – I’m a bit of a skydrive newbie… I’ve updated the link so please try again.

  3. Gerry Tsui says:

    The code is rendering the hotspots with a fixed Radius in screen pixel regardless of the zoom level. ( e.g. when zoom all the way out the hotspots will cover the entire country)
    to fix it…
    // Create radial gradient centred on this point
    var radiusInPixel = _options.radius / _map.getMetersPerPixel();
    var grd = ctx.createRadialGradient(x, y, 0, x, y, radiusInPixel);
    //……….
    ctx.fillRect(x – radiusInPixel, y – radiusInPixel, x + radiusInPixel, y + radiusInPixel);

  4. Gerry Tsui says:

    I fix another bug:

    For the 2nd fillRect statement which read:
    ctx.fillRect(x – _options.radius, y – _options.radius, x + _options.radius, y + _options.radius);

    According to http://dev.w3.org/html5/2dcontext/#simple-shapes-rectangles, the function prototype for fillRect is:
    void fillRect(in double x, in double y, in double w, in double h);

    thus, the correct statement should read:
    ctx.fillRect(x – _options.radius, y – _options.radius, 2 * _options.radius, 2 * _options.radius);

    The bug causes artifacts, when the shading extend beyond the bounds of the main canvas.

    Cheers,

  5. Can anyone offer any ideas on how to digesting just over 3 million records into this project? I can’t seem to get more than a few thousand points to load.

    Charlie

    • alastaira says:

      For 3 million records you don’t really want to be doing anything client-side (using a heatmap or plotting as individual points) – you’re better off looking at creating a server-side heatmap, cutting it into tiles and serving these as raster images to the client.

    • Gerry Tsui says:

      Also take a look of node-heatmap on github.

      In a nutshell, you can run the same JavaScript code to a virtual canvas on the server in the super fast NodeJS environment to output a .png.
      If you fully utilize the event driven, parallel IO/execution node environment against a noSQL distributed database( such as CouchDB/MongoDB). the performance will be many folds beter over conventional Rdbms + thread based web server ( PHP, IIS, Python …etc)

  6. travel5w says:

    Charles check out: http://jkebeck.wordpress.com/2008/12/01/creating-heat-maps-with-virtual-earth-and-sql-server-2008/ for creating tiles. If you still want to do the client-side way ask yourself :is there a possibility that some of these records lie on top of each other or within a reasonable distance. Perhaps server-side clustering would be applicable. You can assign a weight to points based on the number of actual locations that they represent and then use this weight in the client-side calculations to determine the intensity of that point (instead of all points having the same intensity).

  7. Loved this code.
    However, when I use it, my map pushpin events do not fire.
    Is there a way to fix that?

  8. Sasha dos Santos says:

    Alastair,
    I’ve been playing around with the code for some time and wondering if there’s a more efficient (aka faster) way to create the canvas as the user pans the map (this can be detected by comparing zoom levels on subsequent viewchangeend events). I was thinking about storing the pixel x and y of the center of the map and then on viewchangeend, if the zoom level has not changed, get the new pixel x and y of the previous center point. Then determine the deltas and use this along with something like

    var imageData = ctx.getImageData(0, 0, _canvas.width, _canvas.height);
    var pix= imageData.data;
    for (var p = 0; p < pix.length; p += 4)
    {
    ctx.putImageData(imageData, x + deltaX, y + deltaY);
    }
    This would remove the necessity of creating the intensity map and colorizing the map, which look like more intensive operations than the code above.
    Because we are dealing with map data, I don't know if getting the deltas is valid.

  9. Gerry Tsui says:

    Sasha,
    if you are using Bing Ajax V7 you can hook up these viewChange events
    latestViewChangeStartHandlerId = MM.Events.addHandler(map, ‘viewchangestart’, map.entities.clear);
    latestViewChangeEndHandlerId = MM.Events.addThrottledHandler(map, ‘viewchangeend’, updateMap, 2000);

    The Biltering technique (http://en.wikipedia.org/wiki/Bit_blit) sounds good, if you can preload all points – for outside the current viewwport. but how far/ large area?

    For large area ( entire USA) I decided to 1) limit scale to high zoom level and 2) AJAX load new point data and rerender. 3)and you can save an Ajax load call for zoom-in operation.

  10. Wei says:

    Thank you very much for this!
    Is there a way to dynamically add points or only update(redraw) part of the heat map?
    I want to add a lot of points on it without redrawing the entire graph.
    Thanks again for the awesome tool!

  11. Geoff says:

    Thanks for this great module. I also found it useful to modify the radius such that it scaled as the map zoomed.

    Further, I found it useful to extend the Location class to add a weighting to each Location, and then use the weighting to modify the radius of each heat spot. If offers one way to visualize a heat map in which each location in the array is weighted by one of the attributes of the locations (for example, a heatmap of sales, weighted by the value of each sale).

  12. Alex Friedman says:

    Hi, thanks for great library.

    Can you provide some guidance on how much effort it would be to achieve something like the link below?
    http://social.msdn.microsoft.com/Forums/en-US/bingmapsajax/thread/dabc1a10-00ef-4cbb-b6e4-f220cce5afae

    Where would you recommend to begin?

  13. mikedotexe says:

    It looks beautiful when I run the code locally, but when I upload it to a server it won’t work. Am I overlooking something simple here?

  14. mikedotexe says:

    ^ scratch that. finally realized AdBlock Plus was blocking the canvas layer when it was on a server. Hope no one else makes that time-consuming mistake.

Leave a comment