zoukankan      html  css  js  c++  java
  • 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%;
    			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;"+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"
    });

    在线示例





  • 相关阅读:
    react 编写日历组件
    腾讯地图打开地图选取位置 withMap
    react 动态修改 document.title
    axios 中断请求
    react 使用 react-loadable分包
    http Authorization
    @media screen媒体查询
    CSS规范
    布局和WEB性能
    CSS 标签的分类,及显示模式
  • 原文地址:https://www.cnblogs.com/lzugis/p/6539798.html
Copyright © 2011-2022 走看看