首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Openlayers中热力图的实现

Openlayers中热力图的实现

作者头像
lzugis
发布2018-10-23 13:28:25
3.3K0
发布2018-10-23 13:28:25
举报

概述:

本文讲述结合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"
});

在线示例

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015年12月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 在线示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档