Implementation of heat map in Openlayers
Overview:
This article describes how to implement heat map in Openlayers with heatmap. js.
Heatmap. js introduction:
Heatmap is used to display statistical measurements within a certain area. The most common website access heat map is to display the visitor's favorite page area and geographical area in a special highlighted form. Heatmap. js is a JavaScript library that enables a variety of dynamic Heatmap pages to help you study and visualize user behavior.
Effect:
Implementation Code:
<Script src = ".. /.. /.. /plugin/OpenLayers-2.13.1/OpenLayers. js "> </script> <script type =" text/javascript "src =" extend/heatmap. js "> </script> <script type =" text/javascript "src =" extend/heatmap-openlayers.js "> </script> <script type =" text/javascript "> var map, layer, heatmap; function init () {var testData = {max: 5, data: [{name: "Urumqi", lat: 43.782225, lon: 87.576079, count: 1 }, {name: "Lhasa", lat: 29.71056, lon: 91.163218, count: 1 },{ name: "Xining", lat: 36.593725, lon: 101.797439, count: 1 }, {name: "Lanzhou", lat: 36.119175, lon: 103.584421, count: 2}, {name: "Chengdu", lat: 30.714315, lon: 104.035634, count: 3 }, {name: "Chongqing", lat: 29.479073, lon: 106.519225, count: 4}, {name: "Guiyang", lat: 26.457486, lon: 106.668183, count: 2 }, {name: "Kunming", lat: 24.969568, lon: 102.726915, count: 2 },{ name: "Yinchuan", lat: 38.598593, lon: 106.167324, count: 2 }, {name: "Xi'an", lat: 34.276221, lon: 108.967213, count: 3 },{ name: "Nanning", lat: 22.748502, lon: 108.234036, count: 3 }, {name: "Haikou", lat: 19.97015, lon: 110.346274, count: 3 },{ name: "Guangzhou", lat: 23.183277, lon: 113.226755, count: 4 }, {name: "Changsha", lat: 28.170082, lon: 112.947996, count: 4 },{ name: "Nanchang", lat: 28.652529, lon: 115.893762, count: 4 }, {name: "Fuzhou", lat: 26.070956, lon: 119.246798, count: 4 },{ name: "Taipei", lat: 25.008476, lon: 121.503585, count: 2 }, {name: "Hangzhou", lat: 30.330742, lon: 120.183062, count: 4}, {name: "Shanghai", lat: 31.253514, lon: 121.449713, count: 5 }, {name: "Wuhan", lat: 30.579401, lon: 114.216652, count: 5 },{ name: "Hefei", lat: 31.838495, lon: 117.262334, count: 3 }, {name: "Nanjing", lat: 32.085164, lon: 118.805714, count: 4 },{ name: "Zhengzhou", lat: 34.746419, lon: 113.651151, count: 4 }, {name: "Jinan", lat: 36.608511, lon: 117.048354, count: 4 },{ name: "Shijiazhuang", lat: 38.033361, lon: 114.478253, count: 4 }, {name: "Taiyuan", lat: 37.798488, lon: 112.483119, count: 3 },{ name: "Hohhot", lat: 40.895807, lon: 111.842856, count: 3 }, {name: "Tianjin", lat: 38.925801, lon: 117.351108, count: 4}, {name: "Shenyang", lat: 41.801674, lon: 123.29626, count: 3 }, {name: "Changchun", lat: 43.982041, lon: 125.261357, count: 4}, {name: "Harbin", lat: 45.693857, lon: 126.567056, count: 3 }, {name: "Beijing", lat: 39.892297, lon: 116.068297, count: 5 },{ name: "Hong Kong", lat: 22.428066, lon: 114.093184, count: 2 }, {name: "Macao", lat: 22.18471, lon: 113.552554, count: 1}]}; var transformedTestData = {max: testData. max, data: []}, data = testData. data, datalen = data. length, nudata = []; // in order to use the OpenLayers Heatmap Layer we have to transform our data into // {max: , Data: [{lonlat: , Count: },...]} While (datalen --) {nudata. push ({lonlat: new OpenLayers. lonLat (data [datalen]. lon, data [datalen]. lat), count: data [datalen]. count});} transformedTestData. data = nudata; var format = 'image/png '; var bounds = new OpenLayers. bounds (73.45100463562233, 18.16324718764174, 134.97679764650596, 53.531943152223576); var options = {controls: [], maxExtent: bounds, maxResolution: 0.2403351289487642, projection: "EPSG: 4326", units: 'grees'}; map = new OpenLayers. map ('map', options); var tiled = new OpenLayers. layer. WMS ("Geoserver layers-Tiled", "http: // localhost: 8088/geoserver/lzugis/wms", {"LAYERS": 'province ', "STYLES ": '', format: format}, {buffer: 0, displayOutsideMaxExtent: true, isBaseLayer: true, yx: {'epsg: 4326 ': true}); OpenLayers. INCHES_PER_UNIT ["km"] = OpenLayers. INCHES_PER_UNIT ["km"]; OpenLayers. INCHES_PER_UNIT ["meters"] = OpenLayers. INCHES_PER_UNIT ["m"]; OpenLayers. INCHES_PER_UNIT ["Miles"] = OpenLayers. INCHES_PER_UNIT ["mi"]; OpenLayers. INCHES_PER_UNIT ["Inch"] = OpenLayers. INCHES_PER_UNIT ["ft"]; // scale map. addControl (new OpenLayers. control. scaleLine ({topOutUnits: "km", topInUnits: "meters", bottomOutUnits: "Miles", bottomInUnits: "inches"}); map. addControl (new OpenLayers. control. zoom (); map. addControl (new OpenLayers. control. navigation (); map. addControl (new OpenLayers. control. overviewMap (); // create our heatmap layerheatmap = new OpenLayers. layer. heatmap ("Heatmap Layer", map, tiled, {visible: true, radius: 10}, {isBaseLayer: false, opacity: 0.3, projection: new OpenLayers. projection ("EPSG: 4326")}); map. addLayers ([tiled, heatmap]); map. zoomToExtent (bounds); console. log (transformedTestData); heatmap. setDataSet (transformedTestData);} </script>
Attachment:
heatmap-openlayers.js
/* * heatmap.js OpenLayers Heatmap Class * * Copyright (c) 2011, Patrick Wied (http://www.patrick-wied.at) * Dual-licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) * and the Beerware (http://en.wikipedia.org/wiki/Beerware) license. * * Modified on Jun,06 2011 by Antonio Santiago (http://www.acuriousanimal.com) * - Heatmaps as independent map layer. * - Points based on OpenLayers.LonLat. * - Data initialization in constructor. * - Improved 'addDataPoint' to add new lonlat based points. */ OpenLayers.Layer.Heatmap = OpenLayers.Class(OpenLayers.Layer, {// the heatmap isn't a basic layer by default - you usually want to display the heatmap over another map ;)isBaseLayer: false,heatmap: null,mapLayer: null,// we store the lon lat data, because we have to redraw with new positions on zoomend|moveendtmpData: {}, initialize: function(name, map, mLayer, hmoptions, options){ var heatdiv = document.createElement("div"), handler; OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); heatdiv.style.cssText = "position:absolute;width:"+map.size.w+"px;height:"+map.size.h+"px;"; // this will be the heatmaps element this.div.appendChild(heatdiv); // add to our heatmap.js config hmoptions.element = heatdiv; this.mapLayer = mLayer; this.map = map; // create the heatmap with passed heatmap-options this.heatmap = h337.create(hmoptions); handler = function(){ if(this.tmpData.max){ this.updateLayer(); } }; // on zoomend and moveend we have to move the canvas element and redraw the datapoints with new positions map.events.register("zoomend", this, handler); map.events.register("moveend", this, handler); },updateLayer: function(){ var pixelOffset = this.getPixelOffset(), el = this.heatmap.get('element'); // if the pixeloffset e.g. for x was positive move the canvas element to the left by setting left:-offset.y px // otherwise move it the right by setting it a positive value. same for top el.style.top = ((pixelOffset.y > 0)?('-'+pixelOffset.y):(Math.abs(pixelOffset.y)))+'px'; el.style.left = ((pixelOffset.x > 0)?('-'+pixelOffset.x):(Math.abs(pixelOffset.x)))+'px'; this.setDataSet(this.tmpData);}, getPixelOffset: function () { var o = this.mapLayer.map.layerContainerOrigin, o_lonlat = new OpenLayers.LonLat(o.lon, o.lat), o_pixel = this.mapLayer.getViewPortPxFromLonLat(o_lonlat), c = this.mapLayer.map.center, c_lonlat = new OpenLayers.LonLat(c.lon, c.lat), c_pixel = this.mapLayer.getViewPortPxFromLonLat(c_lonlat); return { x: o_pixel.x - c_pixel.x, y: o_pixel.y - c_pixel.y }; },setDataSet: function(obj){ var set = {},dataset = obj.data,dlen = dataset.length, entry, lonlat, pixel;set.max = obj.max;set.data = [];// get the pixels for all the lonlat entries while(dlen--){ entry = dataset[dlen], lonlat = entry.lonlat.clone().transform(this.projection, this.map.getProjectionObject()), pixel = this.roundPixels(this.getViewPortPxFromLonLat(lonlat)); if(pixel){ set.data.push({x: pixel.x, y: pixel.y, count: entry.count}); } } this.tmpData = obj; this.heatmap.store.setDataSet(set);},// we don't want to have decimal numbers such as xxx.9813212 since they slow canvas performance down + don't look niceroundPixels: function(p){ if(p.x < 0 || p.y < 0){ return false; } p.x = (p.x >> 0); p.y = (p.y >> 0); return p;},// same procedure as setDataSetaddDataPoint: function(lonlat){ var pixel = this.roundPixels(this.mapLayer.getViewPortPxFromLonLat(lonlat)), entry = {lonlat: lonlat}, args; if(arguments.length == 2){ entry.count = arguments[1]; } this.tmpData.data.push(entry); if(pixel){ args = [pixel.x, pixel.y];if(arguments.length == 2){ args.push(arguments[1]);}this.heatmap.store.addDataPoint.apply(this.heatmap.store, args); }},toggle: function(){this.heatmap.toggleDisplay();},destroy: function() { // for now, nothing special to do here. OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments); },CLASS_NAME: "OpenLayers.Layer.Heatmap"});