Files
ibs-fullstack/ruoyi-ui/public/baidu/script/HeatMap.js
2026-02-26 14:51:13 +08:00

931 lines
31 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function (w) {
// the heatmapFactory creates heatmap instances
var heatmapFactory = (function(){
// store object constructor
// a heatmap contains a store
// the store has to know about the heatmap in order to trigger heatmap updates when datapoints get added
var store = function store(hmap) {
var _ = {
// data is a two dimensional array
// a datapoint gets saved as data[point-x-value][point-y-value]
// the value at [point-x-value][point-y-value] is the occurrence of the datapoint
data: [],
// tight coupling of the heatmap object
heatmap: hmap
};
// the max occurrence - the heatmaps radial gradient alpha transition is based on it
this.max = 1;
this.get = function (key) {
return _[key];
};
this.set = function (key, value) {
_[key] = value;
};
}
store.prototype = {
// function for adding datapoints to the store
// datapoints are usually defined by x and y but could also contain a third parameter which represents the occurrence
addDataPoint: function (x, y) {
if (x < 0 || y < 0)
return;
var me = this,
heatmap = me.get("heatmap"),
data = me.get("data");
if (!data[x])
data[x] = [];
if (!data[x][y])
data[x][y] = 0;
// if count parameter is set increment by count otherwise by 1
data[x][y] += (arguments.length < 3) ? 1 : arguments[2];
me.set("data", data);
// do we have a new maximum?
if (me.max < data[x][y]) {
// max changed, we need to redraw all existing(lower) datapoints
heatmap.get("actx").clearRect(0, 0, heatmap.get("width"), heatmap.get("height"));
me.setDataSet({ max: data[x][y], data: data }, true);
return;
}
heatmap.drawAlpha(x, y, data[x][y], true);
},
setDataSet: function (obj, internal) {
var me = this,
heatmap = me.get("heatmap"),
data = [],
d = obj.data,
dlen = d.length;
// clear the heatmap before the data set gets drawn
heatmap.clear();
this.max = obj.max;
// if a legend is set, update it
heatmap.get("legend") && heatmap.get("legend").update(obj.max);
if (internal != null && internal) {
for (var one in d) {
// jump over undefined indexes
if (one === undefined)
continue;
for (var two in d[one]) {
if (two === undefined)
continue;
// if both indexes are defined, push the values into the array
heatmap.drawAlpha(one, two, d[one][two], false);
}
}
} else {
while (dlen--) {
var point = d[dlen];
heatmap.drawAlpha(point.x, point.y, point.count, false);
if (!data[point.x])
data[point.x] = [];
if (!data[point.x][point.y])
data[point.x][point.y] = 0;
data[point.x][point.y] = point.count;
}
}
heatmap.colorize();
this.set("data", d);
},
exportDataSet: function () {
var me = this,
data = me.get("data"),
exportData = [];
for (var one in data) {
// jump over undefined indexes
if (one === undefined)
continue;
for (var two in data[one]) {
if (two === undefined)
continue;
// if both indexes are defined, push the values into the array
exportData.push({ x: parseInt(one, 10), y: parseInt(two, 10), count: data[one][two] });
}
}
return { max: me.max, data: exportData };
},
generateRandomDataSet: function (points) {
var heatmap = this.get("heatmap"),
w = heatmap.get("width"),
h = heatmap.get("height");
var randomset = {},
max = Math.floor(Math.random() * 1000 + 1);
randomset.max = max;
var data = [];
while (points--) {
data.push({ x: Math.floor(Math.random() * w + 1), y: Math.floor(Math.random() * h + 1), count: Math.floor(Math.random() * max + 1) });
}
randomset.data = data;
this.setDataSet(randomset);
}
};
var legend = function legend(config) {
this.config = config;
var _ = {
element: null,
labelsEl: null,
gradientCfg: null,
ctx: null
};
this.get = function (key) {
return _[key];
};
this.set = function (key, value) {
_[key] = value;
};
this.init();
};
legend.prototype = {
init: function () {
var me = this,
config = me.config,
title = config.title || "Legend",
position = config.position,
offset = config.offset || 10,
gconfig = config.gradient,
labelsEl = document.createElement("ul"),
labelsHtml = "",
grad, element, gradient, positionCss = "";
me.processGradientObject();
// Positioning
// top or bottom
if (position.indexOf('t') > -1) {
positionCss += 'top:' + offset + 'px;';
} else {
positionCss += 'bottom:' + offset + 'px;';
}
// left or right
if (position.indexOf('l') > -1) {
positionCss += 'left:' + offset + 'px;';
} else {
positionCss += 'right:' + offset + 'px;';
}
element = document.createElement("div");
element.style.cssText = "border-radius:5px;position:absolute;" + positionCss + "font-family:Helvetica; width:256px;z-index:10000000000; background:rgba(255,255,255,1);padding:10px;border:1px solid black;margin:0;";
element.innerHTML = "<h3 style='padding:0;margin:0;text-align:center;font-size:16px;'>" + title + "</h3>";
// create gradient in canvas
labelsEl.style.cssText = "position:relative;font-size:12px;display:block;list-style:none;list-style-type:none;margin:0;height:15px;";
// create gradient element
gradient = document.createElement("div");
gradient.style.cssText = ["position:relative;display:block;width:256px;height:15px;border-bottom:1px solid black; background-image:url(", me.createGradientImage(), ");"].join("");
element.appendChild(labelsEl);
element.appendChild(gradient);
me.set("element", element);
me.set("labelsEl", labelsEl);
me.update(1);
},
processGradientObject: function () {
// create array and sort it
var me = this,
gradientConfig = this.config.gradient,
gradientArr = [];
for (var key in gradientConfig) {
if (gradientConfig.hasOwnProperty(key)) {
gradientArr.push({ stop: key, value: gradientConfig[key] });
}
}
gradientArr.sort(function (a, b) {
return (a.stop - b.stop);
});
gradientArr.unshift({ stop: 0, value: 'rgba(0,0,0,0)' });
me.set("gradientArr", gradientArr);
},
createGradientImage: function () {
var me = this,
gradArr = me.get("gradientArr"),
length = gradArr.length,
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
grad;
// the gradient in the legend including the ticks will be 256x15px
canvas.width = "256";
canvas.height = "15";
grad = ctx.createLinearGradient(0, 5, 256, 10);
for (var i = 0; i < length; i++) {
grad.addColorStop(1 / (length - 1) * i, gradArr[i].value);
}
ctx.fillStyle = grad;
ctx.fillRect(0, 5, 256, 10);
ctx.strokeStyle = "black";
ctx.beginPath();
for (var i = 0; i < length; i++) {
ctx.moveTo(((1 / (length - 1) * i * 256) >> 0) + .5, 0);
ctx.lineTo(((1 / (length - 1) * i * 256) >> 0) + .5, (i == 0) ? 15 : 5);
}
ctx.moveTo(255.5, 0);
ctx.lineTo(255.5, 15);
ctx.moveTo(255.5, 4.5);
ctx.lineTo(0, 4.5);
ctx.stroke();
// we re-use the context for measuring the legends label widths
me.set("ctx", ctx);
return canvas.toDataURL();
},
getElement: function () {
return this.get("element");
},
update: function (max) {
var me = this,
gradient = me.get("gradientArr"),
ctx = me.get("ctx"),
labels = me.get("labelsEl"),
labelText, labelsHtml = "", offset;
for (var i = 0; i < gradient.length; i++) {
labelText = max * gradient[i].stop >> 0;
offset = (ctx.measureText(labelText).width / 2) >> 0;
if (i == 0) {
offset = 0;
}
if (i == gradient.length - 1) {
offset *= 2;
}
labelsHtml += '<li style="position:absolute;left:' + (((((1 / (gradient.length - 1) * i * 256) || 0)) >> 0) - offset + .5) + 'px">' + labelText + '</li>';
}
labels.innerHTML = labelsHtml;
}
};
// heatmap object constructor
var heatmap = function heatmap(config) {
// private variables
var _ = {
radius: 40,
element: {},
canvas: {},
acanvas: {},
ctx: {},
actx: {},
legend: null,
visible: true,
width: 0,
height: 0,
max: false,
gradient: false,
opacity: 180,
premultiplyAlpha: false,
bounds: {
l: 1000,
r: 0,
t: 1000,
b: 0
},
debug: false
};
// heatmap store containing the datapoints and information about the maximum
// accessible via instance.store
this.store = new store(this);
this.get = function (key) {
return _[key];
};
this.set = function (key, value) {
_[key] = value;
};
// configure the heatmap when an instance gets created
this.configure(config);
// and initialize it
this.init();
};
// public functions
heatmap.prototype = {
configure: function (config) {
var me = this,
rout, rin;
me.set("radius", config["radius"] || 40);
me.set("element", (config.element instanceof Object) ? config.element : document.getElementById(config.element));
me.set("visible", (config.visible != null) ? config.visible : true);
me.set("max", config.max || false);
me.set("gradient", config.gradient || { 0.45: "rgb(0,0,255)", 0.55: "rgb(0,255,255)", 0.65: "rgb(0,255,0)", 0.95: "yellow", 1.0: "rgb(255,0,0)" }); // default is the common blue to red gradient
me.set("opacity", parseInt(255 / (100 / config.opacity), 10) || 180);
me.set("width", config.width || 0);
me.set("height", config.height || 0);
me.set("debug", config.debug);
if (config.legend) {
var legendCfg = config.legend;
legendCfg.gradient = me.get("gradient");
me.set("legend", new legend(legendCfg));
}
},
resize: function () {
var me = this,
element = me.get("element"),
canvas = me.get("canvas"),
acanvas = me.get("acanvas");
canvas.width = acanvas.width = me.get("width") || element.style.width.replace(/px/, "") || me.getWidth(element);
this.set("width", canvas.width);
canvas.height = acanvas.height = me.get("height") || element.style.height.replace(/px/, "") || me.getHeight(element);
this.set("height", canvas.height);
},
init: function () {
var me = this,
canvas = document.createElement("canvas"),
acanvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
actx = acanvas.getContext("2d"),
element = me.get("element");
me.initColorPalette();
me.set("canvas", canvas);
me.set("ctx", ctx);
me.set("acanvas", acanvas);
me.set("actx", actx);
me.resize();
canvas.style.cssText = acanvas.style.cssText = "position:absolute;top:0;left:0;z-index:1;";
if (!me.get("visible"))
canvas.style.display = "none";
element.appendChild(canvas);
if (me.get("legend")) {
element.appendChild(me.get("legend").getElement());
}
// debugging purposes only
if (me.get("debug"))
document.body.appendChild(acanvas);
actx.shadowOffsetX = 15000;
actx.shadowOffsetY = 15000;
actx.shadowBlur = 15;
},
initColorPalette: function () {
var me = this,
canvas = document.createElement("canvas"),
gradient = me.get("gradient"),
ctx, grad, testData;
canvas.width = "1";
canvas.height = "256";
ctx = canvas.getContext("2d");
grad = ctx.createLinearGradient(0, 0, 1, 256);
// Test how the browser renders alpha by setting a partially transparent pixel
// and reading the result. A good browser will return a value reasonably close
// to what was set. Some browsers (e.g. on Android) will return a ridiculously wrong value.
testData = ctx.getImageData(0, 0, 1, 1);
testData.data[0] = testData.data[3] = 64; // 25% red & alpha
testData.data[1] = testData.data[2] = 0; // 0% blue & green
ctx.putImageData(testData, 0, 0);
testData = ctx.getImageData(0, 0, 1, 1);
me.set("premultiplyAlpha", (testData.data[0] < 60 || testData.data[0] > 70));
for (var x in gradient) {
grad.addColorStop(x, gradient[x]);
}
ctx.fillStyle = grad;
ctx.fillRect(0, 0, 1, 256);
me.set("gradient", ctx.getImageData(0, 0, 1, 256).data);
},
getWidth: function (element) {
var width = element.offsetWidth;
if (element.style.paddingLeft) {
width += element.style.paddingLeft;
}
if (element.style.paddingRight) {
width += element.style.paddingRight;
}
return width;
},
getHeight: function (element) {
var height = element.offsetHeight;
if (element.style.paddingTop) {
height += element.style.paddingTop;
}
if (element.style.paddingBottom) {
height += element.style.paddingBottom;
}
return height;
},
colorize: function (x, y) {
// get the private variables
var me = this,
width = me.get("width"),
radius = me.get("radius"),
height = me.get("height"),
actx = me.get("actx"),
ctx = me.get("ctx"),
x2 = radius * 3,
premultiplyAlpha = me.get("premultiplyAlpha"),
palette = me.get("gradient"),
opacity = me.get("opacity"),
bounds = me.get("bounds"),
left, top, bottom, right,
image, imageData, length, alpha, offset, finalAlpha;
if (x != null && y != null) {
if (x + x2 > width) {
x = width - x2;
}
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
if (y + x2 > height) {
y = height - x2;
}
left = x;
top = y;
right = x + x2;
bottom = y + x2;
} else {
if (bounds['l'] < 0) {
left = 0;
} else {
left = bounds['l'];
}
if (bounds['r'] > width) {
right = width;
} else {
right = bounds['r'];
}
if (bounds['t'] < 0) {
top = 0;
} else {
top = bounds['t'];
}
if (bounds['b'] > height) {
bottom = height;
} else {
bottom = bounds['b'];
}
}
image = actx.getImageData(left, top, right - left, bottom - top);
imageData = image.data;
length = imageData.length;
// loop thru the area
for (var i = 3; i < length; i += 4) {
// [0] -> r, [1] -> g, [2] -> b, [3] -> alpha
alpha = imageData[i],
offset = alpha * 4;
if (!offset)
continue;
// we ve started with i=3
// set the new r, g and b values
finalAlpha = (alpha < opacity) ? alpha : opacity;
imageData[i - 3] = palette[offset];
imageData[i - 2] = palette[offset + 1];
imageData[i - 1] = palette[offset + 2];
if (premultiplyAlpha) {
// To fix browsers that premultiply incorrectly, we'll pass in a value scaled
// appropriately so when the multiplication happens the correct value will result.
imageData[i - 3] /= 255 / finalAlpha;
imageData[i - 2] /= 255 / finalAlpha;
imageData[i - 1] /= 255 / finalAlpha;
}
// we want the heatmap to have a gradient from transparent to the colors
// as long as alpha is lower than the defined opacity (maximum), we'll use the alpha value
imageData[i] = finalAlpha;
}
// the rgb data manipulation didn't affect the ImageData object(defined on the top)
// after the manipulation process we have to set the manipulated data to the ImageData object
image.data = imageData;
ctx.putImageData(image, left, top);
},
drawAlpha: function (x, y, count, colorize) {
// storing the variables because they will be often used
var me = this,
radius = me.get("radius"),
ctx = me.get("actx"),
max = me.get("max"),
bounds = me.get("bounds"),
xb = x - (1.5 * radius) >> 0, yb = y - (1.5 * radius) >> 0,
xc = x + (1.5 * radius) >> 0, yc = y + (1.5 * radius) >> 0;
ctx.shadowColor = ('rgba(0,0,0,' + ((count) ? (count / me.store.max) : '0.1') + ')');
ctx.shadowOffsetX = 15000;
ctx.shadowOffsetY = 15000;
ctx.shadowBlur = 15;
ctx.beginPath();
ctx.arc(x - 15000, y - 15000, radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
if (colorize) {
// finally colorize the area
me.colorize(xb, yb);
} else {
// or update the boundaries for the area that then should be colorized
if (xb < bounds["l"]) {
bounds["l"] = xb;
}
if (yb < bounds["t"]) {
bounds["t"] = yb;
}
if (xc > bounds['r']) {
bounds['r'] = xc;
}
if (yc > bounds['b']) {
bounds['b'] = yc;
}
}
},
toggleDisplay: function () {
var me = this,
visible = me.get("visible"),
canvas = me.get("canvas");
if (!visible)
canvas.style.display = "block";
else
canvas.style.display = "none";
me.set("visible", !visible);
},
// dataURL export
getImageData: function () {
return this.get("canvas").toDataURL();
},
clear: function () {
var me = this,
w = me.get("width"),
h = me.get("height");
me.store.set("data", []);
// @TODO: reset stores max to 1
//me.store.max = 1;
me.get("ctx").clearRect(0, 0, w, h);
me.get("actx").clearRect(0, 0, w, h);
},
cleanup: function () {
var me = this;
me.get("element").removeChild(me.get("canvas"));
}
};
return {
create: function (config) {
return new heatmap(config);
},
util: {
mousePosition: function (ev) {
// this doesn't work right
// rather use
/*
// this = element to observe
var x = ev.pageX - this.offsetLeft;
var y = ev.pageY - this.offsetTop;
*/
var x, y;
if (ev.layerX) { // Firefox
x = ev.layerX;
y = ev.layerY;
} else if (ev.offsetX) { // Opera
x = ev.offsetX;
y = ev.offsetY;
}
if (typeof (x) == 'undefined')
return;
return [x, y];
}
}
};
})();
w.h337 = w.heatmapFactory = heatmapFactory;
}) (window);
/*==============================以上部分为heatmap.js的核心代码,只负责热力图的展现====================================*/
/*==============================以下部分为专为百度地图打造的覆盖物===================================================*/
/**
* @fileoverview 百度地图的热力图功能,对外开放。
* 主要基于http://www.patrick-wied.at/static/heatmapjs/index.html 修改而得
* 主入口类是<a href="symbols/BMapLib.Heatmap.html">Heatmap</a>
* 基于Baidu Map API 2.0。
*
* @author Baidu Map Api Group
* @version 1.0
*/
/**
* @namespace
* BMap的所有library类均放在BMapLib命名空间下
*/
var BMapLib = window.BMapLib = BMapLib || {};
(function () {
/**
* @exports HeatmapOverlay as BMapLib.HeatmapOverlay
*/
var HeatmapOverlay =
/**
* 热力图的覆盖物
* @class 热力图的覆盖物
* 实例化该类后使用map.addOverlay即可以添加热力图
*
* @constructor
* @param {Json Object} opts 可选的输入参数,非必填项。可输入选项包括:<br />
* {"<b>radius</b>" : {String} 热力图的半径,
* <br />"<b>visible</b>" : {Number} 热力图是否显示,
* <br />"<b>gradient</b>" : {JSON} 热力图的渐变区间,
* <br />"<b>opacity</b>" : {Number} 热力的透明度,
*
* @example <b>参考示例:</b><br />
* var map = new BMapGL.Map("container");<br />map.centerAndZoom(new BMapGL.Point(116.404, 39.915), 15);<br />var heatmapOverlay = new BMapLib.HeatmapOverlay({"radius":10, "visible":true, "opacity":70});<br />heatmapOverlay.setDataSet(data);//data是热力图的详细数据
*/
BMapLib.HeatmapOverlay = function (opts) {
this.conf = opts;
this.heatmap = null;
this.latlngs = [];
this.bounds = null;
}
HeatmapOverlay.prototype = new BMapGL.Overlay();
HeatmapOverlay.prototype.initialize = function (map) {
this._map = map;
var el = document.createElement("div");
el.style.position = "absolute";
el.style.top = 0;
el.style.left = 0;
el.style.border = 0;
el.style.width = this._map.getSize().width + "px";
el.style.height = this._map.getSize().height + "px";
this.conf.element = el;
if (!isSupportCanvas()) {//判断是否支持Canvas.
return el;
}
map.getContainer().appendChild(el);
this.heatmap = h337.create(this.conf);
this._div = el;
return el;
}
HeatmapOverlay.prototype.draw = function () {
if (!isSupportCanvas()) {//判断是否支持Canvas.
return;
}
var currentBounds = this._map.getBounds();
if (currentBounds.equals(this.bounds)) {
return;
}
this.bounds = currentBounds;
var ne = this._map.pointToOverlayPixel(currentBounds.getNorthEast()),
sw = this._map.pointToOverlayPixel(currentBounds.getSouthWest()),
topY = ne.y,
leftX = sw.x,
h = sw.y - ne.y,
w = ne.x - sw.x;
this.conf.element.style.left = leftX + 'px';
this.conf.element.style.top = topY + 'px';
this.conf.element.style.width = w + 'px';
this.conf.element.style.height = h + 'px';
this.heatmap.store.get("heatmap").resize();
if (this.latlngs.length > 0) {
this.heatmap.clear();
var len = this.latlngs.length;
d = {
max: this.heatmap.store.max,
data: []
};
while (len--) {
var latlng = this.latlngs[len].latlng;
if (!currentBounds.containsPoint(latlng)) {
continue;
}
var divPixel = this._map.pointToOverlayPixel(latlng),
screenPixel = new BMapGL.Pixel(divPixel.x - leftX, divPixel.y - topY);
var roundedPoint = this.pixelTransform(screenPixel);
d.data.push({
x: roundedPoint.x,
y: roundedPoint.y,
count: this.latlngs[len].c
});
}
this.heatmap.store.setDataSet(d);
}
}
//内部使用的坐标转化
HeatmapOverlay.prototype.pixelTransform = function (p) {
var w = this.heatmap.get("width"),
h = this.heatmap.get("height");
while (p.x < 0) {
p.x += w;
}
while (p.x > w) {
p.x -= w;
}
while (p.y < 0) {
p.y += h;
}
while (p.y > h) {
p.y -= h;
}
p.x = (p.x >> 0);
p.y = (p.y >> 0);
return p;
}
/**
* 设置热力图展现的详细数据, 实现之后,即可以立刻展现
* @param {Json Object } data
* {"<b>max</b>" : {Number} 权重的最大值,
* <br />"<b>data</b>" : {Array} 坐标详细数据,格式如下 <br/>
* {"lng":116.421969,"lat":39.913527,"count":3}, 其中<br/>
* lng lat分别为经纬度, count权重值
*/
HeatmapOverlay.prototype.setDataSet = function (data) {
this.data = data;
if (!isSupportCanvas()) {//判断是否支持Canvas.
return;
}
var currentBounds = this._map.getBounds();
var mapdata = {
max: data.max,
data: []
};
var d = data.data,
dlen = d.length;
this.latlngs = [];
while (dlen--) {
var latlng = new BMapGL.Point(d[dlen].lng, d[dlen].lat);
if (!currentBounds.containsPoint(latlng)) {
continue;
}
this.latlngs.push({
latlng: latlng,
c: d[dlen].count
});
var divPixel = this._map.pointToOverlayPixel(latlng),
leftX = this._map.pointToOverlayPixel(currentBounds.getSouthWest()).x,
topY = this._map.pointToOverlayPixel(currentBounds.getNorthEast()).y,
screenPixel = new BMapGL.Pixel(divPixel.x - leftX, divPixel.y - topY);
var point = this.pixelTransform(screenPixel);
mapdata.data.push({
x: point.x,
y: point.y,
count: d[dlen].count
});
}
this.heatmap.clear();
this.heatmap.store.setDataSet(mapdata);
}
/**
* 添加热力图的详细坐标点
* @param {Number} lng 经度坐标
* @param {Number} lat 经度坐标
* @param {Number} count 经度坐标
*/
HeatmapOverlay.prototype.addDataPoint = function (lng, lat, count) {
if (!isSupportCanvas()) {
return;
}
if (this.data && this.data.data) {
this.data.data.push({
lng: lng,
lat: lat,
count: count
});
}
var latlng = new BMapGL.Point(lng, lat),
point = this.pixelTransform(this._map.pointToOverlayPixel(latlng));
this.heatmap.store.addDataPoint(point.x, point.y, count);
this.latlngs.push({
latlng: latlng,
c: count
});
}
/**
* 更改热力图的展现或者关闭
*/
HeatmapOverlay.prototype.toggle = function () {
if (!isSupportCanvas()) {//判断是否支持Canvas.
return;
}
this.heatmap.toggleDisplay();
}
/**
* 设置热力图展现的配置
* @param {Json Object} options 可选的输入参数,非必填项。可输入选项包括:<br />
* {"<b>radius</b>" : {String} 热力图的半径,
* <br />"<b>visible</b>" : {Number} 热力图是否显示,
* <br />"<b>gradient</b>" : {JSON} 热力图的渐变区间,
* <br />"<b>opacity</b>" : {Number} 热力的透明度,}
*/
HeatmapOverlay.prototype.setOptions = function (options) {
if (!isSupportCanvas()) {//判断是否支持Canvas.
return;
}
if (options) {
for (var key in options) {
this.heatmap.set(key, options[key]);
if (key == "gradient") {
this.heatmap.initColorPalette();
continue;
}
if (key == 'opacity') {
this.heatmap.set(key, parseInt(255 / (100 / options[key]), 10));
}
}
if (this.data) {
this.setDataSet(this.data);//重新渲染
}
}
}
function isSupportCanvas() {
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
}
})()