diff --git a/README.md b/README.md
index 457e58ac..c2e96a80 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,17 @@ Dynamic Heatmaps for the Web.
[](http://www.patrick-wied.at/static/heatmapjs/?utm_source=gh "View the heatmap.js website with usage examples, showcases, best practises, plugins ( googlemaps heatmap, leaflet) and more.")
+## mars3d update
+- fix: An error "Cannot assign to read only property 'data' of object '#'"
+- add: Added support for typescript in index.d.ts
+- The NPM package was released `@mars3d/heatmap.js`
+
+
## How to get started
The fastest way to get started is to install heatmap.js with bower. Just run the following command:
-`bower install heatmap.js-amd`
+`bower install @mars3d/heatmap.js-amd`
This will download the latest working version of heatmap.js and put it in your bower_components folder.
@@ -20,7 +26,7 @@ The file you're ultimately looking for is **heatmap.js** or **heatmap.min.js**
heatmap.js is also hosted on npm:
-`npm install heatmap.js`
+`npm install @mars3d/heatmap.js`
diff --git a/build/heatmap.js b/build/heatmap.js
index 3eee39ea..c95e5631 100644
--- a/build/heatmap.js
+++ b/build/heatmap.js
@@ -251,7 +251,7 @@ var Canvas2dRenderer = (function Canvas2dRendererClosure() {
var _getColorPalette = function(config) {
var gradientConfig = config.gradient || config.defaultGradient;
var paletteCanvas = document.createElement('canvas');
- var paletteCtx = paletteCanvas.getContext('2d');
+ var paletteCtx = paletteCanvas.getContext('2d', { willReadFrequently: true });
paletteCanvas.width = 256;
paletteCanvas.height = 1;
@@ -269,7 +269,7 @@ var Canvas2dRenderer = (function Canvas2dRendererClosure() {
var _getPointTemplate = function(radius, blurFactor) {
var tplCanvas = document.createElement('canvas');
- var tplCtx = tplCanvas.getContext('2d');
+ var tplCtx = tplCanvas.getContext('2d', { willReadFrequently: true });
var x = radius;
var y = radius;
tplCanvas.width = tplCanvas.height = radius*2;
@@ -340,8 +340,8 @@ var Canvas2dRenderer = (function Canvas2dRendererClosure() {
this._width = canvas.width = shadowCanvas.width = config.width || +(computed.width.replace(/px/,''));
this._height = canvas.height = shadowCanvas.height = config.height || +(computed.height.replace(/px/,''));
- this.shadowCtx = shadowCanvas.getContext('2d');
- this.ctx = canvas.getContext('2d');
+ this.shadowCtx = shadowCanvas.getContext('2d', { willReadFrequently: true });
+ this.ctx = canvas.getContext('2d', { willReadFrequently: true });
// @TODO:
// conditional wrapper
@@ -524,7 +524,6 @@ var Canvas2dRenderer = (function Canvas2dRendererClosure() {
}
- img.data = imgData;
this.ctx.putImageData(img, x, y);
this._renderBoundaries = [1000, 1000, 0, 0];
diff --git a/build/heatmap.min.js b/build/heatmap.min.js
index f92a6605..09146b1a 100644
--- a/build/heatmap.min.js
+++ b/build/heatmap.min.js
@@ -6,4 +6,4 @@
*
* :: 2016-09-05 01:16
*/
-(function(a,b,c){if(typeof module!=="undefined"&&module.exports){module.exports=c()}else if(typeof define==="function"&&define.amd){define(c)}else{b[a]=c()}})("h337",this,function(){var a={defaultRadius:40,defaultRenderer:"canvas2d",defaultGradient:{.25:"rgb(0,0,255)",.55:"rgb(0,255,0)",.85:"yellow",1:"rgb(255,0,0)"},defaultMaxOpacity:1,defaultMinOpacity:0,defaultBlur:.85,defaultXField:"x",defaultYField:"y",defaultValueField:"value",plugins:{}};var b=function h(){var b=function d(a){this._coordinator={};this._data=[];this._radi=[];this._min=10;this._max=1;this._xField=a["xField"]||a.defaultXField;this._yField=a["yField"]||a.defaultYField;this._valueField=a["valueField"]||a.defaultValueField;if(a["radius"]){this._cfgRadius=a["radius"]}};var c=a.defaultRadius;b.prototype={_organiseData:function(a,b){var d=a[this._xField];var e=a[this._yField];var f=this._radi;var g=this._data;var h=this._max;var i=this._min;var j=a[this._valueField]||1;var k=a.radius||this._cfgRadius||c;if(!g[d]){g[d]=[];f[d]=[]}if(!g[d][e]){g[d][e]=j;f[d][e]=k}else{g[d][e]+=j}var l=g[d][e];if(l>h){if(!b){this._max=l}else{this.setDataMax(l)}return false}else if(l0){var a=arguments[0];var b=a.length;while(b--){this.addData.call(this,a[b])}}else{var c=this._organiseData(arguments[0],true);if(c){if(this._data.length===0){this._min=this._max=c.value}this._coordinator.emit("renderpartial",{min:this._min,max:this._max,data:[c]})}}return this},setData:function(a){var b=a.data;var c=b.length;this._data=[];this._radi=[];for(var d=0;d0){this._drawAlpha(a);this._colorize()}},renderAll:function(a){this._clear();if(a.data.length>0){this._drawAlpha(c(a));this._colorize()}},_updateGradient:function(b){this._palette=a(b)},updateConfig:function(a){if(a["gradient"]){this._updateGradient(a)}this._setStyles(a)},setDimensions:function(a,b){this._width=a;this._height=b;this.canvas.width=this.shadowCanvas.width=a;this.canvas.height=this.shadowCanvas.height=b},_clear:function(){this.shadowCtx.clearRect(0,0,this._width,this._height);this.ctx.clearRect(0,0,this._width,this._height)},_setStyles:function(a){this._blur=a.blur==0?0:a.blur||a.defaultBlur;if(a.backgroundColor){this.canvas.style.backgroundColor=a.backgroundColor}this._width=this.canvas.width=this.shadowCanvas.width=a.width||this._width;this._height=this.canvas.height=this.shadowCanvas.height=a.height||this._height;this._opacity=(a.opacity||0)*255;this._maxOpacity=(a.maxOpacity||a.defaultMaxOpacity)*255;this._minOpacity=(a.minOpacity||a.defaultMinOpacity)*255;this._useGradientOpacity=!!a.useGradientOpacity},_drawAlpha:function(a){var c=this._min=a.min;var d=this._max=a.max;var a=a.data||[];var e=a.length;var f=1-this._blur;while(e--){var g=a[e];var h=g.x;var i=g.y;var j=g.radius;var k=Math.min(g.value,d);var l=h-j;var m=i-j;var n=this.shadowCtx;var o;if(!this._templates[j]){this._templates[j]=o=b(j,f)}else{o=this._templates[j]}var p=(k-c)/(d-c);n.globalAlpha=p<.01?.01:p;n.drawImage(o,l,m);if(lthis._renderBoundaries[2]){this._renderBoundaries[2]=l+2*j}if(m+2*j>this._renderBoundaries[3]){this._renderBoundaries[3]=m+2*j}}},_colorize:function(){var a=this._renderBoundaries[0];var b=this._renderBoundaries[1];var c=this._renderBoundaries[2]-a;var d=this._renderBoundaries[3]-b;var e=this._width;var f=this._height;var g=this._opacity;var h=this._maxOpacity;var i=this._minOpacity;var j=this._useGradientOpacity;if(a<0){a=0}if(b<0){b=0}if(a+c>e){c=e-a}if(b+d>f){d=f-b}var k=this.shadowCtx.getImageData(a,b,c,d);var l=k.data;var m=l.length;var n=this._palette;for(var o=3;o0){r=g}else{if(p>0;return b},getDataURL:function(){return this.canvas.toDataURL()}};return d}();var d=function j(){var b=false;if(a["defaultRenderer"]==="canvas2d"){b=c}return b}();var e={merge:function(){var a={};var b=arguments.length;for(var c=0;ch){if(!b){this._max=l}else{this.setDataMax(l)}return false}else if(l0){var a=arguments[0];var b=a.length;while(b--){this.addData.call(this,a[b])}}else{var c=this._organiseData(arguments[0],true);if(c){if(this._data.length===0){this._min=this._max=c.value}this._coordinator.emit("renderpartial",{min:this._min,max:this._max,data:[c]})}}return this},setData:function(a){var b=a.data;var c=b.length;this._data=[];this._radi=[];for(var d=0;d0){this._drawAlpha(a);this._colorize()}},renderAll:function(a){this._clear();if(a.data.length>0){this._drawAlpha(c(a));this._colorize()}},_updateGradient:function(b){this._palette=a(b)},updateConfig:function(a){if(a["gradient"]){this._updateGradient(a)}this._setStyles(a)},setDimensions:function(a,b){this._width=a;this._height=b;this.canvas.width=this.shadowCanvas.width=a;this.canvas.height=this.shadowCanvas.height=b},_clear:function(){this.shadowCtx.clearRect(0,0,this._width,this._height);this.ctx.clearRect(0,0,this._width,this._height)},_setStyles:function(a){this._blur=a.blur==0?0:a.blur||a.defaultBlur;if(a.backgroundColor){this.canvas.style.backgroundColor=a.backgroundColor}this._width=this.canvas.width=this.shadowCanvas.width=a.width||this._width;this._height=this.canvas.height=this.shadowCanvas.height=a.height||this._height;this._opacity=(a.opacity||0)*255;this._maxOpacity=(a.maxOpacity||a.defaultMaxOpacity)*255;this._minOpacity=(a.minOpacity||a.defaultMinOpacity)*255;this._useGradientOpacity=!!a.useGradientOpacity},_drawAlpha:function(a){var c=this._min=a.min;var d=this._max=a.max;var a=a.data||[];var e=a.length;var f=1-this._blur;while(e--){var g=a[e];var h=g.x;var i=g.y;var j=g.radius;var k=Math.min(g.value,d);var l=h-j;var m=i-j;var n=this.shadowCtx;var o;if(!this._templates[j]){this._templates[j]=o=b(j,f)}else{o=this._templates[j]}var p=(k-c)/(d-c);n.globalAlpha=p<.01?.01:p;n.drawImage(o,l,m);if(lthis._renderBoundaries[2]){this._renderBoundaries[2]=l+2*j}if(m+2*j>this._renderBoundaries[3]){this._renderBoundaries[3]=m+2*j}}},_colorize:function(){var a=this._renderBoundaries[0];var b=this._renderBoundaries[1];var c=this._renderBoundaries[2]-a;var d=this._renderBoundaries[3]-b;var e=this._width;var f=this._height;var g=this._opacity;var h=this._maxOpacity;var i=this._minOpacity;var j=this._useGradientOpacity;if(a<0){a=0}if(b<0){b=0}if(a+c>e){c=e-a}if(b+d>f){d=f-b}var k=this.shadowCtx.getImageData(a,b,c,d);var l=k.data;var m=l.length;var n=this._palette;for(var o=3;o0){r=g}else{if(p>0;return b},getDataURL:function(){return this.canvas.toDataURL()}};return d}();var d=function j(){var b=false;if(a["defaultRenderer"]==="canvas2d"){b=c}return b}();var e={merge:function(){var a={};var b=arguments.length;for(var c=0;c
+// Rhys van der Waerden
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+// TypeScript Version: 2.4
+
+export as namespace h337;
+
+/**
+ * Create a heatmap instance. A Heatmap can be customized with the configObject.
+ *
+ * @example Simple configuration with standard gradient
+ *
+ * // create configuration object
+ * var config = {
+ * container: document.getElementById('heatmapContainer'),
+ * radius: 10,
+ * maxOpacity: .5,
+ * minOpacity: 0,
+ * blur: .75
+ * };
+ * // create heatmap with configuration
+ * var heatmapInstance = h337.create(config);
+ *
+ * @example Custom gradient configuration
+ *
+ * // create configuration object
+ * var config = {
+ * container: document.getElementById('heatmapContainer'),
+ * radius: 10,
+ * maxOpacity: .5,
+ * minOpacity: 0,
+ * blur: .75,
+ * gradient: {
+ * // enter n keys between 0 and 1 here
+ * // for gradient color customization
+ * '.5': 'blue',
+ * '.8': 'red',
+ * '.95': 'white'
+ * }
+ * };
+ * var heatmapInstance = h337.create(config);
+ */
+export function create<
+ V extends string = 'value',
+ X extends string = 'x',
+ Y extends string = 'y'
+>(
+ configObject: HeatmapConfiguration
+): Heatmap;
+
+export function register(pluginKey: string, plugin: any): void;
+
+/**
+ * Heatmap instances are returned by h337.create. A heatmap instance has its own
+ * internal datastore and renderer where you can manipulate data. As a result
+ * the heatmap gets updated (either partially or completely, depending on
+ * whether it's necessary).
+ */
+export class Heatmap {
+ /**
+ * Use this functionality only for adding datapoints on the fly, not for data
+ * initialization! heatmapInstance.addData adds a single or multiple
+ * datapoints to the heatmap's datastore.
+ *
+ * @example A single datapoint
+ *
+ * var dataPoint = {
+ * x: 5, // x coordinate of the datapoint, a number
+ * y: 5, // y coordinate of the datapoint, a number
+ * value: 100 // the value at datapoint(x, y)
+ * };
+ * heatmapInstance.addData(dataPoint);
+ *
+ * @example multiple datapoints
+ *
+ * // for data initialization use setData!!
+ * var dataPoints = [dataPoint, dataPoint, dataPoint, dataPoint];
+ * heatmapInstance.addData(dataPoints);
+ */
+ addData(dataPoint: DataPoint | ReadonlyArray>): this;
+
+ /**
+ * Initialize a heatmap instance with the given dataset. Removes all
+ * previously existing points from the heatmap instance and re-initializes
+ * the datastore.
+ *
+ * @example
+ *
+ * var data = {
+ * max: 100,
+ * min: 0,
+ * data: [
+ * dataPoint, dataPoint, dataPoint, dataPoint
+ * ]
+ * };
+ * heatmapInstance.setData(data);
+ */
+ setData(data: HeatmapData>): this;
+
+ /**
+ * Changes the upper bound of your dataset and triggers a complete
+ * rerendering.
+ *
+ * @example
+ *
+ * heatmapInstance.setDataMax(200);
+ * // setting the maximum value triggers a complete rerendering of the heatmap
+ * heatmapInstance.setDataMax(100);
+ */
+ setDataMax(number: number): this;
+
+ /**
+ * Changes the lower bound of your dataset and triggers a complete
+ * rerendering.
+ *
+ * @example
+ *
+ * heatmapInstance.setDataMin(10);
+ * // setting the minimum value triggers a complete rerendering of the heatmap
+ * heatmapInstance.setDataMin(0);
+ */
+ setDataMin(number: number): this;
+
+ /**
+ * Reconfigures a heatmap instance after it has been initialized. Triggers a
+ * complete rerendering.
+ *
+ * NOTE: This returns a reference to itself, but also offers an opportunity
+ * to change the `xField`, `yField` and `valueField` options, which can
+ * change the type of the `Heatmap` instance.
+ *
+ * @example
+ *
+ * var nuConfig = {
+ * radius: 10,
+ * maxOpacity: .5,
+ * minOpacity: 0,
+ * blur: .75
+ * };
+ * heatmapInstance.configure(nuConfig);
+ */
+ configure<
+ Vn extends string = V,
+ Xn extends string = X,
+ Yn extends string = Y
+ >(configObject: HeatmapConfiguration): Heatmap;
+
+ /**
+ * Returns value at datapoint position.
+ *
+ * The returned value is an interpolated value based on the gradient blending
+ * if point is not in store.
+ *
+ * @example
+ *
+ * heatmapInstance.addData({ x: 10, y: 10, value: 100});
+ * // get the value at x=10, y=10
+ * heatmapInstance.getValueAt({ x: 10, y: 10 }); // returns 100
+ */
+ getValueAt(point: { x: number, y: number }): number;
+
+ /**
+ * Returns a persistable and reimportable (with setData) JSON object.
+ *
+ * @example
+ *
+ * var currentData = heatmapInstance.getData();
+ * // now let's create a new instance and set the data
+ * var heatmap2 = h337.create(config);
+ * heatmap2.setData(currentData); // now both heatmap instances have the same content
+ */
+ getData(): HeatmapData;
+
+ /**
+ * Returns dataURL string.
+ *
+ * The returned value is the base64 encoded dataURL of the heatmap instance.
+ *
+ * @example
+ *
+ * heatmapInstance.getDataURL(); // data:image/png;base64...
+ * // ready for saving locally or on the server
+ */
+ getDataURL(): string;
+
+ /**
+ * Repaints the whole heatmap canvas.
+ */
+ repaint(): this;
+}
+
+export interface BaseHeatmapConfiguration {
+ /**
+ * A background color string in form of hexcode, color name, or rgb(a)
+ */
+ backgroundColor?: string;
+
+ /**
+ * The blur factor that will be applied to all datapoints. The higher the
+ * blur factor is, the smoother the gradients will be
+ * Default value: 0.85
+ */
+ blur?: number;
+
+ /**
+ * An object that represents the gradient.
+ * Syntax: {[key: number in range [0,1]]: color}
+ */
+ gradient?: { [key: string]: string };
+
+ /**
+ * The maximal opacity the highest value in the heatmap will have. (will be
+ * overridden if opacity set)
+ * Default value: 0.6
+ */
+ maxOpacity?: number;
+
+ /**
+ * The minimum opacity the lowest value in the heatmap will have (will be
+ * overridden if opacity set)
+ */
+ minOpacity?: number;
+
+ /**
+ * A global opacity for the whole heatmap. This overrides maxOpacity and
+ * minOpacity if set
+ * Default value: 0.6
+ */
+ opacity?: number;
+
+ /**
+ * The radius each datapoint will have (if not specified on the datapoint
+ * itself)
+ */
+ radius?: number;
+
+ /**
+ * Scales the radius based on map zoom.
+ */
+ scaleRadius?: boolean;
+
+ /**
+ * The property name of the value/weight in a datapoint
+ * Default value: 'value'
+ */
+ valueField?: V;
+
+ /**
+ * Pass a callback to receive extrema change updates. Useful for DOM
+ * legends.
+ */
+ onExtremaChange?: () => void;
+
+ /**
+ * Indicate whether the heatmap should use a global extrema or a local
+ * extrema (the maximum and minimum of the currently displayed viewport)
+ */
+ useLocalExtrema?: boolean;
+}
+
+/**
+ * Configuration object of a heatmap
+ */
+export interface HeatmapConfiguration<
+ V extends string = 'value',
+ X extends string = 'x',
+ Y extends string = 'y',
+> extends BaseHeatmapConfiguration {
+ /**
+ * A DOM node where the heatmap canvas should be appended (heatmap will adapt to
+ * the node's size)
+ */
+ container: HTMLElement;
+
+ /**
+ * The property name of your x coordinate in a datapoint
+ * Default value: 'x'
+ */
+ xField?: X;
+
+ /**
+ * The property name of your y coordinate in a datapoint
+ * Default value: 'y'
+ */
+ yField?: Y;
+}
+
+export interface HeatmapOverlayConfiguration<
+ V extends string = 'value',
+ TLat extends string = 'lat',
+ TLong extends string = 'lng',
+> extends BaseHeatmapConfiguration {
+ /**
+ * The property name of your latitude coordinate in a datapoint
+ * Default value: 'x'
+ */
+ latField?: TLat;
+
+ /**
+ * The property name of your longitude coordinate in a datapoint
+ * Default value: 'y'
+ */
+ lngField?: TLong;
+}
+
+/**
+ * A single data point on a heatmap. The interface of the data point can be
+ * overridden by providing alternative values for `xKey` and `yKey` in the
+ * config object.
+ */
+export type DataPoint<
+ V extends string = 'value',
+ X extends string = 'x',
+ Y extends string = 'y',
+> = Record;
+
+/**
+ * Type of data returned by `Heatmap#hello`, which ignores custom `xField`,
+ * `yField` and `valueField`.
+ */
+export interface DataCircle {
+ x: number;
+ y: number;
+ value: number;
+ radius: number;
+}
+
+/**
+ * An object representing the set of data points on a heatmap
+ */
+export interface HeatmapData {
+ /**
+ * An array of data points
+ */
+ data: ReadonlyArray;
+
+ /**
+ * Max value of the valueField
+ */
+ max: number;
+
+ /**
+ * Min value of the valueField
+ */
+ min: number;
+}
diff --git a/package.json b/package.json
index 498f1a09..2029595d 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,9 @@
{
- "name": "heatmap.js",
- "version": "2.0.5",
+ "name": "@mars3d/heatmap.js",
+ "version": "2.0.7",
"description": "Dynamic JavaScript Heatmaps for the Web",
- "homepage": "https://www.patrick-wied.at/static/heatmapjs/",
- "author": {
- "name": "Patrick Wied",
- "email": "heatmapjs@patrick-wied.at",
- "url": "https://www.patrick-wied.at/"
- },
"main": "build/heatmap.js",
+ "types": "index.d.ts",
"devDependencies": {
"grunt": ">= 0.4.1",
"coffee-script": ">= 1.6.3",
@@ -17,6 +12,14 @@
"grunt-contrib-watch": "0.2.0rc7",
"grunt-contrib-jshint": ">= 0.3.0"
},
+ "scripts": {
+ "build": "grunt build",
+ "push": "npm publish --access public"
+ },
+ "files": [
+ "build",
+ "index.d.ts"
+ ],
"keywords": [
"heatmap",
"heatmaps",
@@ -26,21 +29,18 @@
"leaflet heatmap",
"leaflet"
],
- "files": [
- "build",
- "plugins",
- "examples",
- "docs",
- "package.json",
- "LICENSE",
- "README.md"
- ],
- "buildFiles": [
- "src/config.js",
- "src/data.js",
- "src/renderer/canvas2d.js",
- "src/renderer.js",
- "src/util.js",
- "src/core.js"
- ]
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/muyao1987/heatmap.js.git"
+ },
+ "bugs": {
+ "url": "https://github.com/muyao1987/heatmap.js/issues",
+ "email": "wh@marsgis.cn"
+ },
+ "author": {
+ "name": "火星科技 木遥",
+ "url": "http://www.marsgis.cn"
+ },
+ "license": "ISC",
+ "homepage": "https://github.com/muyao1987/heatmap.js"
}
diff --git a/src/renderer/canvas2d.js b/src/renderer/canvas2d.js
index 259c8d14..f55746c5 100644
--- a/src/renderer/canvas2d.js
+++ b/src/renderer/canvas2d.js
@@ -4,7 +4,7 @@ var Canvas2dRenderer = (function Canvas2dRendererClosure() {
var _getColorPalette = function(config) {
var gradientConfig = config.gradient || config.defaultGradient;
var paletteCanvas = document.createElement('canvas');
- var paletteCtx = paletteCanvas.getContext('2d');
+ var paletteCtx = paletteCanvas.getContext('2d', { willReadFrequently: true });
paletteCanvas.width = 256;
paletteCanvas.height = 1;
@@ -22,7 +22,7 @@ var Canvas2dRenderer = (function Canvas2dRendererClosure() {
var _getPointTemplate = function(radius, blurFactor) {
var tplCanvas = document.createElement('canvas');
- var tplCtx = tplCanvas.getContext('2d');
+ var tplCtx = tplCanvas.getContext('2d', { willReadFrequently: true });
var x = radius;
var y = radius;
tplCanvas.width = tplCanvas.height = radius*2;
@@ -93,8 +93,8 @@ var Canvas2dRenderer = (function Canvas2dRendererClosure() {
this._width = canvas.width = shadowCanvas.width = config.width || +(computed.width.replace(/px/,''));
this._height = canvas.height = shadowCanvas.height = config.height || +(computed.height.replace(/px/,''));
- this.shadowCtx = shadowCanvas.getContext('2d');
- this.ctx = canvas.getContext('2d');
+ this.shadowCtx = shadowCanvas.getContext('2d', { willReadFrequently: true });
+ this.ctx = canvas.getContext('2d', { willReadFrequently: true });
// @TODO:
// conditional wrapper
@@ -277,7 +277,7 @@ var Canvas2dRenderer = (function Canvas2dRendererClosure() {
}
- img.data = imgData;
+ // img.data = imgData;
this.ctx.putImageData(img, x, y);
this._renderBoundaries = [1000, 1000, 0, 0];