Improve heatmap documentation.
This also removes a utility function that is also handled in a proper
utils method.
MODIFY
src/canvas/heatmapFeature.js
src/canvas/heatmapFeature.js
@@ -2,15 +2,16 @@ var inherit = require('../inherit');
var registerFeature = require('../registry').registerFeature;
var heatmapFeature = require('../heatmapFeature');
var timestamp = require('../timestamp');
+var util = require('../util');
/**
- * Create a new instance of class heatmapFeature
+ * Create a new instance of class canvas.heatmapFeature.
* Inspired from
- * https://github.com/mourner/simpleheat/blob/gh-pages/simpleheat.js
+ * https://github.com/mourner/simpleheat/blob/gh-pages/simpleheat.js .
*
* @class
* @alias geo.canvas.heatmapFeature
- * @param {Object} arg Options object
+ * @param {geo.heatmapFeature.spec} arg
* @extends geo.heatmapFeature
* @returns {canvas_heatmapFeature}
*/
@@ -36,30 +37,14 @@ var canvas_heatmapFeature = function (arg) {
m_typedBufferData,
m_heatMapPosition,
m_heatMapTransform,
- s_exit = this._exit,
s_init = this._init,
s_update = this._update,
m_renderTime = timestamp();
/**
- * Meta functions for converting from geojs styles to canvas.
- * @private
- */
- this._convertColor = function (c) {
- var color;
- if (c.hasOwnProperty('r') &&
- c.hasOwnProperty('g') &&
- c.hasOwnProperty('b') &&
- c.hasOwnProperty('a')) {
- color = 'rgba(' + 255 * c.r + ',' + 255 * c.g + ','
- + 255 * c.b + ',' + c.a + ')';
- }
- return color;
- };
-
- /**
- * Compute gradient (color lookup table)
- * @protected
+ * Compute gradient. This creates a color lookup table.
+ *
+ * @returns {this}
*/
this._computeGradient = function () {
var canvas, stop, context2d, gradient, colors;
@@ -74,7 +59,7 @@ var canvas_heatmapFeature = function (arg) {
canvas.height = 256;
for (stop in colors) {
- gradient.addColorStop(stop, m_this._convertColor(colors[stop]));
+ gradient.addColorStop(stop, util.convertColorToRGBA(colors[stop]));
}
context2d.fillStyle = gradient;
@@ -87,8 +72,9 @@ var canvas_heatmapFeature = function (arg) {
};
/**
- * Create circle for each data point
- * @protected
+ * Create circle for each data point.
+ *
+ * @returns {this}
*/
this._createCircle = function () {
var circle, ctx, r, r2, blur, gaussian;
@@ -149,7 +135,11 @@ var canvas_heatmapFeature = function (arg) {
};
/**
- * Compute color for each pixel on the screen
+ * Compute color for each pixel on the screen.
+ *
+ * @param {Uint8ClampedArray} pixels A 2D canvas `getImageData` buffer.
+ * @param {Uint8ClampedArray} gradient A 2D canvas with 256 pixels that
+ * contain a color gradient.
* @protected
*/
this._colorize = function (pixels, gradient) {
@@ -174,11 +164,11 @@ var canvas_heatmapFeature = function (arg) {
/**
* Render individual data points on the canvas.
- * @protected
- * @param {object} context2d the canvas context to draw in.
- * @param {object} map the parent map object.
- * @param {Array} data the main data array.
- * @param {number} radius the sum of radius and blurRadius.
+ *
+ * @param {RenderingContext} context2d The canvas context to draw in.
+ * @param {geo.map} map The parent map object.
+ * @param {array} data The main data array.
+ * @param {number} radius The sum of `radius` and `blurRadius`.
*/
this._renderPoints = function (context2d, map, data, radius) {
var position = m_this.gcsPosition(),
@@ -189,7 +179,7 @@ var canvas_heatmapFeature = function (arg) {
for (idx = data.length - 1; idx >= 0; idx -= 1) {
pos = map.worldToDisplay(position[idx]);
- intensity = (intensityFunc(data[idx]) - minIntensity) / rangeIntensity;
+ intensity = (intensityFunc(data[idx], idx) - minIntensity) / rangeIntensity;
if (intensity <= 0) {
continue;
}
@@ -202,12 +192,12 @@ var canvas_heatmapFeature = function (arg) {
/**
* Render data points on the canvas by binning.
- * @protected
- * @param {object} context2d the canvas context to draw in.
- * @param {object} map the parent map object.
- * @param {Array} data the main data array.
- * @param {number} radius the sum of radius and blurRadius.
- * @param {number} binSize size of the bins in pixels.
+ *
+ * @param {RenderingContext} context2d The canvas context to draw in.
+ * @param {geo.map} map The parent map object.
+ * @param {array} data The main data array.
+ * @param {number} radius The sum of `radius` and `blurRadius`.
+ * @param {number} binSize Size of the bins in pixels.
*/
this._renderBinnedData = function (context2d, map, data, radius, binSize) {
var position = m_this.gcsPosition(),
@@ -249,7 +239,7 @@ var canvas_heatmapFeature = function (arg) {
if (y < 0 || y >= maxy) {
continue;
}
- intensity = (intensityFunc(data[idx]) - minIntensity) / rangeIntensity;
+ intensity = (intensityFunc(data[idx], idx) - minIntensity) / rangeIntensity;
if (intensity <= 0) {
continue;
}
@@ -300,9 +290,10 @@ var canvas_heatmapFeature = function (arg) {
/**
* Render the data on the canvas, then colorize the resulting opacity map.
- * @protected
- * @param {object} context2d the canvas context to draw in.
- * @param {object} map the parent map object.
+ *
+ * @param {RenderingContext} context2d The canvas context to draw in.
+ * @param {geo.map} map The parent map object.
+ * @returns {this}
*/
this._renderOnCanvas = function (context2d, map) {
@@ -365,8 +356,9 @@ var canvas_heatmapFeature = function (arg) {
};
/**
- * Initialize
- * @protected
+ * Initialize.
+ *
+ * @returns {this}
*/
this._init = function () {
s_init.call(m_this, arg);
@@ -377,8 +369,9 @@ var canvas_heatmapFeature = function (arg) {
};
/**
- * Update
- * @protected
+ * Update the feature.
+ *
+ * @returns {this}
*/
this._update = function () {
s_update.call(m_this);
@@ -392,7 +385,8 @@ var canvas_heatmapFeature = function (arg) {
/**
* Update the css transform for the layer as part of an animation frame.
- * @protected
+ * This allows an existing rendered version of the heatmap to appear with a
+ * transform until a new version can be computed.
*/
this._setTransform = function () {
if (m_this.layer() && m_this.layer().canvas() && m_this.layer().canvas()[0]) {
@@ -401,10 +395,9 @@ var canvas_heatmapFeature = function (arg) {
};
/**
- * Animate pan (and zoom)
- * @protected
+ * Animate pan and zoom.
*/
- this._animatePan = function (e) {
+ this._animatePan = function () {
if (!m_heatMapPosition) {
return;
@@ -455,14 +448,6 @@ var canvas_heatmapFeature = function (arg) {
}
};
- /**
- * Destroy
- * @protected
- */
- this._exit = function () {
- s_exit.call(m_this);
- };
-
m_this._init(arg);
return this;
};

MODIFY
src/heatmapFeature.js
src/heatmapFeature.js
@@ -4,47 +4,48 @@ var feature = require('./feature');
var transform = require('./transform');
/**
- * Create a new instance of class heatmapFeature
+ * Heatmap feature specification.
*
- * @class
- * @alias geo.heatmapFeature
- * @param {Object} arg Options object
- * @extends geo.feature
- * @param {Object|Function} [position] Position of the data. Default is
- * (data).
- * @param {Object|Function} [intensity] Scalar value of each data point. Scalar
- * value must be a positive real number and will be used to compute
- * the weight for each data point.
+ * @typedef {geo.feature.spec} geo.heatmapFeature.spec
+ * @property {geo.geoPosition|function} [position] Position of the data.
+ * Default is (data).
+ * @param {function} [intensity] Scalar value of each data point. The scalar
+ * value must be a positive real number and is used to compute the weight
+ * for each data point.
* @param {number} [maxIntensity=null] Maximum intensity of the data. Maximum
- * intensity must be a positive real number and will be used to normalize all
- * intensities with a dataset. If no value is given, then a it will
- * be computed.
+ * intensity must be a positive real number and is used to normalize all
+ * intensities within a dataset. If `null`, it is computed.
* @param {number} [minIntensity=null] Minimum intensity of the data. Minimum
- * intensity must be a positive real number will be used to normalize all
- * intensities with a dataset. If no value is given, then a it will
- * be computed.
+ * intensity must be a positive real number and is used to normalize all
+ * intensities within a dataset. If `null`, it is computed.
* @param {number} [updateDelay=1000] Delay in milliseconds after a zoom,
* rotate, or pan event before recomputing the heatmap.
- * @param {boolean|number|'auto'} [binned='auto'] If true or a number,
- * spatially bin data as part of producing the heatpmap. If false, each
- * datapoint stands on its own. If 'auto', bin data if there are more data
- * points than there would be bins. Using true or auto uses bins that are
- * max(Math.floor((radius + blurRadius) / 8), 3).
- * @param {Object|string|Function} [style.color] Color transfer function that.
- * will be used to evaluate color of each pixel using normalized intensity
- * as the look up value.
- * @param {Object|Function} [style.radius=10] Radius of a point in terms of
- * number of pixels.
- * @param {Object|Function} [style.blurRadius=10] Blur radius for each point in
- * terms of number of pixels.
- * @param {boolean} [style.gaussian=true] If true, appoximate a gaussian
+ * @param {boolean|number|'auto'} [binned='auto'] If `true` or a number,
+ * spatially bin data as part of producing the heatmap. If falsy, each
+ * datapoint stands on its own. If `'auto'`, bin data if there are more data
+ * points than there would be bins. Using `true` or `auto` uses bins that
+ * are `max(Math.floor((radius + blurRadius) / 8), 3)`.
+ * @param {object} [style.color] An object where the keys are numbers from
+ * [0-1] and the values are {@link geo.geoColor}. This is used to transform
+ * normalized intensity.
+ * @param {number} [style.radius=10] Radius of a point in pixels.
+ * @param {number} [style.blurRadius=10] Blur radius for each point in pixels.
+ * @param {boolean} [style.gaussian=true] If truthy, appoximate a gaussian
* distribution for each point using a multi-segment linear radial
* appoximation. The total weight of the gaussian area is approximately the
- * 9/16 r^2. The sum of radius + blurRadius is used as the radius for the
- * gaussian distribution.
- * @returns {geo.heatmapFeature}
+ * `9/16 r^2`. The sum of `radius + blurRadius` is used as the radius for
+ * the gaussian distribution.
*/
+/**
+ * Create a new instance of class heatmapFeature.
+ *
+ * @class
+ * @alias geo.heatmapFeature
+ * @param {geo.heatmapFeature.spec} arg
+ * @extends geo.feature
+ * @returns {geo.heatmapFeature}
+ */
var heatmapFeature = function (arg) {
'use strict';
if (!(this instanceof heatmapFeature)) {
@@ -74,9 +75,12 @@ var heatmapFeature = function (arg) {
m_updateDelay = arg.updateDelay ? parseInt(arg.updateDelay, 10) : 1000;
/**
- * Get/Set maxIntensity
+ * Get/Set maxIntensity.
*
- * @returns {geo.heatmap}
+ * @param {number|null} [val] If not specified, return the current value.
+ * If a number, use this as the maximum intensity. If `null`, compute
+ * the maximum intensity.
+ * @returns {number|null|this}
*/
this.maxIntensity = function (val) {
if (val === undefined) {
@@ -90,9 +94,12 @@ var heatmapFeature = function (arg) {
};
/**
- * Get/Set maxIntensity
+ * Get/Set minIntensity.
*
- * @returns {geo.heatmap}
+ * @param {number|null} [val] If not specified, return the current value.
+ * If a number, use this as the minimum intensity. If `null`, compute
+ * the minimum intensity.
+ * @returns {number|null|this}
*/
this.minIntensity = function (val) {
if (val === undefined) {
@@ -106,9 +113,12 @@ var heatmapFeature = function (arg) {
};
/**
- * Get/Set updateDelay
+ * Get/Set updateDelay.
*
- * @returns {geo.heatmap}
+ * @param {number} [val] If not specified, return the current update delay.
+ * If specified, this is the delay in milliseconds after a zoom, rotate,
+ * or pan event before recomputing the heatmap.
+ * @returns {number|this}
*/
this.updateDelay = function (val) {
if (val === undefined) {
@@ -120,9 +130,15 @@ var heatmapFeature = function (arg) {
};
/**
- * Get/Set binned
+ * Get/Set binned value.
*
- * @returns {geo.heatmap}
+ * @param {boolean|number|'auto'} [val] If not specified, return the current
+ * binned value. If `true` or a number, spatially bin data as part of
+ * producing the heatmap. If falsy, each datapoint stands on its own.
+ * If `'auto'`, bin data if there are more data points than there would be
+ * bins. Using `true` or `auto` uses bins that are
+ * `max(Math.floor((radius + blurRadius) / 8), 3)`.
+ * @returns {boolean|number|'auto'|this}
*/
this.binned = function (val) {
if (val === undefined) {
@@ -146,9 +162,14 @@ var heatmapFeature = function (arg) {
};
/**
- * Get/Set position accessor
+ * Get/Set position accessor.
*
- * @returns {geo.heatmap}
+ * @param {geo.geoPosition|function} [val] If not specified, return the
+ * current position accessor. If specified, use this for the position
+ * accessor and return `this`. If a function is given, this is called
+ * with `(dataElement, dataIndex)`.
+ * @returns {geo.geoPosition|function|this} The current position or this
+ * feature.
*/
this.position = function (val) {
if (val === undefined) {
@@ -162,7 +183,7 @@ var heatmapFeature = function (arg) {
};
/**
- * Get pre-computed gcs position accessor
+ * Get pre-computed gcs position accessor.
*
* @returns {geo.heatmap}
*/
@@ -172,9 +193,11 @@ var heatmapFeature = function (arg) {
};
/**
- * Get/Set intensity
+ * Get/Set intensity.
*
- * @returns {geo.heatmap}
+ * @param {function} [val] If not specified, the current intensity accessor.
+ * Otherwise, a function that returns the intensity of each data point.
+ * @returns {function|this}
*/
this.intensity = function (val) {
if (val === undefined) {
@@ -188,7 +211,9 @@ var heatmapFeature = function (arg) {
};
/**
- * Initialize
+ * Initialize.
+ *
+ * @param {geo.heatmapFeature.spec} arg
*/
this._init = function (arg) {
s_init.call(m_this, arg);
@@ -199,7 +224,8 @@ var heatmapFeature = function (arg) {
radius: 10,
blurRadius: 10,
gaussian: true,
- color: {0: {r: 0, g: 0, b: 0.0, a: 0.0},
+ color: {
+ 0: {r: 0, g: 0, b: 0.0, a: 0.0},
0.25: {r: 0, g: 0, b: 1, a: 0.5},
0.5: {r: 0, g: 1, b: 1, a: 0.6},
0.75: {r: 1, g: 1, b: 0, a: 0.7},
@@ -216,8 +242,9 @@ var heatmapFeature = function (arg) {
};
/**
- * Build
- * @override
+ * Build the fetaure.
+ *
+ * @returns {this}
*/
this._build = function () {
var data = m_this.data(),
@@ -226,10 +253,10 @@ var heatmapFeature = function (arg) {
setMax = (m_maxIntensity === null || m_maxIntensity === undefined),
setMin = (m_minIntensity === null || m_minIntensity === undefined);
- data.forEach(function (d) {
- position.push(m_this.position()(d));
+ data.forEach(function (d, i) {
+ position.push(m_this.position()(d, i));
if (setMax || setMin) {
- intensity = m_this.intensity()(d);
+ intensity = m_this.intensity()(d, i);
if (m_maxIntensity === null || m_maxIntensity === undefined) {
m_maxIntensity = intensity;
}

Improve heatmap documentation.

This also removes a utility function that is also handled in a proper
utils method.