结合heatmap.js,在Openlayers中如何实现热力图
概述:
本文讲述结合heatmap.js,在Openlayers中如何实现热力图。
heatmap.js简介:
Heatmap 是用来呈现一定区域内的统计度量,最常见的网站访问热力图就是以特殊高亮的形式显示访客热衷的页面区域和访客所在的地理区域的图示。Heatmap.js 这个 JavaScript 库可以实现各种动态热力图的网页,帮助您研究和可视化用户的行为。
实现效果:
实现代码:
- <html>
- <head>
- <meta charset="UTF-8">
- <title>heatmap.js OpenLayers Heatmap Layer</title>
- <link rel="stylesheet" href="../../../plugin/OpenLayers-2.13.1/theme/default/style.css" type="text/css">
- <style>
- html, body, #map{
- padding:0;
- margin:0;
- height:100%;
- width:100%;
- overflow: hidden;
- }
- </style>
- <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:"乌鲁木齐",lat:43.782225,lon:87.576079,count:1},
- {name:"拉萨",lat:29.71056,lon:91.163218,count:1},
- {name:"西宁",lat:36.593725,lon:101.797439,count:1},
- {name:"兰州",lat:36.119175,lon:103.584421,count:2},
- {name:"成都",lat:30.714315,lon:104.035634,count:3},
- {name:"重庆",lat:29.479073,lon:106.519225,count:4},
- {name:"贵阳",lat:26.457486,lon:106.668183,count:2},
- {name:"昆明",lat:24.969568,lon:102.726915,count:2},
- {name:"银川",lat:38.598593,lon:106.167324,count:2},
- {name:"西安",lat:34.276221,lon:108.967213,count:3},
- {name:"南宁",lat:22.748502,lon:108.234036,count:3},
- {name:"海口",lat:19.97015,lon:110.346274,count:3},
- {name:"广州",lat:23.183277,lon:113.226755,count:4},
- {name:"长沙",lat:28.170082,lon:112.947996,count:4},
- {name:"南昌",lat:28.652529,lon:115.893762,count:4},
- {name:"福州",lat:26.070956,lon:119.246798,count:4},
- {name:"台北",lat:25.008476,lon:121.503585,count:2},
- {name:"杭州",lat:30.330742,lon:120.183062,count:4},
- {name:"上海",lat:31.253514,lon:121.449713,count:5},
- {name:"武汉",lat:30.579401,lon:114.216652,count:5},
- {name:"合肥",lat:31.838495,lon:117.262334,count:3},
- {name:"南京",lat:32.085164,lon:118.805714,count:4},
- {name:"郑州",lat:34.746419,lon:113.651151,count:4},
- {name:"济南",lat:36.608511,lon:117.048354,count:4},
- {name:"石家庄",lat:38.033361,lon:114.478253,count:4},
- {name:"太原",lat:37.798488,lon:112.483119,count:3},
- {name:"呼和浩特",lat:40.895807,lon:111.842856,count:3},
- {name:"天津",lat:38.925801,lon:117.351108,count:4},
- {name:"沈阳",lat:41.801674,lon:123.29626,count:3},
- {name:"长春",lat:43.982041,lon:125.261357,count:4},
- {name:"哈尔滨",lat:45.693857,lon:126.567056,count:3},
- {name:"北京",lat:39.892297,lon:116.068297,count:5},
- {name:"香港",lat:22.428066,lon:114.093184,count:2},
- {name:"澳门",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: <max>, data: [{lonlat: <OpenLayers.LonLat>, count: <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: 'degrees'
- };
- 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["千米"] = OpenLayers.INCHES_PER_UNIT["km"];
- OpenLayers.INCHES_PER_UNIT["米"] = OpenLayers.INCHES_PER_UNIT["m"];
- OpenLayers.INCHES_PER_UNIT["英里"] = OpenLayers.INCHES_PER_UNIT["mi"];
- OpenLayers.INCHES_PER_UNIT["英寸"] = OpenLayers.INCHES_PER_UNIT["ft"];
- //比例尺
- map.addControl(new OpenLayers.Control.ScaleLine({topOutUnits:"千米",topInUnits:"米",bottomOutUnits:"英里",
- bottomInUnits:"英寸"
- }));
- map.addControl(new OpenLayers.Control.Zoom());
- map.addControl(new OpenLayers.Control.Navigation());
- map.addControl(new OpenLayers.Control.OverviewMap());
- // create our heatmap layer
- heatmap = 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>
- </head>
- <body onload="init()">
- <div id="map"></div>
- </body>
- </html>
附件:
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|moveend
- tmpData: {},
- 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 nice
- roundPixels: 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 setDataSet
- addDataPoint: 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"
- });
人在山中,才知道,白云也可以抓上一把,苍翠竟有清甜的味道。
人在山中,才知道,高度永远是一个变量,而快乐则是附于中跋涉过程的函数。
人在山中,才知道,庄严是望远时的一种心境,高处才能指点江山。