Openlayers热力图层
无意中找到的一个Openlayers生成热力图层的实现
原文地址:http://www.websitedev.de/temp/openlayers-heatmap-layer.html
HeatmapLayer.js:
/*
* Copyright (c) 2010 Bjoern Hoehrmann <http://bjoern.hoehrmann.de/>.
* This module is licensed under the same terms as OpenLayers itself.
*
*/
Heatmap = {};
/**
* Class: Heatmap.Source
*/
Heatmap.Source = OpenLayers.Class({
/**
* APIProperty: lonlat
* {OpenLayers.LonLat} location of the heat source
*/
lonlat: null,
/**
* APIProperty: radius
* {Number} Heat source radius
*/
radius: null,
/**
* APIProperty: intensity
* {Number} Heat source intensity
*/
intensity: null,
/**
* Constructor: Heatmap.Source
* Create a heat source.
*
* Parameters:
* lonlat - {OpenLayers.LonLat} Coordinates of the heat source
* radius - {Number} Optional radius
* intensity - {Number} Optional intensity
*/
initialize: function(lonlat, radius, intensity) {
this.lonlat = lonlat;
this.radius = radius;
this.intensity = intensity;
},
CLASS_NAME: 'Heatmap.Source'
});
/**
* Class: Heatmap.Layer
*
* Inherits from:
* - <OpenLayers.Layer>
*/
Heatmap.Layer = OpenLayers.Class(OpenLayers.Layer, {
/**
* APIProperty: isBaseLayer
* {Boolean} Heatmap layer is never a base layer.
*/
isBaseLayer: false,
/**
* Property: points
* {Array(<Heatmap.Source>)} internal coordinate list
*/
points: null,
/**
* Property: cache
* {Object} Hashtable with CanvasGradient objects
*/
cache: null,
/**
* Property: gradient
* {Array(Number)} RGBA gradient map used to colorize the intensity map.
*/
gradient: null,
/**
* Property: canvas
* {DOMElement} Canvas element.
*/
canvas: null,
/**
* APIProperty: defaultRadius
* {Number} Heat source default radius
*/
defaultRadius: null,
/**
* APIProperty: defaultIntensity
* {Number} Heat source default intensity
*/
defaultIntensity: null,
/**
* Constructor: Heatmap.Layer
* Create a heatmap layer.
*
* Parameters:
* name - {String} Name of the Layer
* options - {Object} Hashtable of extra options to tag onto the layer
*/
initialize: function(name, options) {
OpenLayers.Layer.prototype.initialize.apply(this, arguments);
this.points = [];
this.cache = {};
this.canvas = document.createElement('canvas');
this.canvas.style.position = 'absolute';
this.defaultRadius = 20;
this.defaultIntensity = 0.2;
this.setGradientStops({
0.00: 0xffffff00,
0.10: 0x99e9fdff,
0.20: 0x00c9fcff,
0.30: 0x00e9fdff,
0.30: 0x00a5fcff,
0.40: 0x0078f2ff,
0.50: 0x0e53e9ff,
0.60: 0x4a2cd9ff,
0.70: 0x890bbfff,
0.80: 0x99019aff,
0.90: 0x990664ff,
0.99: 0x660000ff,
1.00: 0x000000ff
});
// For some reason OpenLayers.Layer.setOpacity assumes there is
// an additional div between the layer's div and its contents.
var sub = document.createElement('div');
sub.appendChild(this.canvas);
this.div.appendChild(sub);
},
/**
* APIMethod: setGradientStops
* ...
*
* Parameters:
* stops - {Object} Hashtable with stop position as keys and colors
* as values. Stop positions are numbers between 0
* and 1, color values numbers in 0xRRGGBBAA form.
*/
setGradientStops: function(stops) {
// There is no need to perform the linear interpolation manually,
// it is sufficient to let the canvas implementation do that.
var ctx = document.createElement('canvas').getContext('2d');
var grd = ctx.createLinearGradient(0, 0, 256, 0);
for (var i in stops) {
grd.addColorStop(i, 'rgba(' +
((stops[i] >> 24) & 0xFF) + ',' +
((stops[i] >> 16) & 0xFF) + ',' +
((stops[i] >> 8) & 0xFF) + ',' +
((stops[i] >> 0) & 0xFF) + ')');
}
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 256, 1);
this.gradient = ctx.getImageData(0, 0, 256, 1).data;
},
/**
* APIMethod: addSource
* Adds a heat source to the layer.
*
* Parameters:
* source - {<Heatmap.Source>}
*/
addSource: function(source) {
this.points.push(source);
},
/**
* APIMethod: removeSource
* Removes a heat source from the layer.
*
* Parameters:
* source - {<Heatmap.Source>}
*/
removeSource: function(source) {
if (this.points && this.points.length) {
OpenLayers.Util.removeItem(this.points, source);
}
},
/**
* Method: moveTo
*
* Parameters:
* bounds - {<OpenLayers.Bounds>}
* zoomChanged - {Boolean}
* dragging - {Boolean}
*/
moveTo: function(bounds, zoomChanged, dragging) {
OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
// The code is too slow to update the rendering during dragging.
if (dragging)
return;
// Pick some point on the map and use it to determine the offset
// between the map's 0,0 coordinate and the layer's 0,0 position.
var someLoc = new OpenLayers.LonLat(0,0);
var offsetX = this.map.getViewPortPxFromLonLat(someLoc).x -
this.map.getLayerPxFromLonLat(someLoc).x;
var offsetY = this.map.getViewPortPxFromLonLat(someLoc).y -
this.map.getLayerPxFromLonLat(someLoc).y;
this.canvas.width = this.map.getSize().w;
this.canvas.height = this.map.getSize().h;
var ctx = this.canvas.getContext('2d');
ctx.save(); // Workaround for a bug in Google Chrome
ctx.fillStyle = 'transparent';
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
ctx.restore();
for (var i in this.points) {
var src = this.points[i];
var rad = src.radius || this.defaultRadius;
var int = src.intensity || this.defaultIntensity;
var pos = this.map.getLayerPxFromLonLat(src.lonlat);
var x = pos.x - rad + offsetX;
var y = pos.y - rad + offsetY;
if (!this.cache[int]) {
this.cache[int] = {};
}
if (!this.cache[int][rad]) {
var grd = ctx.createRadialGradient(rad, rad, 0, rad, rad, rad);
grd.addColorStop(0.0, 'rgba(0, 0, 0, ' + int + ')');
grd.addColorStop(1.0, 'transparent');
this.cache[int][rad] = grd;
}
ctx.fillStyle = this.cache[int][rad];
ctx.translate(x, y);
ctx.fillRect(0, 0, 2 * rad, 2 * rad);
ctx.translate(-x, -y);
}
var dat = ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
var dim = this.canvas.width * this.canvas.height * 4;
var pix = dat.data;
for (var p = 0; p < dim;) {
var a = pix[ p + 3 ] * 4;
pix[ p++ ] = this.gradient[ a++ ];
pix[ p++ ] = this.gradient[ a++ ];
pix[ p++ ] = this.gradient[ a++ ];
pix[ p++ ] = this.gradient[ a++ ];
}
ctx.putImageData(dat, 0, 0);
// Unfortunately OpenLayers does not currently support layers that
// remain in a fixed position with respect to the screen location
// of the base layer, so this puts this layer manually back into
// that position using one point's offset as determined earlier.
this.canvas.style.left = (-offsetX) + 'px';
this.canvas.style.top = (-offsetY) + 'px';
},
/**
* APIMethod: getDataExtent
* Calculates the max extent which includes all of the heat sources.
*
* Returns:
* {<OpenLayers.Bounds>}
*/
getDataExtent: function () {
var maxExtent = null;
if (this.points && (this.points.length > 0)) {
var maxExtent = new OpenLayers.Bounds();
for(var i = 0, len = this.points.length; i < len; ++i) {
var point = this.points[i];
maxExtent.extend(point.lonlat);
}
}
return maxExtent;
},
CLASS_NAME: 'Heatmap.Layer'
});
示例Html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers Heatmap Layer (using <canvas>)</title>
<script src="OpenLayers.js" type="text/javascript"></script>
<script src="HeatmapLayer.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
var map;
var points=[];
function MapMoveend(event){
//
//alert("moveend");
var level = map.getZoom();
var heat = map.getLayersByName("Heatmap")[0];
if(level>3){
for(var i=0;i<points.length;i++){
heat.removeSource(points[i]);
}
var coordinates = [
[ /* 47273 */ 54.5261111111, 9.91555555556 ],
[ /* 58696 */ 54.4563888889, 11.2125 ],
[ /* 39069 */ 54.8122777778, 9.46488888889 ],
[ /* 41256 */ 54.3265, 10.14 ],
[ /* 53322 */ 54.5280555556, 8.5125 ],
[ /* 53326 */ 54.4652777778, 8.72638888889 ],
[ /* 53327 */ 54.4633333333, 8.55305555556 ],
[ /* 64553 */ 54.4683333333, 11.1438888889 ],
[ /* 53876 */ 54.48, 11.0677777778 ],
[ /* 310169 */ 54.46185, 11.2433666667 ],
[ /* 344838 */ 54.42472, 10.28423 ],
[ /* 285492 */ 54.4, 10.35 ],
[ /* 288560 */ 54.4, 9.85 ]
];
for (var latlng in coordinates) {
var point = new Heatmap.Source(new OpenLayers.LonLat(coordinates[latlng][1], coordinates[latlng][0]),20,(coordinates[latlng][1]-8));
points.push(point);
heat.addSource(point);
}
heat.redraw(true);
}
else{
for(var i=0;i<points.length;i++){
heat.removeSource(points[i]);
}
for (var i=0;i<5000;i++) {
var lon = Math.random()*180;
var lat = Math.random()*90;
var point = new Heatmap.Source(new OpenLayers.LonLat(lon,lat),20,Math.random());
points.push(point);
heat.addSource(point);
}
heat.redraw(true);
}
};
function init() {
map = new OpenLayers.Map('map', {
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.LayerSwitcher({'ascending':false}),
new OpenLayers.Control.MousePosition(),
// new OpenLayers.Control.KeyboardDefaults()
],
eventListeners: {
"moveend": MapMoveend,
}
});
var heat = new Heatmap.Layer("Heatmap");
//heat.defaultIntensity = 1;
heat.setOpacity(0.75);
heat.setGradientStops({
0.00: 0xffffff00,
0.10: 0x00C7FFff,
0.50: 0xFFFF00ff,
1.00: 0xFF0000ff
});
var wms = new OpenLayers.Layer.WMS("OpenLayers WMS", "http://labs.metacarta.com/wms/vmap0", {layers: 'basic'});
map.addLayers([wms, heat]);
//map.zoomToExtent(heat.getDataExtent());
}
//]]>
</script>
</head>
<body onload="init()">
<h1 style='text-align:center'>OpenLayers Heatmap Layer (using <canvas>)</h1>
<div id="map" style='height:600px'></div>
<h2>Usage</h2>
<pre>
var heat = new Heatmap.Layer("Heatmap");
heat.addSource(new Heatmap.Source(new OpenLayers.LonLat(9.434, 54.740)));
heat.addSource(new Heatmap.Source(new OpenLayers.LonLat(9.833, 54.219)));
...
map.addLayer(heat);
map.zoomToExtent(heat.getDataExtent());
</pre>
</body>
</html>
转载自:https://blog.csdn.net/hjhandhf/article/details/51660520