├── .jshintrc
├── MIT-LICENSE.txt
├── README.md
├── index.html
├── license.txt
└── src
├── HeatmapLayer.js
└── heatmap.js
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "undef": true,
3 | "browser":true,
4 | "devel":true,
5 | "globals": { "require": false, "define":false }
6 | }
--------------------------------------------------------------------------------
/MIT-LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2012 Esri and other contributors
2 | http://esri.com/
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | "Software"), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # heatmap-layer-js
2 |
3 | This is a custom DynamicMapServiceLayer for Heatmap.js to work with the ArcGIS Javascript API.
4 |
5 | [View it live](http://esri.github.com/heatmap-layer-js/)
6 |
7 | ## Features
8 | [http://www.patrick-wied.at/static/heatmapjs/](http://www.patrick-wied.at/static/heatmapjs/)
9 | heatmap.js is a JavaScript library that can be used to generate web heatmaps with the html5canvas element based on your data. Heatmap instances contain a store in order to colorize the heatmap based on relative data, which means if you're adding only a single datapoint to the store it will be displayed as the hottest(red) spot, then adding another point with a higher count, it will dynamically recalculate. The heatmaps are fully customizable - you're welcome to choose your own color gradient, change its opacity, datapoint radius and many more.
10 |
11 | ## Instructions
12 | See example HTML file included in download.
13 |
14 | [New to Github? Get started here.](https://github.com/)
15 |
16 | ## Requirements
17 |
18 | * Notepad or HTML editor
19 | * A little background with Javascript
20 | * Experience with the [ArcGIS Javascript API](http://www.esri.com/) would help.
21 |
22 | ## Resources
23 |
24 | * [ArcGIS for JavaScript API Resource Center](http://help.arcgis.com/en/webapi/javascript/arcgis/index.html)
25 | * [ArcGIS Blog](http://blogs.esri.com/esri/arcgis/)
26 | * [twitter@esri](http://twitter.com/esri)
27 |
28 | ## Issues
29 |
30 | Find a bug or want to request a new feature? Please let us know by submitting an issue.
31 |
32 | ## Contributing
33 |
34 | Anyone and everyone is welcome to contribute.
35 |
36 | ## Licensing
37 |
38 | Copyright 2017 Esri
39 |
40 | Licensed under the Apache License, Version 2.0 (the "License");
41 | you may not use this file except in compliance with the License.
42 | You may obtain a copy of the License at
43 |
44 | http://www.apache.org/licenses/LICENSE-2.0
45 |
46 | Unless required by applicable law or agreed to in writing, software
47 | distributed under the License is distributed on an "AS IS" BASIS,
48 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
49 | See the License for the specific language governing permissions and
50 | limitations under the License.
51 |
52 | A copy of the license is available in the repository's [license.txt](https://raw.github.com/Esri/heatmap-layer-js/master/license.txt) file.
53 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Now you just need to add data points to the heatmap. In the example above,
155 | I am adding features from a feature layer of 311 incidents. Here's an example with
156 | two features.
I created a function that executes on map pan that gets all the features
184 | from a featureLayer within the map's extent.
185 |
186 | function getFeatures() {
187 | // set up query
188 | var q = new Query();
189 | // only within extent
190 | q.geometry = map.extent;
191 | // give me all of them!
192 | q.where = "1=1";
193 | // make sure I get them back in my spatial reference
194 | q.outSpatialReference = map.spatialReference;
195 | // get em!
196 | featureLayer.queryFeatures(q, function (featureSet) {
197 | var data = [];
198 | // if we get results back
199 | if (featureSet && featureSet.features && featureSet.features.length > 0) {
200 | // set data to features
201 | data = featureSet.features;
202 | }
203 | // set heatmap data
204 | heatLayer.setData(data);
205 | });
206 | }
207 |
223 |
224 |
238 |
239 |
240 |
364 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | Apache License - 2.0
2 |
3 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
4 |
5 | 1. Definitions.
6 |
7 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
8 |
9 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
10 |
11 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control
12 | with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management
13 | of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial
14 | ownership of such entity.
15 |
16 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
17 |
18 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source,
19 | and configuration files.
20 |
21 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to
22 | compiled object code, generated documentation, and conversions to other media types.
23 |
24 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice
25 | that is included in or attached to the work (an example is provided in the Appendix below).
26 |
27 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the
28 | editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes
29 | of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of,
30 | the Work and Derivative Works thereof.
31 |
32 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work
33 | or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual
34 | or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of
35 | electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on
36 | electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for
37 | the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing
38 | by the copyright owner as "Not a Contribution."
39 |
40 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and
41 | subsequently incorporated within the Work.
42 |
43 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
44 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display,
45 | publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
46 |
47 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide,
48 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell,
49 | sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are
50 | necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was
51 | submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work
52 | or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You
53 | under this License for that Work shall terminate as of the date such litigation is filed.
54 |
55 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications,
56 | and in Source or Object form, provided that You meet the following conditions:
57 |
58 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
59 |
60 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and
61 |
62 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices
63 | from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
64 |
65 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a
66 | readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the
67 | Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the
68 | Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever
69 | such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License.
70 | You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work,
71 | provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to
72 | Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your
73 | modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with
74 | the conditions stated in this License.
75 |
76 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You
77 | to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above,
78 | nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
79 |
80 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except
81 | as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
82 |
83 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides
84 | its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation,
85 | any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for
86 | determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under
87 | this License.
88 |
89 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required
90 | by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages,
91 | including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the
92 | use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or
93 | any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
94 |
95 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a
96 | fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting
97 | such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree
98 | to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your
99 | accepting any such warranty or additional liability.
100 |
101 | END OF TERMS AND CONDITIONS
102 |
--------------------------------------------------------------------------------
/src/HeatmapLayer.js:
--------------------------------------------------------------------------------
1 | /* global h337 */
2 | define([
3 | "dojo/_base/declare",
4 | "dojo/_base/lang",
5 | "dijit/_WidgetBase",
6 | "dojo/dom",
7 | "dojo/query",
8 | "dojo/dom-style",
9 | "dojo/on",
10 | "esri/layers/DynamicMapServiceLayer",
11 | "esri/geometry/screenUtils",
12 | "esri/geometry/Point"
13 | ], function(
14 | declare, lang,
15 | _WidgetBase,
16 | dom,
17 | query,
18 | domStyle,
19 | on,
20 | DynamicMapServiceLayer,
21 | screenUtils,
22 | Point
23 | ) {
24 | return declare([_WidgetBase, DynamicMapServiceLayer], {
25 | options: {
26 | useLocalMaximum: false,
27 | map: null,
28 | config:{
29 | radius: 40,
30 | debug: false,
31 | visible: true,
32 | gradient: {
33 | 0.45: "rgb(000,000,255)",
34 | 0.55: "rgb(000,255,255)",
35 | 0.65: "rgb(000,255,000)",
36 | 0.95: "rgb(255,255,000)",
37 | 1.00: "rgb(255,000,000)"
38 | }
39 | }
40 | },
41 | // constructor
42 | constructor: function(options, srcNode) {
43 | // last data storage
44 | this.set("data", []);
45 | // map node
46 | this.domNode = dom.byId(srcNode);
47 | // defaults
48 | var defaults = lang.mixin({}, this.options, options);
49 | // map var
50 | this.set("map", defaults.map);
51 | this.set("useLocalMaximum", defaults.useLocalMaximum);
52 | defaults.config.height = this.get("map").height;
53 | defaults.config.width = this.get("map").width;
54 | defaults.config.container = this.domNode;
55 | this.set("config", defaults.config);
56 | // create heatmap
57 | this.heatMap = h337.create(this.get("config"));
58 | // global maximum value
59 | this.set("globalMax", 0);
60 | // connect on resize
61 | this.own(on(this.get("map"), "resize", lang.hitch(this, function(evt) {
62 | this.resizeHeatmap(evt.width, evt.height);
63 | })));
64 | // heatlayer div styling
65 | domStyle.set(this.domNode, {
66 | position: "absolute",
67 | display: "none"
68 | });
69 | // loaded
70 | this.set("loaded",true);
71 | this.inherited(arguments);
72 | },
73 | resizeHeatmap: function(width, height) {
74 | // set heatmap data size
75 |
76 | this.heatMap._renderer.setDimensions(width,height);
77 | //this.heatMap.set("width", width);
78 | //this.heatMap.set("height", height);
79 | // set width and height of container
80 | domStyle.set(this.domNode, {
81 | "width": width + 'px',
82 | "height": height + 'px'
83 | });
84 | // set width and height of canvas element inside of container
85 | var child = query(':first-child', this.domNode);
86 | if (child) {
87 | child.attr('width', width);
88 | child.attr('height', height);
89 | }
90 | // set atx canvas width and height fix
91 | /* var actx = this.heatMap._renderer.shadowCtx;
92 | actx.canvas.height = height;
93 | actx.canvas.width = width;
94 | this.heatMap._renderer.shadowCtx = actx;*/
95 | // refresh image and heat map size
96 | this.refresh();
97 | },
98 | // stores heatmap converted data into the plugin which renders it
99 | storeHeatmapData: function(heatPluginData) {
100 | // set heatmap data
101 | this.heatMap.setData(heatPluginData);
102 | },
103 | // converts parsed data into heatmap format
104 | convertHeatmapData: function(parsedData) {
105 | // variables
106 | var xParsed, yParsed, heatPluginData, screenGeometry;
107 | // set heat plugin data object
108 | heatPluginData = {
109 | max: parsedData.max,
110 | data: [] // empty data
111 | };
112 | // if data
113 | if (parsedData.data) {
114 | // for all x values
115 | for (xParsed in parsedData.data) {
116 | // if data[x]
117 | if (parsedData.data.hasOwnProperty(xParsed)) {
118 | // for all y values and count
119 | for (yParsed in parsedData.data[xParsed]) {
120 | if (parsedData.data[xParsed].hasOwnProperty(yParsed)) {
121 | // make sure extent is normalized
122 | var normalizedExtent = this.map.extent._normalize();
123 | // convert data point into screen geometry
124 | screenGeometry = screenUtils.toScreenGeometry(normalizedExtent, this.get("map").width, this.get("map").height, parsedData.data[xParsed][yParsed].dataPoint);
125 | // push to heatmap plugin data array
126 | heatPluginData.data.push({
127 | x: screenGeometry.x,
128 | y: screenGeometry.y,
129 | count: parsedData.data[xParsed][yParsed].count // count value of x,y
130 | });
131 | }
132 | }
133 | }
134 | }
135 | }
136 | // store in heatmap plugin which will render it
137 | this.storeHeatmapData(heatPluginData);
138 | },
139 | // runs through data and calulates weights and max
140 | parseHeatmapData: function(features) {
141 | // variables
142 | var i, parsedData, dataPoint, attributes;
143 | // if data points exist
144 | if (features) {
145 | // create parsed data object
146 | parsedData = {
147 | max: 0,
148 | data: []
149 | };
150 | if (!this.get("useLocalMaximum")) {
151 | parsedData.max = this.get("globalMax");
152 | }
153 | // for each data point
154 | for (i = 0; i < features.length; i++) {
155 | // get geometry and normalize it
156 | var geo = features[i].geometry.normalize();
157 | // create geometry point
158 | dataPoint = new Point(geo.x, geo.y, this.get("map").spatialReference);
159 | // get extent and normalize it.
160 | var normalizedExtent = this.get("map").extent._normalize();
161 | // check point
162 | var validPoint = false;
163 | // if not using local max, point is valid
164 | if (!this.get("useLocalMaximum")) {
165 | validPoint = true;
166 | }
167 | // using local max, make sure point is within extent
168 | else if (normalizedExtent.contains(dataPoint)) {
169 | validPoint = true;
170 | }
171 | if (validPoint) {
172 | // attributes
173 | attributes = features[i].attributes;
174 | // if array value is undefined
175 | if (!parsedData.data[dataPoint.x]) {
176 | // create empty array value
177 | parsedData.data[dataPoint.x] = [];
178 | }
179 | // array value array is undefined
180 | if (!parsedData.data[dataPoint.x][dataPoint.y]) {
181 | // create object in array
182 | parsedData.data[dataPoint.x][dataPoint.y] = {};
183 | // if count is defined in datapoint
184 | if (attributes && attributes.hasOwnProperty('count')) {
185 | // create array value with count of count set in datapoint
186 | parsedData.data[dataPoint.x][dataPoint.y].count = attributes.count;
187 | } else {
188 | // create array value with count of 0
189 | parsedData.data[dataPoint.x][dataPoint.y].count = 0;
190 | }
191 | }
192 | // add 1 to the count
193 | parsedData.data[dataPoint.x][dataPoint.y].count += 1;
194 | // store dataPoint var
195 | parsedData.data[dataPoint.x][dataPoint.y].dataPoint = dataPoint;
196 | // if count is greater than current max
197 | if (parsedData.max < parsedData.data[dataPoint.x][dataPoint.y].count) {
198 | // set max to this count
199 | parsedData.max = parsedData.data[dataPoint.x][dataPoint.y].count;
200 | if (!this.get("useLocalMaximum")) {
201 | this.set("globalMax", parsedData.data[dataPoint.x][dataPoint.y].count);
202 | }
203 | }
204 | }
205 | }
206 | // convert parsed data into heatmap plugin formatted data
207 | this.convertHeatmapData(parsedData);
208 | }
209 | },
210 | // set data function call
211 | setData: function(features) {
212 | // set width/height
213 | this.resizeHeatmap(this.get("map").width, this.get("map").height);
214 | // store points
215 | this.set("data", features);
216 | // create data and then store it
217 | this.parseHeatmapData(features);
218 | // redraws the heatmap
219 | this.refresh();
220 | },
221 | // add one feature to the heatmap
222 | addDataPoint: function(feature) {
223 | if (feature) {
224 | // push to data
225 | var data = this.get("data");
226 | data.push(feature);
227 | // set data
228 | this.setData(data);
229 | }
230 | },
231 | // return data set of features
232 | exportDataSet: function() {
233 | return this.get("data");
234 | },
235 | // clear data function
236 | clearData: function() {
237 | // empty heat map
238 | this.heatMap.clear();
239 | // empty array
240 | var empty = [];
241 | // set data to empty array
242 | this.setData(empty);
243 | },
244 | // get image
245 | getImageUrl: function(extent, width, height, callback) {
246 | // create heatmap data using last data
247 | this.parseHeatmapData(this.get("data"));
248 | // image data
249 | var imageUrl = this.heatMap.getDataURL();
250 | // callback
251 | callback(imageUrl);
252 | }
253 | });
254 | });
--------------------------------------------------------------------------------
/src/heatmap.js:
--------------------------------------------------------------------------------
1 | /*
2 | * heatmap.js v2.0.0 | JavaScript Heatmap Library
3 | *
4 | * Copyright 2008-2014 Patrick Wied - All rights reserved.
5 | * Dual licensed under MIT and Beerware license
6 | *
7 | * :: 2014-08-05 01:42
8 | */
9 | (function(a){var b={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 c=function i(){var a=function d(a){this._coordinator={};this._data=[];this._radi=[];this._min=0;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=b.defaultRadius;a.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}if(g[d][e]>h){if(!b){this._max=g[d][e]}else{this.setDataMax(g[d][e])}return false}else{return{x:d,y:e,value:j,radius:k,min:i,max:h}}},_unOrganizeData:function(){var a=[];var b=this._data;var c=this._radi;for(var d in b){for(var e in b[d]){a.push({x:d,y:e,radius:c[d][e],value:b[d][e]})}}return{min:this._min,max:this._max,data:a}},_onExtremaChange:function(){this._coordinator.emit("extremachange",{min:this._min,max:this._max})},addData:function(){if(arguments[0].length>0){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){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._max=a.max;this._min=a.min||0;this._data=[];this._radi=[];for(var d=0;dthis._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;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 j=this.shadowCtx.getImageData(a,b,c,d);var k=j.data;var l=k.length;var m=this._palette;for(var n=3;n0){q=g}else{if(o>0;return b},getDataURL:function(){return this.canvas.toDataURL()}};return d}();var e=function k(){var a=false;if(b["defaultRenderer"]==="canvas2d"){a=d}return a}();var f={merge:function(){var a={};var b=arguments.length;for(var c=0;c