在cesium 三维地图中我们用到人口热力图更加直观显示数据分布情况
参考 https://www.npmjs.com/package/cesium-heatmap?activeTab=readme
效果图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cesium Demo</title>
<!-- 自己官网下载挥着使用下方 在线js -->
<script src="./Cesium/Cesium.js"></script>
<script src="./Cesium/CesiumHeatmap.js"></script>
<!-- <script src="https://cesium.com/downloads/cesiumjs/releases/1.118/Build/Cesium/Cesium.js"></script> -->
<style>
@import url('Cesium/Widgets/widgets.css');
/* @import url(https://cesium.com/downloads/cesiumjs/releases/1.118/Build/Cesium/Widgets/widgets.css); */
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.btn_group {
position: fixed;
left: 0;
top: 0;
z-index: 3;
}
</style>
</head>
<body>
<div class="btn_group">
<button class="create">创建</button>
<button class="hide">隐藏</button>
<button class="delete">删除</button>
</div>
<div id="cesiumContainer"></div>
<script>
let ACToken = '你自己的 cesium token';
Cesium.Ion.defaultAccessToken = ACToken;
const viewer = new Cesium.Viewer("cesiumContainer", {
// 根据自己的情况设置对用的配置项
animation: false, //时间轴动画控件
baseLayerPicker: false,
fullscreenButton: true,
homeButton: false, // home键值,返回初始地图
// infoBox: true,
navigationHelpButton: false, //是否显示右上角的帮助按钮
navigationInstructionsInitiallyVisible: false, // 导航说明显示
requestRenderMode: true,
// maximumRenderTimeChange : 200,
sceneModePicker: false, //是否显示3D/2D选择器
sceneMode: Cesium.SceneMode.SCENE3D, //显示三维地图
shouldAnimate: true, // 动画效果展示
shadows: true, //光照后的阴影效果
terrainProvider: Cesium.createWorldTerrain({
requestVertexNormals: false,
requestWaterMask: false, // 动态水流
}),
timeline: false, //时间轴控件
vrButton: false,
});
// let pInfoStatusBar = new xt3d.SceneControl.PositionInfoStatusBar(viewer);
// 热力区域范围,一个矩形区域,如果你不好确定,直接用 下方 data 中最小、最大经纬度
let bounds = {
west: 115.88867461317612, // 西
east: 117.42520967681416, // 东
south: 39.515669885977225, // 南方
north: 40.628930577792865 // 北
};
// 将地图视角固定到该范围方便查看热力图数据
viewer.camera.setView({
destination: Cesium.Rectangle.fromDegrees(bounds.west, bounds.south, bounds.east, bounds.north)
});
// init heatmap
let heatMap = CesiumHeatmap.create(
viewer, // 对应 初始化 cesium的 vieer
bounds, //热力图的区域范围
params = {
// 热力图的百分比颜色显示
// "gradient": {
// "0.05": "rgb(0,0,255)",
// "0.25": "rgb(0 255 127)",
// "0.45": "rgb(0,255,0)",
// "0.65": "rgb(255 255 0)",
// "0.85": "rgb(255 165 0)",
// "1.00": "rgb(255,0,0)"
// },
radius: 100, // 热点半径
blur: 0.75, //模糊尺寸
maxOpacity: 0.85, // 最大不透明度
minOpacity: 0.16, //最小不透明度
}
);
// 随机热力图数据
let data = [
{ "x": 116.18489662381741, "y": 39.9873086960114, "value": 10 },
{ "x": 116.38303264743074, "y": 39.924417004370575, "value": 11 },
{ "x": 116.28140313086581, "y": 39.80950560881486, "value": 12 },
// ......
];
let valueMin = 0; // 最小热力值
let valueMax = 50; // 最大热力值
const oCreate = document.querySelector('.create');
const oHide = document.querySelector('.hide');
const oDelete = document.querySelector('.delete');
let isShow = true; // 是否显示热力图数据
// 创建热力图
oCreate.addEventListener('click', () => {
isShow = true;
heatMap.setWGS84Data(valueMin, valueMax, data);
})
// 隐藏热力图
oHide.addEventListener('click', () => {
isShow = !isShow;
heatMap.show(isShow);
})
// 删除热力图(原本CesiumHeatmap.js 中无 delete 方法,是自己在原型上添加的删除)
oDelete.addEventListener('click', () => {
heatMap.delete();
isShow = false;
})
</script>
</body>
</html>
CesiumHeatmap.js 文件
/*
* CesiumHeatmap.js v0.1 | Cesium Heatmap Library
*
* Works with heatmap.js v2.0.0: http://www.patrick-wied.at/static/heatmapjs/
*/
(function (window) {
'use strict';
function define_CesiumHeatmap() {
var CesiumHeatmap = {
defaults: {
useEntitiesIfAvailable: true, //whether to use entities if a Viewer is supplied or always use an ImageryProvider
minCanvasSize: 700, // minimum size (in pixels) for the heatmap canvas
maxCanvasSize: 2000, // maximum size (in pixels) for the heatmap canvas
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)
spacingFactor: 1.5, // extra space around the borders (point radius multiplied by this number yields the spacing)
maxOpacity: 0.8, // the maximum opacity used if not given in the heatmap options object
minOpacity: 0.1, // the minimum opacity used if not given in the heatmap options object
blur: 0.85, // the blur used if not given in the heatmap options object
gradient: { // the gradient used if not given in the heatmap options object
'.3': 'blue',
'.65': 'yellow',
'.8': 'orange',
'.95': 'red'
},
}
};
/* Create a CesiumHeatmap instance
*
* cesium: the CesiumWidget or Viewer instance
* bb: the WGS84 bounding box like {north, east, south, west}
* options: a heatmap.js options object (see http://www.patrick-wied.at/static/heatmapjs/docs.html#h337-create)
*/
CesiumHeatmap.create = function (cesium, bb, options) {
var instance = new CHInstance(cesium, bb, options);
return instance;
};
CesiumHeatmap._getContainer = function (width, height, id) {
var c = document.createElement("div");
if (id) {
c.setAttribute("id", id);
}
c.setAttribute("style", "width: " + width + "px; height: " + height + "px; margin: 0px; display: none;");
document.body.appendChild(c);
return c;
};
CesiumHeatmap._getImageryProvider = function (instance) {
//var n = (new Date()).getTime();
var d = instance._heatmap.getDataURL();
//console.log("Create data URL: " + ((new Date()).getTime() - n));
//var n = (new Date()).getTime();
var imgprov = new Cesium.SingleTileImageryProvider({
url: d,
rectangle: instance._rectangle
});
//console.log("Create imageryprovider: " + ((new Date()).getTime() - n));
imgprov._tilingScheme = new Cesium.WebMercatorTilingScheme({
rectangleSouthwestInMeters: new Cesium.Cartesian2(instance._mbounds.west, instance._mbounds.south),
rectangleNortheastInMeters: new Cesium.Cartesian2(instance._mbounds.east, instance._mbounds.north)
});
return imgprov;
};
CesiumHeatmap._getID = function (len) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < ((len) ? len : 8); i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
};
var WMP = new Cesium.WebMercatorProjection();
/* Convert a WGS84 location into a mercator location
*
* p: the WGS84 location like {x: lon, y: lat}
*/
CesiumHeatmap.wgs84ToMercator = function (p) {
var mp = WMP.project(Cesium.Cartographic.fromDegrees(p.x, p.y));
return {
x: mp.x,
y: mp.y
};
};
/* Convert a WGS84 bounding box into a mercator bounding box
*
* bb: the WGS84 bounding box like {north, east, south, west}
*/
CesiumHeatmap.wgs84ToMercatorBB = function (bb) {
var sw = WMP.project(Cesium.Cartographic.fromDegrees(bb.west, bb.south));
var ne = WMP.project(Cesium.Cartographic.fromDegrees(bb.east, bb.north));
return {
north: ne.y,
east: ne.x,
south: sw.y,
west: sw.x
};
};
/* Convert a mercator location into a WGS84 location
*
* p: the mercator lcation like {x, y}
*/
CesiumHeatmap.mercatorToWgs84 = function (p) {
var wp = WMP.unproject(new Cesium.Cartesian3(p.x, p.y));
return {
x: wp.longitude,
y: wp.latitude
};
};
/* Convert a mercator bounding box into a WGS84 bounding box
*
* bb: the mercator bounding box like {north, east, south, west}
*/
CesiumHeatmap.mercatorToWgs84BB = function (bb) {
var sw = WMP.unproject(new Cesium.Cartesian3(bb.west, bb.south));
var ne = WMP.unproject(new Cesium.Cartesian3(bb.east, bb.north));
return {
north: this.rad2deg(ne.latitude),
east: this.rad2deg(ne.longitude),
south: this.rad2deg(sw.latitude),
west: this.rad2deg(sw.longitude)
};
};
/* Convert degrees into radians
*
* d: the degrees to be converted to radians
*/
CesiumHeatmap.deg2rad = function (d) {
var r = d * (Math.PI / 180.0);
return r;
};
/* Convert radians into degrees
*
* r: the radians to be converted to degrees
*/
CesiumHeatmap.rad2deg = function (r) {
var d = r / (Math.PI / 180.0);
return d;
};
return CesiumHeatmap;
}
if (typeof(CesiumHeatmap) === 'undefined') {
window.CesiumHeatmap = define_CesiumHeatmap();
} else {
console.log("CesiumHeatmap already defined.");
}
})(window);
/* Initiate a CesiumHeatmap instance
*
* c: CesiumWidget instance
* bb: a WGS84 bounding box like {north, east, south, west}
* o: a heatmap.js options object (see http://www.patrick-wied.at/static/heatmapjs/docs.html#h337-create)
*/
function CHInstance(c, bb, o) {
if (!bb) {
return null;
}
if (!o) {
o = {};
}
this._cesium = c;
this._options = o;
this._id = CesiumHeatmap._getID();
this._options.gradient = ((this._options.gradient) ? this._options.gradient : CesiumHeatmap.defaults.gradient);
this._options.maxOpacity = ((this._options.maxOpacity) ? this._options.maxOpacity : CesiumHeatmap.defaults.maxOpacity);
this._options.minOpacity = ((this._options.minOpacity) ? this._options.minOpacity : CesiumHeatmap.defaults.minOpacity);
this._options.blur = ((this._options.blur) ? this._options.blur : CesiumHeatmap.defaults.blur);
this._mbounds = CesiumHeatmap.wgs84ToMercatorBB(bb);
this._setWidthAndHeight(this._mbounds);
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));
this._spacing = this._options.radius * CesiumHeatmap.defaults.spacingFactor;
this._xoffset = this._mbounds.west;
this._yoffset = this._mbounds.south;
this.width = Math.round(this.width + this._spacing * 2);
this.height = Math.round(this.height + this._spacing * 2);
this._mbounds.west -= this._spacing * this._factor;
this._mbounds.east += this._spacing * this._factor;
this._mbounds.south -= this._spacing * this._factor;
this._mbounds.north += this._spacing * this._factor;
this.bounds = CesiumHeatmap.mercatorToWgs84BB(this._mbounds);
this._rectangle = Cesium.Rectangle.fromDegrees(this.bounds.west, this.bounds.south, this.bounds.east, this.bounds.north);
this._container = CesiumHeatmap._getContainer(this.width, this.height, this._id);
this._options.container = this._container;
this._heatmap = h337.create(this._options);
this._container.children[0].setAttribute("id", this._id + "-hm");
}
/* Convert a WGS84 location to the corresponding heatmap location
*
* p: a WGS84 location like {x:lon, y:lat}
*/
CHInstance.prototype.wgs84PointToHeatmapPoint = function (p) {
return this.mercatorPointToHeatmapPoint(CesiumHeatmap.wgs84ToMercator(p));
};
/* Convert a mercator location to the corresponding heatmap location
*
* p: a WGS84 location like {x: lon, y:lat}
*/
CHInstance.prototype.mercatorPointToHeatmapPoint = function (p) {
var pn = {};
pn.x = Math.round((p.x - this._xoffset) / this._factor + this._spacing);
pn.y = Math.round((p.y - this._yoffset) / this._factor + this._spacing);
pn.y = this.height - pn.y;
return pn;
};
CHInstance.prototype._setWidthAndHeight = function (mbb) {
this.width = ((mbb.east > 0 && mbb.west < 0) ? mbb.east + Math.abs(mbb.west) : Math.abs(mbb.east - mbb.west));
this.height = ((mbb.north > 0 && mbb.south < 0) ? mbb.north + Math.abs(mbb.south) : Math.abs(mbb.north - mbb.south));
this._factor = 1;
if (this.width > this.height && this.width > CesiumHeatmap.defaults.maxCanvasSize) {
this._factor = this.width / CesiumHeatmap.defaults.maxCanvasSize;
if (this.height / this._factor < CesiumHeatmap.defaults.minCanvasSize) {
this._factor = this.height / CesiumHeatmap.defaults.minCanvasSize;
}
} else if (this.height > this.width && this.height > CesiumHeatmap.defaults.maxCanvasSize) {
this._factor = this.height / CesiumHeatmap.defaults.maxCanvasSize;
if (this.width / this._factor < CesiumHeatmap.defaults.minCanvasSize) {
this._factor = this.width / CesiumHeatmap.defaults.minCanvasSize;
}
} else if (this.width < this.height && this.width < CesiumHeatmap.defaults.minCanvasSize) {
this._factor = this.width / CesiumHeatmap.defaults.minCanvasSize;
if (this.height / this._factor > CesiumHeatmap.defaults.maxCanvasSize) {
this._factor = this.height / CesiumHeatmap.defaults.maxCanvasSize;
}
} else if (this.height < this.width && this.height < CesiumHeatmap.defaults.minCanvasSize) {
this._factor = this.height / CesiumHeatmap.defaults.minCanvasSize;
if (this.width / this._factor > CesiumHeatmap.defaults.maxCanvasSize) {
this._factor = this.width / CesiumHeatmap.defaults.maxCanvasSize;
}
}
this.width = this.width / this._factor;
this.height = this.height / this._factor;
};
/* Set an array of heatmap locations
*
* min: the minimum allowed value for the data values
* max: the maximum allowed value for the data values
* data: an array of data points in heatmap coordinates and values like {x, y, value}
*/
CHInstance.prototype.setData = function (min, max, data) {
if (data && data.length > 0 && min !== null && min !== false && max !== null && max !== false) {
this._heatmap.setData({
min: min,
max: max,
data: data
});
this.updateLayer();
return true;
}
return false;
};
/* Set an array of WGS84 locations
*
* min: the minimum allowed value for the data values
* max: the maximum allowed value for the data values
* data: an array of data points in WGS84 coordinates and values like { x:lon, y:lat, value }
*/
CHInstance.prototype.setWGS84Data = function (min, max, data) {
if (data && data.length > 0 && min !== null && min !== false && max !== null && max !== false) {
var convdata = [];
for (var i = 0; i < data.length; i++) {
var gp = data[i];
var hp = this.wgs84PointToHeatmapPoint(gp);
if (gp.value || gp.value === 0) {
hp.value = gp.value;
}
convdata.push(hp);
}
return this.setData(min, max, convdata);
}
return false;
};
/* Set whether or not the heatmap is shown on the map
*
* s: true means the heatmap is shown, false means the heatmap is hidden
*/
CHInstance.prototype.show = function (s) {
if (this._layer) {
this._layer.show = s;
}
};
CHInstance.prototype.delete = function (s) {
if(!this._layer) {
return;
}
if (CesiumHeatmap.defaults.useEntitiesIfAvailable && this._cesium.entities) {
this._cesium.entities.remove(this._layer);
} else {
this._cesium.scene.imageryLayers.remove(this._layer);
}
this._layer.show = false;
this._layer = null;
};
/* Update/(re)draw the heatmap
*/
CHInstance.prototype.updateLayer = function () {
// only works with a Viewer instance since the cesiumWidget
// instance doesn't contain an entities property
if (CesiumHeatmap.defaults.useEntitiesIfAvailable && this._cesium.entities) {
if (this._layer) {
this._cesium.entities.remove(this._layer);
}
// Work around issue with material rendering in Cesium
// provided by https://github.com/criis
material = new Cesium.ImageMaterialProperty({
image: this._heatmap._renderer.canvas,
});
if (Cesium.VERSION >= "1.21") {
material.transparent = true;
} else if (Cesium.VERSION >= "1.16") {
material.alpha = 0.99;
}
this._layer = this._cesium.entities.add({
show: true,
rectangle: {
coordinates: this._rectangle,
material: material
}
});
} else {
if (this._layer) {
this._cesium.scene.imageryLayers.remove(this._layer);
}
this._layer = this._cesium.scene.imageryLayers.addImageryProvider(CesiumHeatmap._getImageryProvider(this));
}
};
/* DON'T TOUCH:
*
* heatmap.js v2.0.0 | JavaScript Heatmap Library: http://www.patrick-wied.at/static/heatmapjs/
*
* Copyright 2008-2014 Patrick Wied <heatmapjs@patrick-wied.at> - All rights reserved.
* Dual licensed under MIT and Beerware license
*
* :: 2014-10-31 21: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 = 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 = 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
}
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._data = [];
this._radi = [];
for (var d = 0; d < c; d++) {
this._organiseData(b[d], false)
}
this._max = a.max;
this._min = a.min || 0;
this._onExtremaChange();
this._coordinator.emit("renderall", this._getInternalData());
return this
}, removeData: function () {
}, setDataMax: function (a) {
this._max = a;
this._onExtremaChange();
this._coordinator.emit("renderall", this._getInternalData());
return this
}, setDataMin: function (a) {
this._min = a;
this._onExtremaChange();
this._coordinator.emit("renderall", this._getInternalData());
return this
}, setCoordinator: function (a) {
this._coordinator = a
}, _getInternalData: function () {
return {max: this._max, min: this._min, data: this._data, radi: this._radi}
}, getData: function () {
return this._unOrganizeData()
}
};
return b
}();
var c = function i() {
var a = function (a) {
var b = a.gradient || a.defaultGradient;
var c = document.createElement("canvas");
var d = c.getContext("2d");
c.width = 256;
c.height = 1;
var e = d.createLinearGradient(0, 0, 256, 1);
for (var f in b) {
e.addColorStop(f, b[f])
}
d.fillStyle = e;
d.fillRect(0, 0, 256, 1);
return d.getImageData(0, 0, 256, 1).data
};
var b = function (a, b) {
var c = document.createElement("canvas");
var d = c.getContext("2d");
var e = a;
var f = a;
c.width = c.height = a * 2;
if (b == 1) {
d.beginPath();
d.arc(e, f, a, 0, 2 * Math.PI, false);
d.fillStyle = "rgba(0,0,0,1)";
d.fill()
} else {
var g = d.createRadialGradient(e, f, a * b, e, f, a);
g.addColorStop(0, "rgba(0,0,0,1)");
g.addColorStop(1, "rgba(0,0,0,0)");
d.fillStyle = g;
d.fillRect(0, 0, 2 * a, 2 * a)
}
return c
};
var c = function (a) {
var b = [];
var c = a.min;
var d = a.max;
var e = a.radi;
var a = a.data;
var f = Object.keys(a);
var g = f.length;
while (g--) {
var h = f[g];
var i = Object.keys(a[h]);
var j = i.length;
while (j--) {
var k = i[j];
var l = a[h][k];
var m = e[h][k];
b.push({x: h, y: k, value: l, radius: m})
}
}
return {min: c, max: d, data: b}
};
function d(b) {
var c = b.container;
var d = this.shadowCanvas = document.createElement("canvas");
var e = this.canvas = b.canvas || document.createElement("canvas");
var f = this._renderBoundaries = [1e4, 1e4, 0, 0];
var g = getComputedStyle(b.container) || {};
e.className = "heatmap-canvas";
this._width = e.width = d.width = +g.width.replace(/px/, "");
this._height = e.height = d.height = +g.height.replace(/px/, "");
this.shadowCtx = d.getContext("2d");
this.ctx = e.getContext("2d");
e.style.cssText = d.style.cssText = "position:absolute;left:0;top:0;";
c.style.position = "relative";
c.appendChild(e);
this._palette = a(b);
this._templates = {};
this._setStyles(b)
}
d.prototype = {
renderPartial: function (a) {
this._drawAlpha(a);
this._colorize()
}, renderAll: function (a) {
this._clear();
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._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]
}
n.globalAlpha = (k - c) / (d - c);
n.drawImage(o, l, m);
if (l < this._renderBoundaries[0]) {
this._renderBoundaries[0] = l
}
if (m < this._renderBoundaries[1]) {
this._renderBoundaries[1] = m
}
if (l + 2 * j > this._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; o < m; o += 4) {
var p = l[o];
var q = p * 4;
if (!q) {
continue
}
var r;
if (g > 0) {
r = g
} else {
if (p < h) {
if (p < i) {
r = i
} else {
r = p
}
} else {
r = h
}
}
l[o - 3] = n[q];
l[o - 2] = n[q + 1];
l[o - 1] = n[q + 2];
l[o] = j ? n[q + 3] : r
}
k.data = l;
this.ctx.putImageData(k, a, b);
this._renderBoundaries = [1e3, 1e3, 0, 0]
}, getValueAt: function (a) {
var b;
var c = this.shadowCtx;
var d = c.getImageData(a.x, a.y, 1, 1);
var e = d.data[3];
var f = this._max;
var g = this._min;
b = Math.abs(f - g) * (e / 255) >> 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 < b; c++) {
var d = arguments[c];
for (var e in d) {
a[e] = d[e]
}
}
return a
}
};
var f = function k() {
var c = function h() {
function a() {
this.cStore = {}
}
a.prototype = {
on: function (a, b, c) {
var d = this.cStore;
if (!d[a]) {
d[a] = []
}
d[a].push(function (a) {
return b.call(c, a)
})
}, emit: function (a, b) {
var c = this.cStore;
if (c[a]) {
var d = c[a].length;
for (var e = 0; e < d; e++) {
var f = c[a][e];
f(b)
}
}
}
};
return a
}();
var f = function (a) {
var b = a._renderer;
var c = a._coordinator;
var d = a._store;
c.on("renderpartial", b.renderPartial, b);
c.on("renderall", b.renderAll, b);
c.on("extremachange", function (b) {
a._config.onExtremaChange && a._config.onExtremaChange({
min: b.min,
max: b.max,
gradient: a._config["gradient"] || a._config["defaultGradient"]
})
});
d.setCoordinator(c)
};
function g() {
var g = this._config = e.merge(a, arguments[0] || {});
this._coordinator = new c;
if (g["plugin"]) {
var h = g["plugin"];
if (!a.plugins[h]) {
throw new Error("Plugin '" + h + "' not found. Maybe it was not registered.")
} else {
var i = a.plugins[h];
this._renderer = new i.renderer(g);
this._store = new i.store(g)
}
} else {
this._renderer = new d(g);
this._store = new b(g)
}
f(this)
}
g.prototype = {
addData: function () {
this._store.addData.apply(this._store, arguments);
return this
}, removeData: function () {
this._store.removeData && this._store.removeData.apply(this._store, arguments);
return this
}, setData: function () {
this._store.setData.apply(this._store, arguments);
return this
}, setDataMax: function () {
this._store.setDataMax.apply(this._store, arguments);
return this
}, setDataMin: function () {
this._store.setDataMin.apply(this._store, arguments);
return this
}, configure: function (a) {
this._config = e.merge(this._config, a);
this._renderer.updateConfig(this._config);
this._coordinator.emit("renderall", this._store._getInternalData());
return this
}, repaint: function () {
this._coordinator.emit("renderall", this._store._getInternalData());
return this
}, getData: function () {
return this._store.getData()
}, getDataURL: function () {
return this._renderer.getDataURL()
}, getValueAt: function (a) {
if (this._store.getValueAt) {
return this._store.getValueAt(a)
} else if (this._renderer.getValueAt) {
return this._renderer.getValueAt(a)
} else {
return null
}
}
};
return g
}();
var g = {
create: function (a) {
return new f(a)
}, register: function (b, c) {
a.plugins[b] = c
}
};
return g
});