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

You may also like...