CesiumHeatmap.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. /*
  2. * CesiumHeatmap.js v0.1 | Cesium Heatmap Library
  3. *
  4. * Works with heatmap.js v2.0.0: http://www.patrick-wied.at/static/heatmapjs/
  5. */
  6. (function (window) {
  7. 'use strict';
  8. function define_CesiumHeatmap() {
  9. var CesiumHeatmap = {
  10. defaults: {
  11. useEntitiesIfAvailable: true, //whether to use entities if a Viewer is supplied or always use an ImageryProvider
  12. minCanvasSize: 700, // minimum size (in pixels) for the heatmap canvas
  13. maxCanvasSize: 2000, // maximum size (in pixels) for the heatmap canvas
  14. radiusFactor: 60, // data point size factor used if no radius is given (the greater of height and width divided by this number yields the used radius)
  15. spacingFactor: 1.5, // extra space around the borders (point radius multiplied by this number yields the spacing)
  16. maxOpacity: 0.8, // the maximum opacity used if not given in the heatmap options object
  17. minOpacity: 0.1, // the minimum opacity used if not given in the heatmap options object
  18. blur: 0.85, // the blur used if not given in the heatmap options object
  19. gradient: { // the gradient used if not given in the heatmap options object
  20. '.3': 'blue',
  21. '.65': 'yellow',
  22. '.8': 'orange',
  23. '.95': 'red'
  24. },
  25. }
  26. };
  27. /* Create a CesiumHeatmap instance
  28. *
  29. * cesium: the CesiumWidget or Viewer instance
  30. * bb: the WGS84 bounding box like {north, east, south, west}
  31. * options: a heatmap.js options object (see http://www.patrick-wied.at/static/heatmapjs/docs.html#h337-create)
  32. */
  33. CesiumHeatmap.create = function (cesium, bb, options) {
  34. var instance = new CHInstance(cesium, bb, options);
  35. return instance;
  36. };
  37. CesiumHeatmap._getContainer = function (width, height, id) {
  38. var c = document.createElement("div");
  39. if (id) {
  40. c.setAttribute("id", id);
  41. }
  42. c.setAttribute("style", "width: " + width + "px; height: " + height + "px; margin: 0px; display: none;");
  43. document.body.appendChild(c);
  44. return c;
  45. };
  46. CesiumHeatmap._getImageryProvider = function (instance) {
  47. //var n = (new Date()).getTime();
  48. var d = instance._heatmap.getDataURL();
  49. //console.log("Create data URL: " + ((new Date()).getTime() - n));
  50. //var n = (new Date()).getTime();
  51. var imgprov = new Cesium.SingleTileImageryProvider({
  52. url: d,
  53. rectangle: instance._rectangle
  54. });
  55. //console.log("Create imageryprovider: " + ((new Date()).getTime() - n));
  56. imgprov._tilingScheme = new Cesium.WebMercatorTilingScheme({
  57. rectangleSouthwestInMeters: new Cesium.Cartesian2(instance._mbounds.west, instance._mbounds.south),
  58. rectangleNortheastInMeters: new Cesium.Cartesian2(instance._mbounds.east, instance._mbounds.north)
  59. });
  60. return imgprov;
  61. };
  62. CesiumHeatmap._getID = function (len) {
  63. var text = "";
  64. var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  65. for (var i = 0; i < ((len) ? len : 8); i++)
  66. text += possible.charAt(Math.floor(Math.random() * possible.length));
  67. return text;
  68. };
  69. var WMP = new Cesium.WebMercatorProjection();
  70. /* Convert a WGS84 location into a mercator location
  71. *
  72. * p: the WGS84 location like {x: lon, y: lat}
  73. */
  74. CesiumHeatmap.wgs84ToMercator = function (p) {
  75. var mp = WMP.project(Cesium.Cartographic.fromDegrees(p.x, p.y));
  76. return {
  77. x: mp.x,
  78. y: mp.y
  79. };
  80. };
  81. /* Convert a WGS84 bounding box into a mercator bounding box
  82. *
  83. * bb: the WGS84 bounding box like {north, east, south, west}
  84. */
  85. CesiumHeatmap.wgs84ToMercatorBB = function (bb) {
  86. var sw = WMP.project(Cesium.Cartographic.fromDegrees(bb.west, bb.south));
  87. var ne = WMP.project(Cesium.Cartographic.fromDegrees(bb.east, bb.north));
  88. return {
  89. north: ne.y,
  90. east: ne.x,
  91. south: sw.y,
  92. west: sw.x
  93. };
  94. };
  95. /* Convert a mercator location into a WGS84 location
  96. *
  97. * p: the mercator lcation like {x, y}
  98. */
  99. CesiumHeatmap.mercatorToWgs84 = function (p) {
  100. var wp = WMP.unproject(new Cesium.Cartesian3(p.x, p.y));
  101. return {
  102. x: wp.longitude,
  103. y: wp.latitude
  104. };
  105. };
  106. /* Convert a mercator bounding box into a WGS84 bounding box
  107. *
  108. * bb: the mercator bounding box like {north, east, south, west}
  109. */
  110. CesiumHeatmap.mercatorToWgs84BB = function (bb) {
  111. var sw = WMP.unproject(new Cesium.Cartesian3(bb.west, bb.south));
  112. var ne = WMP.unproject(new Cesium.Cartesian3(bb.east, bb.north));
  113. return {
  114. north: this.rad2deg(ne.latitude),
  115. east: this.rad2deg(ne.longitude),
  116. south: this.rad2deg(sw.latitude),
  117. west: this.rad2deg(sw.longitude)
  118. };
  119. };
  120. /* Convert degrees into radians
  121. *
  122. * d: the degrees to be converted to radians
  123. */
  124. CesiumHeatmap.deg2rad = function (d) {
  125. var r = d * (Math.PI / 180.0);
  126. return r;
  127. };
  128. /* Convert radians into degrees
  129. *
  130. * r: the radians to be converted to degrees
  131. */
  132. CesiumHeatmap.rad2deg = function (r) {
  133. var d = r / (Math.PI / 180.0);
  134. return d;
  135. };
  136. return CesiumHeatmap;
  137. }
  138. if (typeof(CesiumHeatmap) === 'undefined') {
  139. window.CesiumHeatmap = define_CesiumHeatmap();
  140. } else {
  141. console.log("CesiumHeatmap already defined.");
  142. }
  143. })(window);
  144. /* Initiate a CesiumHeatmap instance
  145. *
  146. * c: CesiumWidget instance
  147. * bb: a WGS84 bounding box like {north, east, south, west}
  148. * o: a heatmap.js options object (see http://www.patrick-wied.at/static/heatmapjs/docs.html#h337-create)
  149. */
  150. function CHInstance(c, bb, o) {
  151. if (!bb) {
  152. return null;
  153. }
  154. if (!o) {
  155. o = {};
  156. }
  157. this._cesium = c;
  158. this._options = o;
  159. this._id = CesiumHeatmap._getID();
  160. this._options.gradient = ((this._options.gradient) ? this._options.gradient : CesiumHeatmap.defaults.gradient);
  161. this._options.maxOpacity = ((this._options.maxOpacity) ? this._options.maxOpacity : CesiumHeatmap.defaults.maxOpacity);
  162. this._options.minOpacity = ((this._options.minOpacity) ? this._options.minOpacity : CesiumHeatmap.defaults.minOpacity);
  163. this._options.blur = ((this._options.blur) ? this._options.blur : CesiumHeatmap.defaults.blur);
  164. this._mbounds = CesiumHeatmap.wgs84ToMercatorBB(bb);
  165. this._setWidthAndHeight(this._mbounds);
  166. this._options.radius = Math.round((this._options.radius) ? this._options.radius : ((this.width > this.height) ? this.width / CesiumHeatmap.defaults.radiusFactor : this.height / CesiumHeatmap.defaults.radiusFactor));
  167. this._spacing = this._options.radius * CesiumHeatmap.defaults.spacingFactor;
  168. this._xoffset = this._mbounds.west;
  169. this._yoffset = this._mbounds.south;
  170. this.width = Math.round(this.width + this._spacing * 2);
  171. this.height = Math.round(this.height + this._spacing * 2);
  172. this._mbounds.west -= this._spacing * this._factor;
  173. this._mbounds.east += this._spacing * this._factor;
  174. this._mbounds.south -= this._spacing * this._factor;
  175. this._mbounds.north += this._spacing * this._factor;
  176. this.bounds = CesiumHeatmap.mercatorToWgs84BB(this._mbounds);
  177. this._rectangle = Cesium.Rectangle.fromDegrees(this.bounds.west, this.bounds.south, this.bounds.east, this.bounds.north);
  178. this._container = CesiumHeatmap._getContainer(this.width, this.height, this._id);
  179. this._options.container = this._container;
  180. this._heatmap = h337.create(this._options);
  181. this._container.children[0].setAttribute("id", this._id + "-hm");
  182. }
  183. /* Convert a WGS84 location to the corresponding heatmap location
  184. *
  185. * p: a WGS84 location like {x:lon, y:lat}
  186. */
  187. CHInstance.prototype.wgs84PointToHeatmapPoint = function (p) {
  188. return this.mercatorPointToHeatmapPoint(CesiumHeatmap.wgs84ToMercator(p));
  189. };
  190. /* Convert a mercator location to the corresponding heatmap location
  191. *
  192. * p: a WGS84 location like {x: lon, y:lat}
  193. */
  194. CHInstance.prototype.mercatorPointToHeatmapPoint = function (p) {
  195. var pn = {};
  196. pn.x = Math.round((p.x - this._xoffset) / this._factor + this._spacing);
  197. pn.y = Math.round((p.y - this._yoffset) / this._factor + this._spacing);
  198. pn.y = this.height - pn.y;
  199. return pn;
  200. };
  201. CHInstance.prototype._setWidthAndHeight = function (mbb) {
  202. this.width = ((mbb.east > 0 && mbb.west < 0) ? mbb.east + Math.abs(mbb.west) : Math.abs(mbb.east - mbb.west));
  203. this.height = ((mbb.north > 0 && mbb.south < 0) ? mbb.north + Math.abs(mbb.south) : Math.abs(mbb.north - mbb.south));
  204. this._factor = 1;
  205. if (this.width > this.height && this.width > CesiumHeatmap.defaults.maxCanvasSize) {
  206. this._factor = this.width / CesiumHeatmap.defaults.maxCanvasSize;
  207. if (this.height / this._factor < CesiumHeatmap.defaults.minCanvasSize) {
  208. this._factor = this.height / CesiumHeatmap.defaults.minCanvasSize;
  209. }
  210. } else if (this.height > this.width && this.height > CesiumHeatmap.defaults.maxCanvasSize) {
  211. this._factor = this.height / CesiumHeatmap.defaults.maxCanvasSize;
  212. if (this.width / this._factor < CesiumHeatmap.defaults.minCanvasSize) {
  213. this._factor = this.width / CesiumHeatmap.defaults.minCanvasSize;
  214. }
  215. } else if (this.width < this.height && this.width < CesiumHeatmap.defaults.minCanvasSize) {
  216. this._factor = this.width / CesiumHeatmap.defaults.minCanvasSize;
  217. if (this.height / this._factor > CesiumHeatmap.defaults.maxCanvasSize) {
  218. this._factor = this.height / CesiumHeatmap.defaults.maxCanvasSize;
  219. }
  220. } else if (this.height < this.width && this.height < CesiumHeatmap.defaults.minCanvasSize) {
  221. this._factor = this.height / CesiumHeatmap.defaults.minCanvasSize;
  222. if (this.width / this._factor > CesiumHeatmap.defaults.maxCanvasSize) {
  223. this._factor = this.width / CesiumHeatmap.defaults.maxCanvasSize;
  224. }
  225. }
  226. this.width = this.width / this._factor;
  227. this.height = this.height / this._factor;
  228. };
  229. /* Set an array of heatmap locations
  230. *
  231. * min: the minimum allowed value for the data values
  232. * max: the maximum allowed value for the data values
  233. * data: an array of data points in heatmap coordinates and values like {x, y, value}
  234. */
  235. CHInstance.prototype.setData = function (min, max, data) {
  236. if (data && data.length > 0 && min !== null && min !== false && max !== null && max !== false) {
  237. this._heatmap.setData({
  238. min: min,
  239. max: max,
  240. data: data
  241. });
  242. this.updateLayer();
  243. return true;
  244. }
  245. return false;
  246. };
  247. /* Set an array of WGS84 locations
  248. *
  249. * min: the minimum allowed value for the data values
  250. * max: the maximum allowed value for the data values
  251. * data: an array of data points in WGS84 coordinates and values like { x:lon, y:lat, value }
  252. */
  253. CHInstance.prototype.setWGS84Data = function (min, max, data) {
  254. if (data && data.length > 0 && min !== null && min !== false && max !== null && max !== false) {
  255. var convdata = [];
  256. for (var i = 0; i < data.length; i++) {
  257. var gp = data[i];
  258. var hp = this.wgs84PointToHeatmapPoint(gp);
  259. if (gp.value || gp.value === 0) {
  260. hp.value = gp.value;
  261. }
  262. convdata.push(hp);
  263. }
  264. return this.setData(min, max, convdata);
  265. }
  266. return false;
  267. };
  268. /* Set whether or not the heatmap is shown on the map
  269. *
  270. * s: true means the heatmap is shown, false means the heatmap is hidden
  271. */
  272. CHInstance.prototype.show = function (s) {
  273. if (this._layer) {
  274. this._layer.show = s;
  275. }
  276. };
  277. /* Update/(re)draw the heatmap
  278. */
  279. CHInstance.prototype.updateLayer = function () {
  280. // only works with a Viewer instance since the cesiumWidget
  281. // instance doesn't contain an entities property
  282. if (CesiumHeatmap.defaults.useEntitiesIfAvailable && this._cesium.entities) {
  283. if (this._layer) {
  284. this._cesium.entities.remove(this._layer);
  285. }
  286. // Work around issue with material rendering in Cesium
  287. // provided by https://github.com/criis
  288. material = new Cesium.ImageMaterialProperty({
  289. image: this._heatmap._renderer.canvas,
  290. });
  291. if (Cesium.VERSION >= "1.21") {
  292. material.transparent = true;
  293. } else if (Cesium.VERSION >= "1.16") {
  294. material.alpha = 0.99;
  295. }
  296. this._layer = this._cesium.entities.add({
  297. show: true,
  298. rectangle: {
  299. coordinates: this._rectangle,
  300. material: material
  301. }
  302. });
  303. } else {
  304. if (this._layer) {
  305. this._cesium.scene.imageryLayers.remove(this._layer);
  306. }
  307. this._layer = this._cesium.scene.imageryLayers.addImageryProvider(CesiumHeatmap._getImageryProvider(this));
  308. }
  309. };
  310. /* DON'T TOUCH:
  311. *
  312. * heatmap.js v2.0.0 | JavaScript Heatmap Library: http://www.patrick-wied.at/static/heatmapjs/
  313. *
  314. * Copyright 2008-2014 Patrick Wied <heatmapjs@patrick-wied.at> - All rights reserved.
  315. * Dual licensed under MIT and Beerware license
  316. *
  317. * :: 2014-10-31 21:16
  318. */
  319. (function (a, b, c) {
  320. if (typeof module !== "undefined" && module.exports) {
  321. module.exports = c()
  322. } else if (typeof define === "function" && define.amd) {
  323. define(c)
  324. } else {
  325. b[a] = c()
  326. }
  327. })("h337", this, function () {
  328. var a = {
  329. defaultRadius: 40,
  330. defaultRenderer: "canvas2d",
  331. defaultGradient: {.25: "rgb(0,0,255)", .55: "rgb(0,255,0)", .85: "yellow", 1: "rgb(255,0,0)"},
  332. defaultMaxOpacity: 1,
  333. defaultMinOpacity: 0,
  334. defaultBlur: .85,
  335. defaultXField: "x",
  336. defaultYField: "y",
  337. defaultValueField: "value",
  338. plugins: {}
  339. };
  340. var b = function h() {
  341. var b = function d(a) {
  342. this._coordinator = {};
  343. this._data = [];
  344. this._radi = [];
  345. this._min = 0;
  346. this._max = 1;
  347. this._xField = a["xField"] || a.defaultXField;
  348. this._yField = a["yField"] || a.defaultYField;
  349. this._valueField = a["valueField"] || a.defaultValueField;
  350. if (a["radius"]) {
  351. this._cfgRadius = a["radius"]
  352. }
  353. };
  354. var c = a.defaultRadius;
  355. b.prototype = {
  356. _organiseData: function (a, b) {
  357. var d = a[this._xField];
  358. var e = a[this._yField];
  359. var f = this._radi;
  360. var g = this._data;
  361. var h = this._max;
  362. var i = this._min;
  363. var j = a[this._valueField] || 1;
  364. var k = a.radius || this._cfgRadius || c;
  365. if (!g[d]) {
  366. g[d] = [];
  367. f[d] = []
  368. }
  369. if (!g[d][e]) {
  370. g[d][e] = j;
  371. f[d][e] = k
  372. } else {
  373. g[d][e] += j
  374. }
  375. if (g[d][e] > h) {
  376. if (!b) {
  377. this._max = g[d][e]
  378. } else {
  379. this.setDataMax(g[d][e])
  380. }
  381. return false
  382. } else {
  383. return {x: d, y: e, value: j, radius: k, min: i, max: h}
  384. }
  385. }, _unOrganizeData: function () {
  386. var a = [];
  387. var b = this._data;
  388. var c = this._radi;
  389. for (var d in b) {
  390. for (var e in b[d]) {
  391. a.push({x: d, y: e, radius: c[d][e], value: b[d][e]})
  392. }
  393. }
  394. return {min: this._min, max: this._max, data: a}
  395. }, _onExtremaChange: function () {
  396. this._coordinator.emit("extremachange", {min: this._min, max: this._max})
  397. }, addData: function () {
  398. if (arguments[0].length > 0) {
  399. var a = arguments[0];
  400. var b = a.length;
  401. while (b--) {
  402. this.addData.call(this, a[b])
  403. }
  404. } else {
  405. var c = this._organiseData(arguments[0], true);
  406. if (c) {
  407. this._coordinator.emit("renderpartial", {min: this._min, max: this._max, data: [c]})
  408. }
  409. }
  410. return this
  411. }, setData: function (a) {
  412. var b = a.data;
  413. var c = b.length;
  414. this._data = [];
  415. this._radi = [];
  416. for (var d = 0; d < c; d++) {
  417. this._organiseData(b[d], false)
  418. }
  419. this._max = a.max;
  420. this._min = a.min || 0;
  421. this._onExtremaChange();
  422. this._coordinator.emit("renderall", this._getInternalData());
  423. return this
  424. }, removeData: function () {
  425. }, setDataMax: function (a) {
  426. this._max = a;
  427. this._onExtremaChange();
  428. this._coordinator.emit("renderall", this._getInternalData());
  429. return this
  430. }, setDataMin: function (a) {
  431. this._min = a;
  432. this._onExtremaChange();
  433. this._coordinator.emit("renderall", this._getInternalData());
  434. return this
  435. }, setCoordinator: function (a) {
  436. this._coordinator = a
  437. }, _getInternalData: function () {
  438. return {max: this._max, min: this._min, data: this._data, radi: this._radi}
  439. }, getData: function () {
  440. return this._unOrganizeData()
  441. }
  442. };
  443. return b
  444. }();
  445. var c = function i() {
  446. var a = function (a) {
  447. var b = a.gradient || a.defaultGradient;
  448. var c = document.createElement("canvas");
  449. var d = c.getContext("2d");
  450. c.width = 256;
  451. c.height = 1;
  452. var e = d.createLinearGradient(0, 0, 256, 1);
  453. for (var f in b) {
  454. e.addColorStop(f, b[f])
  455. }
  456. d.fillStyle = e;
  457. d.fillRect(0, 0, 256, 1);
  458. return d.getImageData(0, 0, 256, 1).data
  459. };
  460. var b = function (a, b) {
  461. var c = document.createElement("canvas");
  462. var d = c.getContext("2d");
  463. var e = a;
  464. var f = a;
  465. c.width = c.height = a * 2;
  466. if (b == 1) {
  467. d.beginPath();
  468. d.arc(e, f, a, 0, 2 * Math.PI, false);
  469. d.fillStyle = "rgba(0,0,0,1)";
  470. d.fill()
  471. } else {
  472. var g = d.createRadialGradient(e, f, a * b, e, f, a);
  473. g.addColorStop(0, "rgba(0,0,0,1)");
  474. g.addColorStop(1, "rgba(0,0,0,0)");
  475. d.fillStyle = g;
  476. d.fillRect(0, 0, 2 * a, 2 * a)
  477. }
  478. return c
  479. };
  480. var c = function (a) {
  481. var b = [];
  482. var c = a.min;
  483. var d = a.max;
  484. var e = a.radi;
  485. var a = a.data;
  486. var f = Object.keys(a);
  487. var g = f.length;
  488. while (g--) {
  489. var h = f[g];
  490. var i = Object.keys(a[h]);
  491. var j = i.length;
  492. while (j--) {
  493. var k = i[j];
  494. var l = a[h][k];
  495. var m = e[h][k];
  496. b.push({x: h, y: k, value: l, radius: m})
  497. }
  498. }
  499. return {min: c, max: d, data: b}
  500. };
  501. function d(b) {
  502. var c = b.container;
  503. var d = this.shadowCanvas = document.createElement("canvas");
  504. var e = this.canvas = b.canvas || document.createElement("canvas");
  505. var f = this._renderBoundaries = [1e4, 1e4, 0, 0];
  506. var g = getComputedStyle(b.container) || {};
  507. e.className = "heatmap-canvas";
  508. this._width = e.width = d.width = +g.width.replace(/px/, "");
  509. this._height = e.height = d.height = +g.height.replace(/px/, "");
  510. this.shadowCtx = d.getContext("2d");
  511. this.ctx = e.getContext("2d");
  512. e.style.cssText = d.style.cssText = "position:absolute;left:0;top:0;";
  513. c.style.position = "relative";
  514. c.appendChild(e);
  515. this._palette = a(b);
  516. this._templates = {};
  517. this._setStyles(b)
  518. }
  519. d.prototype = {
  520. renderPartial: function (a) {
  521. this._drawAlpha(a);
  522. this._colorize()
  523. }, renderAll: function (a) {
  524. this._clear();
  525. this._drawAlpha(c(a));
  526. this._colorize()
  527. }, _updateGradient: function (b) {
  528. this._palette = a(b)
  529. }, updateConfig: function (a) {
  530. if (a["gradient"]) {
  531. this._updateGradient(a)
  532. }
  533. this._setStyles(a)
  534. }, setDimensions: function (a, b) {
  535. this._width = a;
  536. this._height = b;
  537. this.canvas.width = this.shadowCanvas.width = a;
  538. this.canvas.height = this.shadowCanvas.height = b
  539. }, _clear: function () {
  540. this.shadowCtx.clearRect(0, 0, this._width, this._height);
  541. this.ctx.clearRect(0, 0, this._width, this._height)
  542. }, _setStyles: function (a) {
  543. this._blur = a.blur == 0 ? 0 : a.blur || a.defaultBlur;
  544. if (a.backgroundColor) {
  545. this.canvas.style.backgroundColor = a.backgroundColor
  546. }
  547. this._opacity = (a.opacity || 0) * 255;
  548. this._maxOpacity = (a.maxOpacity || a.defaultMaxOpacity) * 255;
  549. this._minOpacity = (a.minOpacity || a.defaultMinOpacity) * 255;
  550. this._useGradientOpacity = !!a.useGradientOpacity
  551. }, _drawAlpha: function (a) {
  552. var c = this._min = a.min;
  553. var d = this._max = a.max;
  554. var a = a.data || [];
  555. var e = a.length;
  556. var f = 1 - this._blur;
  557. while (e--) {
  558. var g = a[e];
  559. var h = g.x;
  560. var i = g.y;
  561. var j = g.radius;
  562. var k = Math.min(g.value, d);
  563. var l = h - j;
  564. var m = i - j;
  565. var n = this.shadowCtx;
  566. var o;
  567. if (!this._templates[j]) {
  568. this._templates[j] = o = b(j, f)
  569. } else {
  570. o = this._templates[j]
  571. }
  572. n.globalAlpha = (k - c) / (d - c);
  573. n.drawImage(o, l, m);
  574. if (l < this._renderBoundaries[0]) {
  575. this._renderBoundaries[0] = l
  576. }
  577. if (m < this._renderBoundaries[1]) {
  578. this._renderBoundaries[1] = m
  579. }
  580. if (l + 2 * j > this._renderBoundaries[2]) {
  581. this._renderBoundaries[2] = l + 2 * j
  582. }
  583. if (m + 2 * j > this._renderBoundaries[3]) {
  584. this._renderBoundaries[3] = m + 2 * j
  585. }
  586. }
  587. }, _colorize: function () {
  588. var a = this._renderBoundaries[0];
  589. var b = this._renderBoundaries[1];
  590. var c = this._renderBoundaries[2] - a;
  591. var d = this._renderBoundaries[3] - b;
  592. var e = this._width;
  593. var f = this._height;
  594. var g = this._opacity;
  595. var h = this._maxOpacity;
  596. var i = this._minOpacity;
  597. var j = this._useGradientOpacity;
  598. if (a < 0) {
  599. a = 0
  600. }
  601. if (b < 0) {
  602. b = 0
  603. }
  604. if (a + c > e) {
  605. c = e - a
  606. }
  607. if (b + d > f) {
  608. d = f - b
  609. }
  610. var k = this.shadowCtx.getImageData(a, b, c, d);
  611. var l = k.data;
  612. var m = l.length;
  613. var n = this._palette;
  614. for (var o = 3; o < m; o += 4) {
  615. var p = l[o];
  616. var q = p * 4;
  617. if (!q) {
  618. continue
  619. }
  620. var r;
  621. if (g > 0) {
  622. r = g
  623. } else {
  624. if (p < h) {
  625. if (p < i) {
  626. r = i
  627. } else {
  628. r = p
  629. }
  630. } else {
  631. r = h
  632. }
  633. }
  634. l[o - 3] = n[q];
  635. l[o - 2] = n[q + 1];
  636. l[o - 1] = n[q + 2];
  637. l[o] = j ? n[q + 3] : r
  638. }
  639. k.data = l;
  640. this.ctx.putImageData(k, a, b);
  641. this._renderBoundaries = [1e3, 1e3, 0, 0]
  642. }, getValueAt: function (a) {
  643. var b;
  644. var c = this.shadowCtx;
  645. var d = c.getImageData(a.x, a.y, 1, 1);
  646. var e = d.data[3];
  647. var f = this._max;
  648. var g = this._min;
  649. b = Math.abs(f - g) * (e / 255) >> 0;
  650. return b
  651. }, getDataURL: function () {
  652. return this.canvas.toDataURL()
  653. }
  654. };
  655. return d
  656. }();
  657. var d = function j() {
  658. var b = false;
  659. if (a["defaultRenderer"] === "canvas2d") {
  660. b = c
  661. }
  662. return b
  663. }();
  664. var e = {
  665. merge: function () {
  666. var a = {};
  667. var b = arguments.length;
  668. for (var c = 0; c < b; c++) {
  669. var d = arguments[c];
  670. for (var e in d) {
  671. a[e] = d[e]
  672. }
  673. }
  674. return a
  675. }
  676. };
  677. var f = function k() {
  678. var c = function h() {
  679. function a() {
  680. this.cStore = {}
  681. }
  682. a.prototype = {
  683. on: function (a, b, c) {
  684. var d = this.cStore;
  685. if (!d[a]) {
  686. d[a] = []
  687. }
  688. d[a].push(function (a) {
  689. return b.call(c, a)
  690. })
  691. }, emit: function (a, b) {
  692. var c = this.cStore;
  693. if (c[a]) {
  694. var d = c[a].length;
  695. for (var e = 0; e < d; e++) {
  696. var f = c[a][e];
  697. f(b)
  698. }
  699. }
  700. }
  701. };
  702. return a
  703. }();
  704. var f = function (a) {
  705. var b = a._renderer;
  706. var c = a._coordinator;
  707. var d = a._store;
  708. c.on("renderpartial", b.renderPartial, b);
  709. c.on("renderall", b.renderAll, b);
  710. c.on("extremachange", function (b) {
  711. a._config.onExtremaChange && a._config.onExtremaChange({
  712. min: b.min,
  713. max: b.max,
  714. gradient: a._config["gradient"] || a._config["defaultGradient"]
  715. })
  716. });
  717. d.setCoordinator(c)
  718. };
  719. function g() {
  720. var g = this._config = e.merge(a, arguments[0] || {});
  721. this._coordinator = new c;
  722. if (g["plugin"]) {
  723. var h = g["plugin"];
  724. if (!a.plugins[h]) {
  725. throw new Error("Plugin '" + h + "' not found. Maybe it was not registered.")
  726. } else {
  727. var i = a.plugins[h];
  728. this._renderer = new i.renderer(g);
  729. this._store = new i.store(g)
  730. }
  731. } else {
  732. this._renderer = new d(g);
  733. this._store = new b(g)
  734. }
  735. f(this)
  736. }
  737. g.prototype = {
  738. addData: function () {
  739. this._store.addData.apply(this._store, arguments);
  740. return this
  741. }, removeData: function () {
  742. this._store.removeData && this._store.removeData.apply(this._store, arguments);
  743. return this
  744. }, setData: function () {
  745. this._store.setData.apply(this._store, arguments);
  746. return this
  747. }, setDataMax: function () {
  748. this._store.setDataMax.apply(this._store, arguments);
  749. return this
  750. }, setDataMin: function () {
  751. this._store.setDataMin.apply(this._store, arguments);
  752. return this
  753. }, configure: function (a) {
  754. this._config = e.merge(this._config, a);
  755. this._renderer.updateConfig(this._config);
  756. this._coordinator.emit("renderall", this._store._getInternalData());
  757. return this
  758. }, repaint: function () {
  759. this._coordinator.emit("renderall", this._store._getInternalData());
  760. return this
  761. }, getData: function () {
  762. return this._store.getData()
  763. }, getDataURL: function () {
  764. return this._renderer.getDataURL()
  765. }, getValueAt: function (a) {
  766. if (this._store.getValueAt) {
  767. return this._store.getValueAt(a)
  768. } else if (this._renderer.getValueAt) {
  769. return this._renderer.getValueAt(a)
  770. } else {
  771. return null
  772. }
  773. }
  774. };
  775. return g
  776. }();
  777. var g = {
  778. create: function (a) {
  779. return new f(a)
  780. }, register: function (b, c) {
  781. a.plugins[b] = c
  782. }
  783. };
  784. return g
  785. });