Merge pull request #3231 from fredj/heatmap-radius

Make ol.layer.Heatmap#radius configurable
This commit is contained in:
Frédéric Junod
2015-02-12 16:36:56 +01:00
3 changed files with 96 additions and 26 deletions
+9 -2
View File
@@ -29,7 +29,7 @@
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span8">
<h4 id="title">Earthquakes heatmap</h4> <h4 id="title">Earthquakes heatmap</h4>
<p id="shortdesc">Demonstrates the use of a heatmap layer.</p> <p id="shortdesc">Demonstrates the use of a heatmap layer.</p>
<div id="docs"> <div id="docs">
@@ -40,8 +40,15 @@
</div> </div>
<div id="tags">heatmap, kml, vector, style</div> <div id="tags">heatmap, kml, vector, style</div>
</div> </div>
</div>
<div class="span4">
<form>
<label>radius size</label>
<input id="radius" type="range" min="1" max="50" step="1" value="5"/>
</form>
</div>
</div>
</div> </div>
<script src="../resources/jquery.min.js" type="text/javascript"></script> <script src="../resources/jquery.min.js" type="text/javascript"></script>
+7 -1
View File
@@ -5,6 +5,7 @@ goog.require('ol.layer.Tile');
goog.require('ol.source.KML'); goog.require('ol.source.KML');
goog.require('ol.source.Stamen'); goog.require('ol.source.Stamen');
var radius = $('#radius');
var vector = new ol.layer.Heatmap({ var vector = new ol.layer.Heatmap({
source: new ol.source.KML({ source: new ol.source.KML({
@@ -12,7 +13,7 @@ var vector = new ol.layer.Heatmap({
projection: 'EPSG:3857', projection: 'EPSG:3857',
url: 'data/kml/2012_Earthquakes_Mag5.kml' url: 'data/kml/2012_Earthquakes_Mag5.kml'
}), }),
radius: 5 radius: parseInt(radius.val(), 10)
}); });
vector.getSource().on('addfeature', function(event) { vector.getSource().on('addfeature', function(event) {
@@ -38,3 +39,8 @@ var map = new ol.Map({
zoom: 2 zoom: 2
}) })
}); });
radius.on('input', function() {
vector.setRadius(parseInt(radius.val(), 10));
});
+80 -23
View File
@@ -16,7 +16,8 @@ goog.require('ol.style.Style');
* @enum {string} * @enum {string}
*/ */
ol.layer.HeatmapLayerProperty = { ol.layer.HeatmapLayerProperty = {
GRADIENT: 'gradient' GRADIENT: 'gradient',
RADIUS: 'radius'
}; };
@@ -52,22 +53,42 @@ ol.layer.Heatmap = function(opt_options) {
*/ */
this.gradient_ = null; this.gradient_ = null;
/**
* @private
* @type {number}
*/
this.blur_ = goog.isDef(options.blur) ? options.blur : 15;
/**
* @private
* @type {number}
*/
this.shadow_ = goog.isDef(options.shadow) ? options.shadow : 250;
/**
* @private
* @type {string|undefined}
*/
this.circleImage_ = undefined;
/**
* @private
* @type {Array.<Array.<ol.style.Style>>}
*/
this.styleCache_ = null;
goog.events.listen(this, goog.events.listen(this,
ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.GRADIENT), ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.GRADIENT),
this.handleGradientChanged_, false, this); this.handleGradientChanged_, false, this);
goog.events.listen(this,
ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.RADIUS),
this.handleStyleChanged_, false, this);
this.setGradient(goog.isDef(options.gradient) ? this.setGradient(goog.isDef(options.gradient) ?
options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT); options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT);
var circle = ol.layer.Heatmap.createCircle_( this.setRadius(goog.isDef(options.radius) ? options.radius : 8);
goog.isDef(options.radius) ? options.radius : 8,
goog.isDef(options.blur) ? options.blur : 15,
goog.isDef(options.shadow) ? options.shadow : 250);
/**
* @type {Array.<Array.<ol.style.Style>>}
*/
var styleCache = new Array(256);
var weight = goog.isDef(options.weight) ? options.weight : 'weight'; var weight = goog.isDef(options.weight) ? options.weight : 'weight';
var weightFunction; var weightFunction;
@@ -80,25 +101,25 @@ ol.layer.Heatmap = function(opt_options) {
} }
goog.asserts.assert(goog.isFunction(weightFunction)); goog.asserts.assert(goog.isFunction(weightFunction));
this.setStyle(function(feature, resolution) { this.setStyle(goog.bind(function(feature, resolution) {
var weight = weightFunction(feature); var weight = weightFunction(feature);
var opacity = goog.isDef(weight) ? goog.math.clamp(weight, 0, 1) : 1; var opacity = goog.isDef(weight) ? goog.math.clamp(weight, 0, 1) : 1;
// cast to 8 bits // cast to 8 bits
var index = (255 * opacity) | 0; var index = (255 * opacity) | 0;
var style = styleCache[index]; var style = this.styleCache_[index];
if (!goog.isDef(style)) { if (!goog.isDef(style)) {
style = [ style = [
new ol.style.Style({ new ol.style.Style({
image: new ol.style.Icon({ image: new ol.style.Icon({
opacity: opacity, opacity: opacity,
src: circle src: this.circleImage_
}) })
}) })
]; ];
styleCache[index] = style; this.styleCache_[index] = style;
} }
return style; return style;
}); }, this));
// For performance reasons, don't sort the features before rendering. // For performance reasons, don't sort the features before rendering.
// The render order is not relevant for a heatmap representation. // The render order is not relevant for a heatmap representation.
@@ -142,21 +163,19 @@ ol.layer.Heatmap.createGradient_ = function(colors) {
/** /**
* @param {number} radius Radius size in pixel.
* @param {number} blur Blur size in pixel.
* @param {number} shadow Shadow offset size in pixel.
* @return {string} * @return {string}
* @private * @private
*/ */
ol.layer.Heatmap.createCircle_ = function(radius, blur, shadow) { ol.layer.Heatmap.prototype.createCircle_ = function() {
var halfSize = radius + blur + 1; var radius = this.getRadius();
var halfSize = radius + this.blur_ + 1;
var size = 2 * halfSize; var size = 2 * halfSize;
var context = ol.dom.createCanvasContext2D(size, size); var context = ol.dom.createCanvasContext2D(size, size);
context.shadowOffsetX = context.shadowOffsetY = shadow; context.shadowOffsetX = context.shadowOffsetY = this.shadow_;
context.shadowBlur = blur; context.shadowBlur = this.blur_;
context.shadowColor = '#000'; context.shadowColor = '#000';
context.beginPath(); context.beginPath();
var center = halfSize - shadow; var center = halfSize - this.shadow_;
context.arc(center, center, radius, 0, Math.PI * 2, true); context.arc(center, center, radius, 0, Math.PI * 2, true);
context.fill(); context.fill();
return context.canvas.toDataURL(); return context.canvas.toDataURL();
@@ -178,6 +197,20 @@ goog.exportProperty(
ol.layer.Heatmap.prototype.getGradient); ol.layer.Heatmap.prototype.getGradient);
/**
* @return {number} Radius size in pixel.
* @api
* @observable
*/
ol.layer.Heatmap.prototype.getRadius = function() {
return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.RADIUS));
};
goog.exportProperty(
ol.layer.Heatmap.prototype,
'getRadius',
ol.layer.Heatmap.prototype.getRadius);
/** /**
* @private * @private
*/ */
@@ -186,6 +219,16 @@ ol.layer.Heatmap.prototype.handleGradientChanged_ = function() {
}; };
/**
* @private
*/
ol.layer.Heatmap.prototype.handleStyleChanged_ = function() {
this.circleImage_ = this.createCircle_();
this.styleCache_ = new Array(256);
this.changed();
};
/** /**
* @param {ol.render.Event} event Post compose event * @param {ol.render.Event} event Post compose event
* @private * @private
@@ -221,3 +264,17 @@ goog.exportProperty(
ol.layer.Heatmap.prototype, ol.layer.Heatmap.prototype,
'setGradient', 'setGradient',
ol.layer.Heatmap.prototype.setGradient); ol.layer.Heatmap.prototype.setGradient);
/**
* @param {number} radius Radius size in pixel.
* @api
* @observable
*/
ol.layer.Heatmap.prototype.setRadius = function(radius) {
this.set(ol.layer.HeatmapLayerProperty.RADIUS, radius);
};
goog.exportProperty(
ol.layer.Heatmap.prototype,
'setRadius',
ol.layer.Heatmap.prototype.setRadius);