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"
    });

    在线示例





  • 相关阅读:
    HDU 2433 Travel (最短路,BFS,变形)
    HDU 2544 最短路 (最短路,spfa)
    HDU 2063 过山车 (最大匹配,匈牙利算法)
    HDU 1150 Machine Schedule (最小覆盖,匈牙利算法)
    290 Word Pattern 单词模式
    289 Game of Life 生命的游戏
    287 Find the Duplicate Number 寻找重复数
    283 Move Zeroes 移动零
    282 Expression Add Operators 给表达式添加运算符
    279 Perfect Squares 完美平方数
  • 原文地址:https://www.cnblogs.com/lzugis/p/6539798.html
Copyright © 2011-2022 走看看