结合heatmap.js,在Openlayers中如何实现热力图

概述:

本文讲述结合heatmap.js,在Openlayers中如何实现热力图。

 

heatmap.js简介:

Heatmap 是用来呈现一定区域内的统计度量,最常见的网站访问热力图就是以特殊高亮的形式显示访客热衷的页面区域和访客所在的地理区域的图示。Heatmap.js 这个 JavaScript 库可以实现各种动态热力图的网页,帮助您研究和可视化用户的行为。

 

实现效果:

实现代码:

  1. <html>  
  2. <head>  
  3.     <meta charset="UTF-8">  
  4.     <title>heatmap.js OpenLayers Heatmap Layer</title>  
  5.     <link rel="stylesheet" href="../../../plugin/OpenLayers-2.13.1/theme/default/style.css" type="text/css">  
  6.     <style>  
  7.         html, body, #map{  
  8.             padding:0;  
  9.             margin:0;  
  10.             height:100%;  
  11.             width:100%;  
  12.             overflow: hidden;  
  13.         }  
  14.     </style>  
  15.     <script src="../../../plugin/OpenLayers-2.13.1/OpenLayers.js"></script>  
  16.     <script type="text/javascript" src="extend/heatmap.js"></script>  
  17.     <script type="text/javascript" src="extend/heatmap-openlayers.js"></script>  
  18.     <script type="text/javascript">  
  19.         var map, layer, heatmap;  
  20.         function init(){  
  21.             var testData={  
  22.                 max: 5,  
  23.                 data: [  
  24.                     {name:"乌鲁木齐",lat:43.782225,lon:87.576079,count:1},  
  25.                     {name:"拉萨",lat:29.71056,lon:91.163218,count:1},  
  26.                     {name:"西宁",lat:36.593725,lon:101.797439,count:1},  
  27.                     {name:"兰州",lat:36.119175,lon:103.584421,count:2},  
  28.                     {name:"成都",lat:30.714315,lon:104.035634,count:3},  
  29.                     {name:"重庆",lat:29.479073,lon:106.519225,count:4},  
  30.                     {name:"贵阳",lat:26.457486,lon:106.668183,count:2},  
  31.                     {name:"昆明",lat:24.969568,lon:102.726915,count:2},  
  32.                     {name:"银川",lat:38.598593,lon:106.167324,count:2},  
  33.                     {name:"西安",lat:34.276221,lon:108.967213,count:3},  
  34.                     {name:"南宁",lat:22.748502,lon:108.234036,count:3},  
  35.                     {name:"海口",lat:19.97015,lon:110.346274,count:3},  
  36.                     {name:"广州",lat:23.183277,lon:113.226755,count:4},  
  37.                     {name:"长沙",lat:28.170082,lon:112.947996,count:4},  
  38.                     {name:"南昌",lat:28.652529,lon:115.893762,count:4},  
  39.                     {name:"福州",lat:26.070956,lon:119.246798,count:4},  
  40.                     {name:"台北",lat:25.008476,lon:121.503585,count:2},  
  41.                     {name:"杭州",lat:30.330742,lon:120.183062,count:4},  
  42.                     {name:"上海",lat:31.253514,lon:121.449713,count:5},  
  43.                     {name:"武汉",lat:30.579401,lon:114.216652,count:5},  
  44.                     {name:"合肥",lat:31.838495,lon:117.262334,count:3},  
  45.                     {name:"南京",lat:32.085164,lon:118.805714,count:4},  
  46.                     {name:"郑州",lat:34.746419,lon:113.651151,count:4},  
  47.                     {name:"济南",lat:36.608511,lon:117.048354,count:4},  
  48.                     {name:"石家庄",lat:38.033361,lon:114.478253,count:4},  
  49.                     {name:"太原",lat:37.798488,lon:112.483119,count:3},  
  50.                     {name:"呼和浩特",lat:40.895807,lon:111.842856,count:3},  
  51.                     {name:"天津",lat:38.925801,lon:117.351108,count:4},  
  52.                     {name:"沈阳",lat:41.801674,lon:123.29626,count:3},  
  53.                     {name:"长春",lat:43.982041,lon:125.261357,count:4},  
  54.                     {name:"哈尔滨",lat:45.693857,lon:126.567056,count:3},  
  55.                     {name:"北京",lat:39.892297,lon:116.068297,count:5},  
  56.                     {name:"香港",lat:22.428066,lon:114.093184,count:2},  
  57.                     {name:"澳门",lat:22.18471,lon:113.552554,count:1}  
  58.                 ]  
  59.             };  
  60.             var transformedTestData = { max: testData.max , data: [] },  
  61.                     data = testData.data,  
  62.                     datalen = data.length,  
  63.                     nudata = [];  
  64.             // in order to use the OpenLayers Heatmap Layer we have to transform our data into  
  65.             // { max: <max>, data: [{lonlat: <OpenLayers.LonLat>, count: <count>},...]}  
  66.             while(datalen--){  
  67.                 nudata.push({  
  68.                     lonlat: new OpenLayers.LonLat(data[datalen].lon, data[datalen].lat),  
  69.                     count: data[datalen].count  
  70.                 });  
  71.             }  
  72.             transformedTestData.data = nudata;  
  73.             var format = 'image/png';  
  74.             var bounds = new OpenLayers.Bounds(  
  75.                     73.45100463562233, 18.16324718764174,  
  76.                     134.97679764650596, 53.531943152223576  
  77.             );  
  78.             var options = {  
  79.                 controls: [],  
  80.                 maxExtent: bounds,  
  81.                 maxResolution: 0.2403351289487642,  
  82.                 projection: "EPSG:4326",  
  83.                 units: 'degrees'  
  84.             };  
  85.             map = new OpenLayers.Map('map', options);  
  86.             var tiled = new OpenLayers.Layer.WMS(  
  87.                     "Geoserver layers - Tiled",  
  88.                     "http://localhost:8088/geoserver/lzugis/wms",  
  89.                     {  
  90.                         "LAYERS": 'province',  
  91.                         "STYLES": '',  
  92.                         format: format  
  93.                     },  
  94.                     {  
  95.                         buffer: 0,  
  96.                         displayOutsideMaxExtent: true,  
  97.                         isBaseLayer: true,  
  98.                         yx : {'EPSG:4326' : true}  
  99.                     }  
  100.             );  
  101.             OpenLayers.INCHES_PER_UNIT["千米"] = OpenLayers.INCHES_PER_UNIT["km"];  
  102.             OpenLayers.INCHES_PER_UNIT["米"] = OpenLayers.INCHES_PER_UNIT["m"];  
  103.             OpenLayers.INCHES_PER_UNIT["英里"] = OpenLayers.INCHES_PER_UNIT["mi"];  
  104.             OpenLayers.INCHES_PER_UNIT["英寸"] = OpenLayers.INCHES_PER_UNIT["ft"];  
  105.             //比例尺  
  106.             map.addControl(new OpenLayers.Control.ScaleLine({topOutUnits:"千米",topInUnits:"米",bottomOutUnits:"英里",  
  107.                 bottomInUnits:"英寸"  
  108.             }));  
  109.             map.addControl(new OpenLayers.Control.Zoom());  
  110.             map.addControl(new OpenLayers.Control.Navigation());  
  111.             map.addControl(new OpenLayers.Control.OverviewMap());  
  112.   
  113.             // create our heatmap layer  
  114.             heatmap = new OpenLayers.Layer.Heatmap( "Heatmap Layer",  
  115.                     map, tiled,  
  116.                     {  
  117.                         visible: true,  
  118.                         radius:10  
  119.                     },  
  120.                     {  
  121.                         isBaseLayer: false,  
  122.                         opacity: 0.3,  
  123.                         projection: new OpenLayers.Projection("EPSG:4326")  
  124.                     }  
  125.             );  
  126.             map.addLayers([tiled,heatmap]);  
  127.             map.zoomToExtent(bounds);  
  128.             console.log(transformedTestData);  
  129.             heatmap.setDataSet(transformedTestData);  
  130.         }  
  131.     </script>  
  132. </head>  
  133. <body onload="init()">  
  134. <div id="map"></div>  
  135. </body>  
  136. </html>  

 

附件:

heatmap-openlayers.js
[javascript] view plain copy print?
  1. /*  
  2.  * heatmap.js OpenLayers Heatmap Class 
  3.  * 
  4.  * Copyright (c) 2011, Patrick Wied (http://www.patrick-wied.at) 
  5.  * Dual-licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
  6.  * and the Beerware (http://en.wikipedia.org/wiki/Beerware) license. 
  7.  *  
  8.  * Modified on Jun,06 2011 by Antonio Santiago (http://www.acuriousanimal.com) 
  9.  * - Heatmaps as independent map layer. 
  10.  * - Points based on OpenLayers.LonLat. 
  11.  * - Data initialization in constructor. 
  12.  * - Improved 'addDataPoint' to add new lonlat based points. 
  13.  */   
  14. OpenLayers.Layer.Heatmap = OpenLayers.Class(OpenLayers.Layer, {  
  15.     // the heatmap isn't a basic layer by default - you usually want to display the heatmap over another map ;)  
  16.     isBaseLayer: false,  
  17.     heatmap: null,  
  18.     mapLayer: null,  
  19.     // we store the lon lat data, because we have to redraw with new positions on zoomend|moveend  
  20.     tmpData: {},  
  21.         initialize: function(name, map, mLayer, hmoptions, options){  
  22.             var heatdiv = document.createElement("div"),  
  23.                 handler;  
  24.   
  25.             OpenLayers.Layer.prototype.initialize.apply(this, [name, options]);  
  26.   
  27.         heatdiv.style.cssText = "position:absolute;width:"+map.size.w+"px;height:"+map.size.h+"px;";  
  28.         // this will be the heatmaps element  
  29.         this.div.appendChild(heatdiv);  
  30.         // add to our heatmap.js config  
  31.         hmoptions.element = heatdiv;  
  32.         this.mapLayer = mLayer;  
  33.         this.map = map;  
  34.             // create the heatmap with passed heatmap-options  
  35.         this.heatmap = h337.create(hmoptions);  
  36.   
  37.             handler = function(){   
  38.                 if(this.tmpData.max){  
  39.                     this.updateLayer();   
  40.                 }  
  41.             };  
  42.         // on zoomend and moveend we have to move the canvas element and redraw the datapoints with new positions  
  43.         map.events.register("zoomend", this, handler);  
  44.         map.events.register("moveend", this, handler);  
  45.         },  
  46.     updateLayer: function(){  
  47.                 var pixelOffset = this.getPixelOffset(),  
  48.                     el = this.heatmap.get('element');  
  49.                 // if the pixeloffset e.g. for x was positive move the canvas element to the left by setting left:-offset.y px   
  50.                 // otherwise move it the right by setting it a positive value. same for top  
  51.                 el.style.top = ((pixelOffset.y > 0)?('-'+pixelOffset.y):(Math.abs(pixelOffset.y)))+'px';  
  52.                 el.style.left = ((pixelOffset.x > 0)?('-'+pixelOffset.x):(Math.abs(pixelOffset.x)))+'px';  
  53.           
  54.                 this.setDataSet(this.tmpData);  
  55.     },  
  56.         getPixelOffset: function () {  
  57.             var o = this.mapLayer.map.layerContainerOrigin,  
  58.                 o_lonlat = new OpenLayers.LonLat(o.lon, o.lat),  
  59.                 o_pixel = this.mapLayer.getViewPortPxFromLonLat(o_lonlat),  
  60.                 c = this.mapLayer.map.center,  
  61.                 c_lonlat = new OpenLayers.LonLat(c.lon, c.lat),  
  62.                 c_pixel = this.mapLayer.getViewPortPxFromLonLat(c_lonlat);  
  63.   
  64.             return {   
  65.                 x: o_pixel.x - c_pixel.x,  
  66.                 y: o_pixel.y - c_pixel.y   
  67.             };  
  68.   
  69.         },  
  70.     setDataSet: function(obj){  
  71.         var set = {},  
  72.         dataset = obj.data,  
  73.         dlen = dataset.length,  
  74.                 entry, lonlat, pixel;  
  75.   
  76.         set.max = obj.max;  
  77.         set.data = [];  
  78.         // get the pixels for all the lonlat entries  
  79.             while(dlen--){  
  80.                 entry = dataset[dlen],  
  81.                 lonlat = entry.lonlat.clone().transform(this.projection, this.map.getProjectionObject()),  
  82.                 pixel = this.roundPixels(this.getViewPortPxFromLonLat(lonlat));  
  83.                       
  84.                 if(pixel){  
  85.                     set.data.push({x: pixel.x, y: pixel.y, count: entry.count});  
  86.                 }  
  87.             }  
  88.         this.tmpData = obj;  
  89.         this.heatmap.store.setDataSet(set);  
  90.     },  
  91.     // we don't want to have decimal numbers such as xxx.9813212 since they slow canvas performance down + don't look nice  
  92.     roundPixels: function(p){  
  93.         if(p.x < 0 || p.y < 0){  
  94.             return false;  
  95.             }  
  96.           
  97.             p.x = (p.x >> 0);  
  98.         p.y = (p.y >> 0);  
  99.       
  100.             return p;  
  101.     },  
  102.     // same procedure as setDataSet  
  103.     addDataPoint: function(lonlat){  
  104.         var pixel = this.roundPixels(this.mapLayer.getViewPortPxFromLonLat(lonlat)),  
  105.                 entry = {lonlat: lonlat},  
  106.                 args;  
  107.   
  108.             if(arguments.length == 2){  
  109.                 entry.count = arguments[1];  
  110.             }  
  111.   
  112.             this.tmpData.data.push(entry);  
  113.               
  114.             if(pixel){  
  115.                 args = [pixel.x, pixel.y];  
  116.   
  117.         if(arguments.length == 2){  
  118.             args.push(arguments[1]);  
  119.         }  
  120.         this.heatmap.store.addDataPoint.apply(this.heatmap.store, args);  
  121.         }  
  122.   
  123.     },  
  124.     toggle: function(){  
  125.         this.heatmap.toggleDisplay();  
  126.     },  
  127.     destroy: function() {  
  128.         // for now, nothing special to do here.   
  129.         OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);    
  130.     },  
  131.     CLASS_NAME: "OpenLayers.Layer.Heatmap"  
  132. }); 
posted @ 2016-07-18 15:13  韩慧兵  阅读(1518)  评论(0编辑  收藏  举报