mirror of https://gitee.com/antv-l7/antv-l7
feat(l7): feat heatmap layer
This commit is contained in:
parent
e0addf89b6
commit
ad8a5a3c5e
|
@ -42,15 +42,6 @@ scene.on('loaded', () => {
|
|||
}
|
||||
})
|
||||
.render();
|
||||
|
||||
/* scene.PointLayer({
|
||||
zIndex: 3
|
||||
})
|
||||
.source(data)
|
||||
.shape('2d:circle')
|
||||
.size(2)
|
||||
.color('#EE2C2C')
|
||||
.render();*/
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import BufferBase from './bufferBase';
|
||||
import { colorScales } from '../../attr/colorscales';
|
||||
import * as THREE from '../../core/three';
|
||||
import BufferBase from '../bufferBase';
|
||||
import { colorScales } from '../../../attr/colorscales';
|
||||
import * as THREE from '../../../core/three';
|
||||
|
||||
|
||||
export default class HeatmapBuffer extends BufferBase {
|
|
@ -1,55 +0,0 @@
|
|||
import Layer from '../core/layer';
|
||||
import gridBuffer from '../geom/buffer/heatmap/grid';
|
||||
import DrawGrid from './render/heatmap/gird';
|
||||
import DrawHexagon from './render/heatmap/hexagon';
|
||||
import hexagonBuffer from '../geom/buffer/heatmap/hexagon';
|
||||
|
||||
export default class HeatMapLayer extends Layer {
|
||||
shape(type) {
|
||||
this.shapeType = type;
|
||||
return this;
|
||||
}
|
||||
render() {
|
||||
this._prepareRender();
|
||||
return this;
|
||||
}
|
||||
_prepareRender() {
|
||||
this.init();
|
||||
switch (this.shapeType) {
|
||||
case 'grid' :
|
||||
this._drawGrid();
|
||||
break;
|
||||
case 'hexagon' :
|
||||
this._drawHexagon();
|
||||
break;
|
||||
default:
|
||||
this._drawGrid();
|
||||
}
|
||||
}
|
||||
_drawHexagon() {
|
||||
const style = this.get('styleOptions');
|
||||
const { radius } = this.layerSource.data;
|
||||
this._buffer = new hexagonBuffer(this.layerData);
|
||||
const config = {
|
||||
...style,
|
||||
radius
|
||||
};
|
||||
const Mesh = new DrawHexagon(this._buffer, config);
|
||||
this.add(Mesh);
|
||||
|
||||
}
|
||||
_drawGrid() {
|
||||
this.type = 'heatmap';
|
||||
const style = this.get('styleOptions');
|
||||
const { xOffset, yOffset } = this.layerSource.data;
|
||||
this._buffer = new gridBuffer(this.layerData);
|
||||
const config = {
|
||||
...style,
|
||||
xOffset,
|
||||
yOffset
|
||||
};
|
||||
const girdMesh = new DrawGrid(this._buffer, config);
|
||||
this.add(girdMesh);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,111 +1,55 @@
|
|||
import Layer from '../core/layer';
|
||||
import HeatmapBuffer from '../geom/buffer/heatmap';
|
||||
import { createColorRamp } from '../geom/buffer/heatmap';
|
||||
import { HeatmapIntensityMaterial, HeatmapColorizeMaterial } from '../geom/material/heatmapMateial';
|
||||
import Renderpass from '../core/engine/renderpass';
|
||||
import * as THREE from '../core/three';
|
||||
|
||||
export default class HeatmapLayer extends Layer {
|
||||
import gridBuffer from '../geom/buffer/heatmap/grid';
|
||||
import DrawGrid from './render/heatmap/gird';
|
||||
import DrawHexagon from './render/heatmap/hexagon';
|
||||
import drawHeatmap from './render/heatmap/heatmap';
|
||||
import hexagonBuffer from '../geom/buffer/heatmap/hexagon';
|
||||
|
||||
export default class HeatMapLayer extends Layer {
|
||||
shape(type) {
|
||||
this.shapeType = type;
|
||||
return this;
|
||||
}
|
||||
render() {
|
||||
this._prepareRender();
|
||||
return this;
|
||||
}
|
||||
_prepareRender() {
|
||||
this.init();
|
||||
const bbox = this._calBoundingBox(this.layerData);
|
||||
const colors = this.get('styleOptions').rampColors;
|
||||
this.colorRamp = createColorRamp(colors);
|
||||
this._createIntensityPass(bbox);
|
||||
this._createColorizePass(bbox);
|
||||
this.type = 'heatmap';
|
||||
switch (this.shapeType) {
|
||||
case 'grid' :
|
||||
this._drawGrid();
|
||||
break;
|
||||
case 'hexagon' :
|
||||
this._drawHexagon();
|
||||
break;
|
||||
default:
|
||||
drawHeatmap(this);
|
||||
}
|
||||
}
|
||||
|
||||
_createIntensityPass(bbox) {
|
||||
_drawHexagon() {
|
||||
const style = this.get('styleOptions');
|
||||
const data = this.layerData;
|
||||
// get attributes data
|
||||
const buffer = new HeatmapBuffer({
|
||||
data
|
||||
});
|
||||
const attributes = buffer.attributes;
|
||||
// create geometery
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
// geometry.setIndex(attributes.indices);
|
||||
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
|
||||
geometry.addAttribute('a_dir', new THREE.Float32BufferAttribute(attributes.dirs, 2));
|
||||
geometry.addAttribute('a_weight', new THREE.Float32BufferAttribute(attributes.weights, 1));
|
||||
// set material
|
||||
const material = new HeatmapIntensityMaterial({
|
||||
intensity: style.intensity,
|
||||
radius: style.radius,
|
||||
zoom: this.scene.getZoom()
|
||||
});
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
// set camera
|
||||
const passOrth = new THREE.OrthographicCamera(bbox.width / -2, bbox.width / 2, bbox.height / 2, bbox.height / -2, 1, 10000);
|
||||
passOrth.position.set(bbox.minX + bbox.width / 2, bbox.minY + bbox.height / 2, 1000);
|
||||
// renderpass
|
||||
const renderpass = new Renderpass({
|
||||
renderer: this.scene._engine._renderer,
|
||||
camera: passOrth,
|
||||
size: {
|
||||
width: 10000,
|
||||
height: 10000 * (bbox.height / bbox.width)
|
||||
},
|
||||
clear: {
|
||||
clearColor: 0x000000,
|
||||
clearAlpha: 1.0
|
||||
}
|
||||
});
|
||||
renderpass.add(mesh);
|
||||
renderpass.render();
|
||||
this.intensityPass = renderpass;
|
||||
const scene = this.scene;
|
||||
render();
|
||||
function render() {
|
||||
requestAnimationFrame(render);
|
||||
renderpass.render();
|
||||
mesh.material.uniforms.u_zoom.value = scene.getZoom();
|
||||
}
|
||||
}
|
||||
_createColorizePass(bbox) {
|
||||
// create plane geometry
|
||||
const geometery = new THREE.PlaneBufferGeometry(bbox.width, bbox.height);
|
||||
const material = new HeatmapColorizeMaterial({
|
||||
texture: this.intensityPass.texture,
|
||||
colorRamp: this.colorRamp
|
||||
});
|
||||
const mesh = new THREE.Mesh(geometery, material);
|
||||
mesh.position.set(bbox.minX + bbox.width / 2, bbox.minY + bbox.height / 2, 0.0);
|
||||
this.add(mesh);
|
||||
}
|
||||
|
||||
_calBoundingBox(data) {
|
||||
let minX = Infinity;
|
||||
let minY = Infinity;
|
||||
let maxX = -Infinity;
|
||||
let maxY = -Infinity;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const p = data[i].coordinates;
|
||||
if (p[0] < minX) {
|
||||
minX = p[0];
|
||||
} else if (p[0] > maxX) {
|
||||
maxX = p[0];
|
||||
}
|
||||
if (p[1] < minY) {
|
||||
minY = p[1];
|
||||
} else if (p[1] > maxY) {
|
||||
maxY = p[1];
|
||||
}
|
||||
}
|
||||
const width = maxX - minX;
|
||||
const height = maxY - minY;
|
||||
|
||||
return {
|
||||
minX,
|
||||
maxX,
|
||||
minY,
|
||||
maxY,
|
||||
width,
|
||||
height
|
||||
const { radius } = this.layerSource.data;
|
||||
this._buffer = new hexagonBuffer(this.layerData);
|
||||
const config = {
|
||||
...style,
|
||||
radius
|
||||
};
|
||||
const Mesh = new DrawHexagon(this._buffer, config);
|
||||
this.add(Mesh);
|
||||
}
|
||||
_drawGrid() {
|
||||
const style = this.get('styleOptions');
|
||||
const { xOffset, yOffset } = this.layerSource.data;
|
||||
this._buffer = new gridBuffer(this.layerData);
|
||||
const config = {
|
||||
...style,
|
||||
xOffset,
|
||||
yOffset
|
||||
};
|
||||
const girdMesh = new DrawGrid(this._buffer, config);
|
||||
this.add(girdMesh);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,14 +5,12 @@ import LineLayer from './lineLayer';
|
|||
import ImageLayer from './imageLayer';
|
||||
import RasterLayer from './rasterLayer';
|
||||
import HeatmapLayer from './heatmapLayer';
|
||||
import HeatMapLayer from './heatmap';
|
||||
|
||||
registerLayer('PolygonLayer', PolygonLayer);
|
||||
registerLayer('PointLayer', PointLayer);
|
||||
registerLayer('LineLayer', LineLayer);
|
||||
registerLayer('ImageLayer', ImageLayer);
|
||||
registerLayer('RasterLayer', RasterLayer);
|
||||
registerLayer('HeatMapLayer', HeatMapLayer);
|
||||
registerLayer('HeatmapLayer', HeatmapLayer);
|
||||
|
||||
export { LAYER_MAP } from './factory';
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
import HeatmapBuffer from '../../../geom/buffer/heatmap/heatmap';
|
||||
import { createColorRamp } from '../../../geom/buffer/heatmap/heatmap';
|
||||
import { HeatmapIntensityMaterial, HeatmapColorizeMaterial } from '../../../geom/material/heatmapMateial';
|
||||
import Renderpass from '../../../core/engine/renderpass';
|
||||
import * as THREE from '../../../core/three';
|
||||
|
||||
export default function drawHeatmap(layer) {
|
||||
const bbox = calBoundingBox(layer.layerData);
|
||||
const colors = layer.get('styleOptions').rampColors;
|
||||
layer.colorRamp = createColorRamp(colors);
|
||||
createIntensityPass(layer, bbox);
|
||||
createColorizePass(layer, bbox);
|
||||
}
|
||||
|
||||
function createIntensityPass(layer, bbox) {
|
||||
const style = layer.get('styleOptions');
|
||||
const data = layer.layerData;
|
||||
// get attributes data
|
||||
const buffer = new HeatmapBuffer({
|
||||
data
|
||||
});
|
||||
const attributes = buffer.attributes;
|
||||
// create geometery
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
// geometry.setIndex(attributes.indices);
|
||||
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
|
||||
geometry.addAttribute('a_dir', new THREE.Float32BufferAttribute(attributes.dirs, 2));
|
||||
geometry.addAttribute('a_weight', new THREE.Float32BufferAttribute(attributes.weights, 1));
|
||||
// set material
|
||||
const material = new HeatmapIntensityMaterial({
|
||||
intensity: style.intensity,
|
||||
radius: style.radius,
|
||||
zoom: layer.scene.getZoom()
|
||||
});
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
// set camera
|
||||
const passOrth = new THREE.OrthographicCamera(bbox.width / -2, bbox.width / 2, bbox.height / 2, bbox.height / -2, 1, 10000);
|
||||
passOrth.position.set(bbox.minX + bbox.width / 2, bbox.minY + bbox.height / 2, 1000);
|
||||
// renderpass
|
||||
const renderpass = new Renderpass({
|
||||
renderer: layer.scene._engine._renderer,
|
||||
camera: passOrth,
|
||||
size: {
|
||||
width: 10000,
|
||||
height: 10000 * (bbox.height / bbox.width)
|
||||
},
|
||||
clear: {
|
||||
clearColor: 0x000000,
|
||||
clearAlpha: 1.0
|
||||
}
|
||||
});
|
||||
renderpass.add(mesh);
|
||||
renderpass.render();
|
||||
layer.intensityPass = renderpass;
|
||||
const scene = layer.scene;
|
||||
render();
|
||||
function render() {
|
||||
requestAnimationFrame(render);
|
||||
renderpass.render();
|
||||
mesh.material.uniforms.u_zoom.value = scene.getZoom();
|
||||
}
|
||||
}
|
||||
function createColorizePass(layer, bbox) {
|
||||
// create plane geometry
|
||||
const geometery = new THREE.PlaneBufferGeometry(bbox.width, bbox.height);
|
||||
const material = new HeatmapColorizeMaterial({
|
||||
texture: layer.intensityPass.texture,
|
||||
colorRamp: layer.colorRamp
|
||||
});
|
||||
const mesh = new THREE.Mesh(geometery, material);
|
||||
mesh.position.set(bbox.minX + bbox.width / 2, bbox.minY + bbox.height / 2, 0.0);
|
||||
layer.add(mesh);
|
||||
}
|
||||
|
||||
function calBoundingBox(data) {
|
||||
let minX = Infinity;
|
||||
let minY = Infinity;
|
||||
let maxX = -Infinity;
|
||||
let maxY = -Infinity;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const p = data[i].coordinates;
|
||||
if (p[0] < minX) {
|
||||
minX = p[0];
|
||||
} else if (p[0] > maxX) {
|
||||
maxX = p[0];
|
||||
}
|
||||
if (p[1] < minY) {
|
||||
minY = p[1];
|
||||
} else if (p[1] > maxY) {
|
||||
maxY = p[1];
|
||||
}
|
||||
}
|
||||
const width = maxX - minX;
|
||||
const height = maxY - minY;
|
||||
|
||||
return {
|
||||
minX,
|
||||
maxX,
|
||||
minY,
|
||||
maxY,
|
||||
width,
|
||||
height
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue