@soonspacejs/plugin-heat-map
Version:
Haet-map plugin for SoonSpace.js
556 lines (555 loc) • 23.4 kB
JavaScript
import { Matrix4 as B, Vector2 as P, Shape as j, ShapeGeometry as T, Box2 as A, Plane as F, Vector3 as w, Matrix3 as O, PlaneGeometry as L, CanvasTexture as _, MeshStandardMaterial as z, Mesh as R, Box3 as k, DoubleSide as G } from "three";
var y = { defaultRadius: 40, defaultGradient: { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1: "rgb(255,0,0)" }, defaultMaxOpacity: 1, defaultMinOpacity: 0, defaultBlur: 0.85, defaultXField: "x", defaultYField: "y", defaultValueField: "value" }, U = (function() {
function s() {
this.eStore = {};
}
return s.prototype.on = function(t, e, a) {
this.eStore[t] || (this.eStore[t] = []), this.eStore[t].push((function(i) {
return e.call(a, i);
}));
}, s.prototype.emit = function(t, e) {
this.eStore[t] && this.eStore[t].forEach((function(a) {
return a(e);
}));
}, s;
})(), V = (function() {
function s(t) {
this.coordinator = new U(), this.data = [], this.radi = [], this.min = 10, this.max = 1, this.xField = t.xField || y.defaultXField, this.yField = t.yField || y.defaultYField, this.valueField = t.valueField || y.defaultValueField, this.radius = t.radius || y.defaultRadius;
}
return s.prototype._organiseData = function(t, e) {
var a = t[this.xField], i = t[this.yField], n = this.radi, r = this.data, o = this.max, h = this.min, d = t[this.valueField] || 1, c = t.radius || this.radius;
n[a] || (r[a] = [], n[a] = []), n[a][i] ? r[a][i] += d : (r[a][i] = d, n[a][i] = c);
var l = r[a][i];
return l ? l > o ? (e ? this.setDataMax(l) : this.max = l, !1) : l < h ? (e ? this.setDataMin(l) : this.min = l, !1) : void 0 : { x: a, y: i, value: d, radius: c, min: h, max: o };
}, s.prototype._unOrganizeData = function() {
for (var t = [], e = 0; e < this.radi.length; e++) for (var a = 0; a < this.radi[e].length; a++) t.push({ x: e, y: a, radius: this.radi[e][a], value: this.radi[e][a] });
return { min: this.min, max: this.max, data: t };
}, s.prototype._onExtremaChange = function() {
this.coordinator.emit("extremachange", { min: this.min, max: this.max });
}, s.prototype.addData = function(t) {
var e = this._organiseData(t, !0);
e && (this.data.length === 0 && (this.min = e.value, this.max = e.value), this.coordinator.emit("renderpartial", { min: this.min, max: this.max, data: [e] }));
}, s.prototype.setData = function(t) {
var e = t.data;
this.data = [], this.radi = [];
for (var a = 0; a < e.length; a++) this._organiseData(e[a], !1);
return this.min = t.min || 0, this.max = t.max || 100, this._onExtremaChange(), this.coordinator.emit("renderall", this._getInternalData()), this;
}, s.prototype.setDataMax = function(t) {
return this.max = t, this._onExtremaChange(), this.coordinator.emit("renderall", this._getInternalData()), this;
}, s.prototype.setDataMin = function(t) {
return this.min = t, this._onExtremaChange(), this.coordinator.emit("renderall", this._getInternalData()), this;
}, s.prototype._getInternalData = function() {
return { max: this.max, min: this.min, data: this.data, radi: this.radi };
}, s.prototype.getData = function() {
return this._unOrganizeData();
}, s;
})(), N = (function() {
function s(t) {
this.canvas = t.canvas || document.createElement("canvas"), this.ctx = this.canvas.getContext("2d"), this.shadowCanvas = t.shadowCanvas || document.createElement("canvas"), this.shadowCtx = this.shadowCanvas.getContext("2d"), this.width = t.width || 512, this.height = t.height || 512, this.max = 100, this.min = 1, this.blur = 1, this.opacity = 1, this.maxOpacity = 1, this.minOpacity = 0, this.useGradientOpacity = !1, this.canvas.style.cssText = this.shadowCanvas.style.cssText = "position:absolute;left:0;top:0;", t.container && (t.container.style.position = "relative", t.container.appendChild(this.canvas)), this.renderBoundaries = [1e4, 1e4, 0, 0], this.palette = this._getColorPalette(t), this.templates = [], this._setStyles(t);
}
return s.prototype.renderPartial = function(t) {
t.data.length > 0 && (this._drawAlpha(t), this._colorize());
}, s.prototype.renderAll = function(t) {
this._clear(), t.data.length > 0 && (this._drawAlpha(this._prepareData(t)), this._colorize());
}, s.prototype.updateConfig = function(t) {
t.gradient && this._updateGradient(t), this._setStyles(t);
}, s.prototype.setDimensions = function(t, e) {
this.width = this.canvas.width = this.shadowCanvas.width = t, this.height = this.canvas.height = this.shadowCanvas.height = e;
}, s.prototype.getValueAt = function(t) {
if (!this.shadowCtx) return 0;
var e = this.shadowCtx.getImageData(t.x, t.y, 1, 1);
return Math.abs(this.max - this.min) * (e.data[3] / 255) >> 0;
}, s.prototype.getDataURL = function() {
return this.canvas.toDataURL();
}, s.prototype._getColorPalette = function(t) {
var e = t.gradient || y.defaultGradient, a = document.createElement("canvas"), i = a.getContext("2d");
if (a.width = 256, a.height = 1, !i) return new Uint8ClampedArray(1024);
var n = i.createLinearGradient(0, 0, 256, 1);
for (var r in e) n.addColorStop(Number(r), e[r]);
return i.fillStyle = n, i.fillRect(0, 0, 256, 1), i.getImageData(0, 0, 256, 1).data;
}, s.prototype._getPointTemplate = function(t, e) {
var a = document.createElement("canvas"), i = a.getContext("2d");
if (!i) return a;
var n = t, r = t;
if (a.width = a.height = 2 * t, e === 1) i.beginPath(), i.arc(n, r, t, 0, 2 * Math.PI, !1), i.fillStyle = "rgba(0,0,0,1)", i.fill();
else {
var o = i.createRadialGradient(n, r, t * e, n, r, t);
o.addColorStop(0, "rgba(0,0,0,1)"), o.addColorStop(1, "rgba(0,0,0,0)"), i.fillStyle = o, i.fillRect(0, 0, 2 * t, 2 * t);
}
return a;
}, s.prototype._prepareData = function(t) {
for (var e = [], a = t.min, i = t.max, n = t.radi, r = t.data, o = Object.keys(r), h = o.length; h--; ) for (var d = o[h], c = Object.keys(r[d]), l = c.length; l--; ) {
var p = c[l], u = r[d][p], m = n[d][p];
e.push({ x: Number(d), y: Number(p), value: u, radius: m });
}
return { min: a, max: i, data: e };
}, s.prototype._setStyles = function(t) {
this.blur = t.blur === 0 ? 0 : t.blur || y.defaultBlur, t.backgroundColor && (this.canvas.style.backgroundColor = t.backgroundColor), this.width = this.canvas.width = this.shadowCanvas.width = t.width || this.width, this.height = this.canvas.height = this.shadowCanvas.height = t.height || this.height, this.opacity = 255 * (t.opacity || 0), this.maxOpacity = 255 * (t.maxOpacity || y.defaultMaxOpacity), this.minOpacity = 255 * (t.minOpacity || y.defaultMinOpacity), this.useGradientOpacity = !!t.useGradientOpacity;
}, s.prototype._updateGradient = function(t) {
this.palette = this._getColorPalette(t);
}, s.prototype._drawAlpha = function(t) {
for (var e = this.min = t.min || 0, a = this.max = t.max || 100, i = t.data || [], n = i.length, r = 1 - this.blur; n--; ) {
var o = i[n], h = o.x, d = o.y, c = o.radius, l = Math.min(o.value, a), p = h - c, u = d - c;
if (!this.shadowCtx) return;
var m = void 0;
this.templates[c] ? m = this.templates[c] : this.templates[c] = m = this._getPointTemplate(c, r);
var g = (l - e) / (a - e);
this.shadowCtx.globalAlpha = g < 0.01 ? 0.01 : g, this.shadowCtx.drawImage(m, p, u), p < this.renderBoundaries[0] && (this.renderBoundaries[0] = p), u < this.renderBoundaries[1] && (this.renderBoundaries[1] = u), p + 2 * c > this.renderBoundaries[2] && (this.renderBoundaries[2] = p + 2 * c), u + 2 * c > this.renderBoundaries[3] && (this.renderBoundaries[3] = u + 2 * c);
}
}, s.prototype._colorize = function() {
var t = this.renderBoundaries[0], e = this.renderBoundaries[1], a = this.renderBoundaries[2] - t, i = this.renderBoundaries[3] - e, n = this.width, r = this.height;
if (t < 0 && (t = 0), e < 0 && (e = 0), t + a > n && (a = n - t), e + i > r && (i = r - e), this.ctx && this.shadowCtx) {
for (var o = this.shadowCtx.getImageData(t, e, a, i), h = 3; h < o.data.length; h += 4) {
var d, c = o.data[h], l = 4 * c;
l && (d = this.opacity > 0 ? this.opacity : c < this.maxOpacity ? c < this.minOpacity ? this.minOpacity : c : this.maxOpacity, o.data[h - 3] = this.palette[l], o.data[h - 2] = this.palette[l + 1], o.data[h - 1] = this.palette[l + 2], o.data[h] = this.useGradientOpacity ? this.palette[l + 3] : d);
}
this.ctx.putImageData(o, t, e), this.renderBoundaries = [1e3, 1e3, 0, 0];
}
}, s.prototype._clear = function() {
this.ctx && this.shadowCtx && (this.ctx.clearRect(0, 0, this.width, this.height), this.shadowCtx.clearRect(0, 0, this.width, this.height));
}, s;
})(), $ = (function() {
function s(t) {
this.config = t, this.renderer = new N(this.config), this.store = new V(this.config), this._init();
}
return s.prototype._init = function() {
var t = this;
this.store.coordinator.on("renderpartial", this.renderer.renderPartial, this.renderer), this.store.coordinator.on("renderall", this.renderer.renderAll, this.renderer), this.store.coordinator.on("extremachange", (function(e) {
t.config.onExtremaChange && t.config.onExtremaChange({ min: e.min, max: e.max, gradient: t.config.gradient || y.defaultGradient });
}));
}, s.prototype.addData = function(t) {
return this.store.addData(t), this;
}, s.prototype.setData = function(t) {
return this.store.setData(t), this;
}, s.prototype.setDataMaxx = function(t) {
return this.store.setDataMax(t), this;
}, s.prototype.setDataMin = function(t) {
return this.store.setDataMin(t), this;
}, s.prototype.repaint = function() {
return this.store.coordinator.emit("renderall", this.store._getInternalData()), this;
}, s.prototype.getData = function() {
return this.store.getData();
}, s.prototype.getDataURL = function() {
return this.renderer.getDataURL();
}, s.prototype.getValueAt = function(t) {
return this.renderer.getValueAt(t);
}, s;
})();
function W(s) {
const t = H(s), e = new B();
e.setFromMatrix3(t);
const a = s[0], i = e.clone();
i.setPosition(a);
const n = i.clone().invert(), r = s.map((p) => {
const u = p.clone().applyMatrix4(n);
return new P(u.x, u.y);
}), o = new j(r), h = new T(o), d = new A();
d.setFromPoints(r);
const c = X(d);
return h.getAttribute("uv").applyMatrix3(c), h.applyMatrix4(e), { geometry: h, polygonBox: d, modelMatrix: e, planeMatrix: i, projectionMatrix: n, position: a };
}
function H(s) {
const [t, e, a] = s, i = new F();
i.setFromCoplanarPoints(e, t, a);
const n = i.normal, r = n.clone().cross(new w(0, 0, 1));
r.equals(new w()) && r.set(1, 0, 0);
const o = n.clone().cross(r);
r.normalize(), o.normalize(), n.normalize();
const h = new O();
return h.elements = [
r.x,
r.y,
r.z,
o.x,
o.y,
o.z,
n.x,
n.y,
n.z
], h;
}
function X(s) {
const t = s.min, e = s.getSize(new P()), a = new O();
return a.elements = [
e.x,
0,
0,
0,
e.y,
0,
t.x,
t.y,
1
], a.invert();
}
function K(s, t) {
if (s >= t)
throw new Error("Min value must be less than max value.");
return Math.floor(Math.random() * (t - s + 1)) + s;
}
function Y(s, t, e, a, i, n) {
const {
min: r,
max: o,
radius: h,
beforePointUpdate: d,
value: c,
distanceInterval: l
} = e, p = i.object, u = n.viewport.getIntersects(s, [p]);
if (!(u?.length > 0))
return null;
const m = u[0].point.clone();
if (a.length > 0 && l) {
const { x, y: D, z: M } = a[a.length - 1], C = new w(x, D, M);
if (l > C.distanceTo(m))
return null;
}
const g = Array.isArray(c) ? K(c[0], c[1]) : c, v = { ...m, radius: h, value: g }, f = d?.(t, v, a);
return f === !1 ? null : typeof f == "object" ? f : v;
}
class q {
constructor(t, e) {
this.heatMapPlugin = t;
const { data: a = [] } = e;
this.ssp = t.ssp, this.store = t.store, this.createDrawingParam = e, this.dataPoints = [...a], this.object = t.createPolygon(e);
}
store = /* @__PURE__ */ new Map();
ssp;
// 用时间形式加热力点
intervalId = null;
// 存储鼠标当前所在点事件
currentMouseEvent = null;
// 最后一次获取热力点的时间,用于节流
lastTime;
// 绑定事件
events = {};
// 拖拽
isDragging = !1;
// 开始绘制
isStarting = !1;
createDrawingParam;
// 所有热力点
dataPoints = [];
// 热力图实例
object;
startResolve;
startReject;
// 开始绘制热力点 绑定事件
start = () => {
const { addTriggerType: t, doneTriggerType: e, undoTriggerType: a } = this.createDrawingParam;
return new Promise((i, n) => {
if (this.startResolve = i, this.startReject = n, this.isStarting) {
console.warn("请先取消绘制再调用start方法");
return;
}
this.isStarting = !0, this.handleEventListeners("add", t, this.handleAddPoint), this.handleEventListeners("add", e, this.done), this.handleEventListeners("add", a, this.popPoint);
});
};
// 取消
cancel = () => {
const { id: t } = this.createDrawingParam, e = [...this.dataPoints];
this.heatMapPlugin.setDataPolygon(t, []), this.remove(), this.startReject?.(e);
};
// 销毁
dispose = () => {
const { id: t } = this.createDrawingParam;
this.remove(), this.heatMapPlugin.removeById(t);
};
// 完成
done = () => {
const t = [...this.dataPoints];
this.remove(), this.startResolve?.(t);
};
// 移除监听
remove = () => {
const { addTriggerType: t, doneTriggerType: e, undoTriggerType: a } = this.createDrawingParam;
this.dataPoints = [], this.lastTime = void 0, this.setMouseEvent(null), this.handleEventListeners("remove", t, this.handleAddPoint), this.handleEventListeners("remove", e, this.done), this.handleEventListeners("remove", a, this.popPoint), this.events = {}, this.isDragging = !1, this.ssp.controls.enabled = !0, this.isStarting = !1;
};
// 增加热力点
pushPoint = (t) => {
if (!t)
return;
const { id: e, onAdd: a } = this.createDrawingParam, i = t;
this.dataPoints.push(i), this.heatMapPlugin.setDataPolygon(e, this.dataPoints), a?.(i, this.dataPoints);
};
// 删除上一个热力点
popPoint = () => {
const t = this.dataPoints?.length;
if (!(t > 0))
return;
const { id: e, beforePointUpdate: a, onUndo: i } = this.createDrawingParam, n = a?.(E.undo, this.dataPoints[t - 1], this.dataPoints);
if (n === !1)
return;
typeof n == "object" && (this.dataPoints[t - 1] = n);
const r = this.dataPoints.pop();
r && (this.heatMapPlugin.setDataPolygon(e, this.dataPoints), i?.(r, this.dataPoints));
};
handleAddPoint = (t) => {
if (!t?.clientX)
throw new Error("addTriggerType仅支持:time、drag、click、dblClick、rightClick、mouseDown、mouseMove、mouseUp、mouseWheel");
this.setMouseEvent(t);
const e = this.getPoint(t, E.add);
this.pushPoint(e);
};
// 设置鼠标事件
setMouseEvent = (t) => {
this.currentMouseEvent = t;
};
handleEventListeners = (t, e, a) => {
e?.length > 0 && (e.forEach((i) => {
if (typeof i == "object") {
for (const [n, r] of Object.entries(i)) {
const o = `${n}_${r.join("_")}`;
t === "add" && (this.events[o] = (h) => {
this.keyEvents(r, a, h);
}), this.ssp.signals[n]?.[t]?.(this.events[o]);
}
return;
}
if (i === "time") {
if (t === "add") {
const { timeInterval: n } = this.createDrawingParam || {};
this.ssp.signals.mouseMove.add(this.setMouseEvent), this.intervalId = window.setInterval(() => {
this.currentMouseEvent && a(this.currentMouseEvent);
}, n);
} else
this.ssp.signals.mouseMove.remove(this.setMouseEvent);
return;
}
if (i === "drag") {
const n = this.ssp.viewport.container, r = i;
t === "add" ? (this.events[r] = (o) => {
this.onPointerMove(a, o);
}, n.addEventListener("pointerdown", this.onPointerdown), n.addEventListener("pointermove", this.events[r]), n.addEventListener("pointerup", this.onPointerUp)) : (n.removeEventListener("pointerdown", this.onPointerdown), n.removeEventListener("pointermove", this.events[r]), n.removeEventListener("pointerup", this.onPointerUp));
return;
}
this.ssp.signals[i]?.[t]?.(a);
}), t === "remove" && this.intervalId && (clearInterval(this.intervalId), this.intervalId = null));
};
keyEvents(t, e, a) {
t?.includes(a.code) && e();
}
// 通过鼠标事件获取热力点
getPoint(t, e) {
const { id: a, timeInterval: i = 100 } = this.createDrawingParam;
if (this.lastTime && i && i > (/* @__PURE__ */ new Date()).getTime() - this.lastTime.getTime())
return null;
this.lastTime = /* @__PURE__ */ new Date();
const n = this.store.get(a);
return Y(t, e, this.createDrawingParam, this.dataPoints, n, this.ssp);
}
onPointerdown = (t) => {
this.ssp.controls.enabled = !1, this.isDragging = !0;
};
onPointerMove = (t, e) => {
e.preventDefault(), this.isDragging && t(e);
};
onPointerUp = (t) => {
this.isDragging = !1, this.ssp.controls.enabled = !0;
};
}
var E = /* @__PURE__ */ ((s) => (s.add = "add", s.undo = "undo", s))(E || {});
class Q {
constructor(t) {
this.ssp = t, this.hmInstance = null;
}
hmInstance;
store = /* @__PURE__ */ new Map();
maxCanvasSize = 512;
create(t) {
const {
id: e,
name: a,
yAxisHeight: i,
minPosition: n,
maxPosition: r,
data: o,
min: h = 0,
max: d = 100,
radius: c = 100,
canvasScalar: l = 1
} = t, p = new w((r.x + n.x) / 2, i, (r.z + n.z) / 2), u = r.x - n.x, m = r.z - n.z, g = this._formatCanvasSize(u * l, m * l), { canvas: v, hmInstance: f } = this.createInitData({ ...g, radius: c });
f.setData({
max: d,
min: h,
data: this._formatData(o, n, { width: u, height: m }, g)
});
const x = new L(u, m), D = new _(v), M = new z({
map: D,
depthWrite: !1,
transparent: !0
}), C = new R(x, M), b = this.ssp.createPluginObject({
id: e,
name: a,
position: p.clone(),
rotation: {
x: -Math.PI / 2,
y: 0,
z: 0
}
}, C);
return this.store.set(e, {
object: b,
canvas: v,
param: { ...t, min: h, max: d },
width: u,
height: m
}), b;
}
createPolygon(t) {
const {
id: e,
name: a,
points: i,
data: n,
min: r = 0,
max: o = 100,
radius: h = 100
} = t, d = i.map((I) => new w(I.x, I.y, I.z)), { geometry: c, projectionMatrix: l, polygonBox: p, position: u } = W(d);
new k().setFromPoints(d);
const { x: g, y: v } = p.getSize(new P()), f = this._formatCanvasSize(g, v), { canvas: x, hmInstance: D } = this.createInitData({ ...f, radius: h });
n && n.length > 0 && D.setData({
max: o,
min: r,
data: this._formatData_Polygon(n, l, p, f)
});
const M = new _(x), C = new z({
map: M,
depthWrite: !1,
transparent: !0,
side: G
}), b = new this.ssp.library.BaseMesh({ id: `${e}_mesh`, name: a }, c, C);
b.renderOrder = 0;
const S = this.ssp.createPluginObject({
id: e,
name: a,
position: u
}, b);
return this.store.set(e, {
object: S,
canvas: x,
param: { ...t, min: r, max: o },
width: g,
height: v,
projectionMatrix: l,
polygonBox: p,
position: u.clone()
}), S;
}
createDrawing(t) {
const {
data: e = [],
addTriggerType: a = ["click", "mouseMove"],
doneTriggerType: i = ["dblClick", { keyDown: ["Enter"] }],
undoTriggerType: n = ["rightClick", { keyDown: ["Backspace"] }],
timeInterval: r = 100,
min: o = 0,
max: h = 100,
radius: d = 100,
value: c = [o, h],
distanceInterval: l = 5,
...p
} = t, u = {
data: e,
addTriggerType: a,
doneTriggerType: i,
undoTriggerType: n,
timeInterval: r,
min: o,
max: h,
radius: d,
value: c,
distanceInterval: l,
...p
};
return new q(this, u);
}
setData(t, e) {
const a = this.store.get(t);
if (a) {
const { object: i, canvas: n, param: { minPosition: r, min: o, max: h }, width: d, height: c } = a, l = this.createInitData(), { canvas: p, hmInstance: u } = l;
u.renderer.updateConfig({
width: n.width,
height: n.height
}), u.setData({
max: h,
min: o,
data: this._formatData(e, r, { width: d, height: c }, this._formatCanvasSize(d, c))
});
const m = i.children[0].material;
return this.ssp.render(() => {
const g = new _(p);
m.map && m.map.dispose(), m.map = g;
}), i;
} else
return console.warn(`In soonspacejs: 插件(plugin-heat-map)未找到 id 为 '"${t}"' 的热力图对象!`);
}
setDataPolygon(t, e) {
const a = this.store.get(t);
if (a) {
const { object: i, canvas: n, param: { min: r, max: o }, projectionMatrix: h, polygonBox: d, position: c } = a;
if (!h) throw new Error(`${t} 不是多边形热力图类型`);
const p = this.getById(t)?.getWorldPosition(new w()), u = this.createInitData(), { canvas: m, hmInstance: g } = u;
g.renderer.updateConfig({
width: n.width,
height: n.height
});
const v = d.getSize(new P());
g.setData({
max: o,
min: r,
data: this._formatData_Polygon(e, h, d, this._formatCanvasSize(v.x, v.y), c, p)
});
const f = i.children[0].material;
return this.ssp.render(() => {
const x = new _(m);
f.map && f.map.dispose(), f.map = x;
}), i;
} else
return console.warn(`In soonspacejs: 插件(plugin-heat-map)未找到 id 为 '"${t}"' 的热力图对象!`);
}
getById(t) {
return this.ssp.getObjectById(t);
}
getByName(t) {
return this.ssp.getObjectByName(t);
}
removeById(t) {
return this.store.has(t) ? (this.ssp.removeObjectById(t), this.store.delete(t), !0) : !1;
}
createInitData(t) {
const e = this.hmInstance = new $(t || {});
return { hmInstance: e, canvas: e.renderer.canvas };
}
_formatCanvasSize(t, e) {
const a = t / e;
return t > this.maxCanvasSize && (t = this.maxCanvasSize, e = t / a), e > this.maxCanvasSize && (e = this.maxCanvasSize, t = a * e), { width: t, height: e };
}
_formatData(t, e, a, i) {
return t.map((n) => ({
...n,
// 取整,否则不生效
x: Math.trunc((n.x - e.x) / a.width * i.width),
y: Math.trunc((n.z - e.z) / a.height * i.height)
}));
}
_formatData_Polygon(t, e, a, i, n, r) {
const o = n && r ? r.clone().sub(n) : new w(0, 0, 0);
return t.map((h) => {
const d = new w(h.x, h.y, h.z);
d.sub(o), d.applyMatrix4(e);
const { x: c, y: l } = a.getParameter(new P(d.x, d.y), new P());
return {
...h,
// 取整,否则不生效
x: Math.trunc(c * i.width),
// 热力图图片的 y 轴的正方向是 从 图片上方 到 图片 下方
y: Math.trunc((1 - l) * i.height)
};
});
}
}
export {
E as StartEventType,
Q as default
};