@orca-fe/x-map
Version:
124 lines (123 loc) • 5.21 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
/* eslint-disable no-param-reassign */
const three_1 = require("three");
const supercluster_1 = tslib_1.__importDefault(require("supercluster"));
const ThreeObject_1 = tslib_1.__importDefault(require("./ThreeObject"));
const heatmap_1 = tslib_1.__importDefault(require("./heatmap"));
const coord_1 = require("../../utils/coord");
const private_1 = require("../../utils/private");
const ThreeLayer_1 = tslib_1.__importDefault(require("../ThreeLayer"));
function rangeDiff(min, max, value) {
if (value < min)
return value - min;
if (value > max)
return value - max;
return 0;
}
function toGeoJSONPoint(data) {
return data.map(({ value, lng, lat }) => ({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [lng, lat],
},
properties: {
value,
lng,
lat,
},
}));
}
class HeatmapObject extends ThreeObject_1.default {
constructor(options) {
super();
this.material = new three_1.MeshBasicMaterial({ side: three_1.FrontSide, opacity: 0.5, transparent: true });
this.canvas = document.createElement('canvas');
this.sc = new supercluster_1.default({
maxZoom: 1,
});
this.dom = document.createElement('div');
this.redraw = () => {
var _a;
if ((_a = this.layer) === null || _a === void 0 ? void 0 : _a.map) {
const { map } = this.layer;
const { threeCenter } = map;
// 取得屏幕尺寸
const { zoom } = map.getViewport();
const bounds = map.getBounds();
const [minMercator, maxMercator] = bounds.map(coord_1.lonLat2Mercator);
const mercatorSize = [maxMercator[0] - minMercator[0], maxMercator[1] - minMercator[1]];
const size = map.getSize();
// 根据屏幕尺寸,计算出热力图 canvas 的尺寸
const scale = ((Math.pow(2, zoom) / coord_1.MercatorMax) * Math.min(size[0], size[1])) / 20;
const canvasSize = [mercatorSize[0] * scale, mercatorSize[1] * scale];
const [width, height] = canvasSize;
[this.canvas.width, this.canvas.height] = canvasSize;
this.canvas.style.width = `${this.canvas.width}px`;
this.canvas.style.height = `${this.canvas.height}px`;
let radius = Math.round(20 * Math.pow(2, rangeDiff(12, 15, zoom)));
radius = Math.max(2, radius);
const points = this.data.map((p) => {
const [x, y] = (0, coord_1.lonLat2Mercator)([p.x, p.y]);
return {
x: Math.round((x - minMercator[0]) * scale),
y: -Math.round((y - maxMercator[1]) * scale),
value: p.value,
};
});
this.heatmap = heatmap_1.default.create({
container: this.dom,
canvas: this.canvas,
radius,
width,
height,
});
this.heatmap.setData({
min: 0,
max: 100,
data: points,
});
this.heatmap.repaint();
// 重新调整 平面的尺寸
const center = [
0.5 * (minMercator[0] + maxMercator[0]) - threeCenter[0],
0.5 * (minMercator[1] + maxMercator[1]) - threeCenter[1],
];
if (this.material.map)
this.material.map.needsUpdate = true;
this.object3D.position.set(center[0], center[1], 1);
this.object3D.scale.set(Math.abs(maxMercator[0] - minMercator[0]), Math.abs(maxMercator[1] - minMercator[1]), 1);
if (this.layer instanceof ThreeLayer_1.default) {
this.layer.three.render();
}
}
};
this.redrawDebounce = (0, private_1.debounce)(this.redraw, 300, { maxWait: 1000 });
const { data = [] } = options;
this.data = data.map(({ lng, lat, value }) => ({
x: lng,
y: lat,
value,
}));
this.sc.load(toGeoJSONPoint(data));
this.object3D = new three_1.Mesh(new three_1.PlaneGeometry(1, 1, 2), this.material);
this.material.map = new three_1.CanvasTexture(this.canvas);
document.body.append(this.dom);
this.dom.style.display = 'none';
this.dom.append(this.canvas);
this.heatmap = heatmap_1.default.create({
container: this.dom,
canvas: this.canvas,
radius: 10,
});
}
updatePosition() {
this.redrawDebounce();
}
createObject() {
this.redraw();
}
}
exports.default = HeatmapObject;