mirror of https://gitee.com/antv-l7/antv-l7
feat(tilelayer): add mask
This commit is contained in:
parent
b39f6c297a
commit
e018661b7a
|
@ -0,0 +1,53 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<meta name="geometry" content="diagram">
|
||||||
|
<link rel="stylesheet" href="./assets/common.css">
|
||||||
|
<link rel="stylesheet" href="./assets/info.css">
|
||||||
|
|
||||||
|
<title>hexagon demo</title>
|
||||||
|
<style>
|
||||||
|
body {margin: 0;}
|
||||||
|
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="map"></div>
|
||||||
|
<script src="https://webapi.amap.com/maps?v=1.4.8&key=15cd8a57710d40c9b7c0e3cc120f1200&plugin=Map3D"></script>
|
||||||
|
<script src="./assets/jquery-3.2.1.min.js"></script>
|
||||||
|
<script src="./assets/dat.gui.min.js"></script>
|
||||||
|
<script src="../build/L7.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
const scene = new L7.Scene({
|
||||||
|
id: 'map',
|
||||||
|
mapStyle: 'light', // 样式URL
|
||||||
|
center: [120.05859375,30.29701788337204 ],
|
||||||
|
pitch: 0,
|
||||||
|
hash:true,
|
||||||
|
zoom: 11,
|
||||||
|
|
||||||
|
});
|
||||||
|
window.scene = scene;
|
||||||
|
scene.on('loaded', () => {
|
||||||
|
const layer = scene.VectorTileLayer({
|
||||||
|
zIndex:0
|
||||||
|
})
|
||||||
|
//.source('https://pre-lbs-show.taobao.com/gettile?x={x}&y={y}&z={z}&pipeId=pipe_vt_test')
|
||||||
|
// https://mvt.amap.com/district/CHN2/8/203/105/4096?key=
|
||||||
|
.source('http://localhost:5000/test.mbtile/{z}/{x}/{y}.pbf')
|
||||||
|
.shape('line')
|
||||||
|
.color('red')
|
||||||
|
.render();
|
||||||
|
|
||||||
|
console.log(layer);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@antv/l7",
|
"name": "@antv/l7",
|
||||||
"version": "1.1.10",
|
"version": "1.1.11",
|
||||||
"description": "Large-scale WebGL-powered Geospatial Data Visualization",
|
"description": "Large-scale WebGL-powered Geospatial Data Visualization",
|
||||||
"main": "build/l7.js",
|
"main": "build/l7.js",
|
||||||
"browser": "build/l7.js",
|
"browser": "build/l7.js",
|
||||||
|
|
|
@ -24,11 +24,14 @@ export default class Engine extends EventEmitter {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
update() {
|
update() {
|
||||||
|
this._renderer.clear();
|
||||||
this._renderer.render(this._scene, this._camera);
|
this._renderer.render(this._scene, this._camera);
|
||||||
this._initPostProcessing();
|
this._initPostProcessing();
|
||||||
}
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
|
}
|
||||||
|
renderScene(scene) {
|
||||||
|
this._renderer.render(scene, this._camera);
|
||||||
}
|
}
|
||||||
run() {
|
run() {
|
||||||
this.update();
|
this.update();
|
||||||
|
|
|
@ -9,7 +9,8 @@ export default class Renderer {
|
||||||
initRender() {
|
initRender() {
|
||||||
this.renderer = new THREE.WebGLRenderer({
|
this.renderer = new THREE.WebGLRenderer({
|
||||||
antialias: true,
|
antialias: true,
|
||||||
alpha: true
|
alpha: true,
|
||||||
|
autoClear: false
|
||||||
});
|
});
|
||||||
this.renderer.setClearColor(0xff0000, 0.0);
|
this.renderer.setClearColor(0xff0000, 0.0);
|
||||||
this.pixelRatio = window.devicePixelRatio;
|
this.pixelRatio = window.devicePixelRatio;
|
||||||
|
|
|
@ -309,7 +309,7 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
|
|
||||||
createScale(field) {
|
createScale(field) {
|
||||||
const data = this.layerSource.data.dataArray;
|
const data = this.layerSource ? this.layerSource.data.dataArray : null;
|
||||||
const scales = this.get('scales');
|
const scales = this.get('scales');
|
||||||
let scale = scales[field];
|
let scale = scales[field];
|
||||||
const scaleController = this.get('scaleController');
|
const scaleController = this.get('scaleController');
|
||||||
|
@ -404,7 +404,7 @@ export default class Layer extends Base {
|
||||||
const nextAttrs = this.get('attrOptions');
|
const nextAttrs = this.get('attrOptions');
|
||||||
const preStyle = this.get('preStyleOption');
|
const preStyle = this.get('preStyleOption');
|
||||||
const nextStyle = this.get('styleOptions');
|
const nextStyle = this.get('styleOptions');
|
||||||
if (preAttrs === undefined && preStyle === undefined) {
|
if (preAttrs === undefined && preStyle === undefined) { // 首次渲染
|
||||||
this._mapping();
|
this._mapping();
|
||||||
this._setPreOption();
|
this._setPreOption();
|
||||||
this._scaleByZoom();
|
this._scaleByZoom();
|
||||||
|
@ -490,12 +490,13 @@ export default class Layer extends Base {
|
||||||
this.layerMesh.material.updateUninform(newOption);
|
this.layerMesh.material.updateUninform(newOption);
|
||||||
|
|
||||||
}
|
}
|
||||||
_mapping() {
|
_mapping(source) {
|
||||||
const self = this;
|
const self = this;
|
||||||
const attrs = self.get('attrs');
|
const attrs = self.get('attrs');
|
||||||
const mappedData = [];
|
const mappedData = [];
|
||||||
// const data = this.layerSource.propertiesData;
|
// const data = this.layerSource.propertiesData;
|
||||||
const data = this.layerSource.data.dataArray;
|
let data;
|
||||||
|
source ? data = source.data.dataArray : data = this.layerSource.data.dataArray;
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
const record = data[i];
|
const record = data[i];
|
||||||
const newRecord = {};
|
const newRecord = {};
|
||||||
|
@ -528,14 +529,16 @@ export default class Layer extends Base {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.layerData = mappedData;
|
this.layerData = mappedData;
|
||||||
|
return mappedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新地图映射
|
// 更新地图映射
|
||||||
_updateMaping() {
|
_updateMaping(source, layer) {
|
||||||
const self = this;
|
const self = this;
|
||||||
const attrs = self.get('attrs');
|
const attrs = self.get('attrs');
|
||||||
|
|
||||||
const data = this.layerSource.data.dataArray;
|
const data = source ? source.data.dataArray : this.layerSource.data.dataArray;
|
||||||
|
const layerData = layer || this.layerData;
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
const record = data[i];
|
const record = data[i];
|
||||||
for (const attrName in attrs) {
|
for (const attrName in attrs) {
|
||||||
|
@ -547,10 +550,10 @@ export default class Layer extends Base {
|
||||||
for (let j = 0; j < values.length; j++) {
|
for (let j = 0; j < values.length; j++) {
|
||||||
const val = values[j];
|
const val = values[j];
|
||||||
const name = names[j];
|
const name = names[j];
|
||||||
this.layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
||||||
|
|
||||||
}
|
}
|
||||||
attr.neadUpdate = true;
|
attr.neadUpdate = true;
|
||||||
|
@ -668,6 +671,7 @@ export default class Layer extends Base {
|
||||||
pickAttr.needsUpdate = true;
|
pickAttr.needsUpdate = true;
|
||||||
}
|
}
|
||||||
_visibleWithZoom() {
|
_visibleWithZoom() {
|
||||||
|
if (this._object3D === null) return;
|
||||||
const zoom = this.scene.getZoom();
|
const zoom = this.scene.getZoom();
|
||||||
const minZoom = this.get('minZoom');
|
const minZoom = this.get('minZoom');
|
||||||
const maxZoom = this.get('maxZoom');
|
const maxZoom = this.get('maxZoom');
|
||||||
|
@ -751,7 +755,6 @@ export default class Layer extends Base {
|
||||||
this.clearMapEvent();
|
this.clearMapEvent();
|
||||||
if (this._object3D.type === 'composer') {
|
if (this._object3D.type === 'composer') {
|
||||||
this.remove(this._object3D);
|
this.remove(this._object3D);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this._object3D && this._object3D.children) {
|
if (this._object3D && this._object3D.children) {
|
||||||
|
@ -778,8 +781,19 @@ export default class Layer extends Base {
|
||||||
child = null;
|
child = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.layerMesh.geometry = null;
|
||||||
|
this.layerMesh.material.dispose();
|
||||||
|
this.layerMesh.material = null;
|
||||||
|
if (this._pickingMesh) {
|
||||||
|
this._pickingMesh.children[0].geometry = null;
|
||||||
|
this._pickingMesh.children[0].material.dispose();
|
||||||
|
this._pickingMesh.children[0].material = null;
|
||||||
|
}
|
||||||
|
this._buffer = null;
|
||||||
this._object3D = null;
|
this._object3D = null;
|
||||||
this.scene._engine._scene.remove(this._object3D);
|
this.scene._engine._scene.remove(this._object3D);
|
||||||
|
this.layerData.length = 0;
|
||||||
|
this.layerSource = null;
|
||||||
this.scene._engine._picking.remove(this._pickingMesh);
|
this.scene._engine._picking.remove(this._pickingMesh);
|
||||||
this.destroyed = true;
|
this.destroyed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,8 @@ export default class Scene extends Base {
|
||||||
|
|
||||||
_initEngine(mapContainer) {
|
_initEngine(mapContainer) {
|
||||||
this._engine = new Engine(mapContainer, this);
|
this._engine = new Engine(mapContainer, this);
|
||||||
this.registerMapEvent();
|
// this.registerMapEvent();
|
||||||
|
this._engine.run();
|
||||||
// this.workerPool = new WorkerPool();
|
// this.workerPool = new WorkerPool();
|
||||||
compileBuiltinModules();
|
compileBuiltinModules();
|
||||||
}
|
}
|
||||||
|
@ -73,7 +74,6 @@ export default class Scene extends Base {
|
||||||
}
|
}
|
||||||
off(type, hander) {
|
off(type, hander) {
|
||||||
if (this.map) { this.map.off(type, hander); }
|
if (this.map) { this.map.off(type, hander); }
|
||||||
|
|
||||||
super.off(type, hander);
|
super.off(type, hander);
|
||||||
}
|
}
|
||||||
addImage() {
|
addImage() {
|
||||||
|
|
|
@ -87,6 +87,7 @@ export default class LineBuffer extends BufferBase {
|
||||||
layerData.forEach(item => {
|
layerData.forEach(item => {
|
||||||
const props = item;
|
const props = item;
|
||||||
const positionCount = positions.length / 3;
|
const positionCount = positions.length / 3;
|
||||||
|
// TODO 处理多个线段的情况
|
||||||
const attr = lineShape.Line(item.coordinates, props, positionCount, (lineType !== 'soild'));
|
const attr = lineShape.Line(item.coordinates, props, positionCount, (lineType !== 'soild'));
|
||||||
positions.push(...attr.positions);
|
positions.push(...attr.positions);
|
||||||
normal.push(...attr.normal);
|
normal.push(...attr.normal);
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import Material from './../material';
|
||||||
|
import { getModule } from '../../../util/shaderModule';
|
||||||
|
export default class MaskMaterial extends Material {
|
||||||
|
getDefaultParameters() {
|
||||||
|
return {
|
||||||
|
uniforms: {
|
||||||
|
},
|
||||||
|
defines: {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
constructor(_uniforms, _defines, parameters) {
|
||||||
|
super(parameters);
|
||||||
|
const { uniforms, defines } = this.getDefaultParameters();
|
||||||
|
const { vs, fs } = getModule('mask_quard');
|
||||||
|
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
|
||||||
|
this.type = 'MaskMaterial';
|
||||||
|
this.defines = Object.assign(defines, _defines);
|
||||||
|
this.vertexShader = vs;
|
||||||
|
this.fragmentShader = fs;
|
||||||
|
this.transparent = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,11 @@ import raster_frag from '../shader/raster_frag.glsl';
|
||||||
import tile_polygon_vert from '../shader/tile/polygon_vert.glsl';
|
import tile_polygon_vert from '../shader/tile/polygon_vert.glsl';
|
||||||
import tile_polygon_frag from '../shader/tile/polygon_frag.glsl';
|
import tile_polygon_frag from '../shader/tile/polygon_frag.glsl';
|
||||||
|
|
||||||
|
// mask
|
||||||
|
import mask_quard_vert from '../shader/tile/mask_quard_vert.glsl';
|
||||||
|
import mask_quard_frag from '../shader/tile/mask_quard_frag.glsl';
|
||||||
|
|
||||||
|
|
||||||
import common from './common.glsl';
|
import common from './common.glsl';
|
||||||
import { registerModule } from '../../util/shaderModule';
|
import { registerModule } from '../../util/shaderModule';
|
||||||
import pick_color from './shaderChunks/pick_color.glsl';
|
import pick_color from './shaderChunks/pick_color.glsl';
|
||||||
|
@ -65,5 +70,6 @@ export function compileBuiltinModules() {
|
||||||
registerModule('image', { vs: image_vert, fs: image_frag });
|
registerModule('image', { vs: image_vert, fs: image_frag });
|
||||||
registerModule('raster', { vs: raster_vert, fs: raster_frag });
|
registerModule('raster', { vs: raster_vert, fs: raster_frag });
|
||||||
registerModule('tilepolygon', { vs: tile_polygon_vert, fs: tile_polygon_frag });
|
registerModule('tilepolygon', { vs: tile_polygon_vert, fs: tile_polygon_frag });
|
||||||
|
registerModule('mask_quard', { vs: mask_quard_vert, fs: mask_quard_frag });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
precision highp float;
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = vec4(1.0);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
precision highp float;
|
||||||
|
void main(){
|
||||||
|
mat4 matModelViewProjection=projectionMatrix*modelViewMatrix;
|
||||||
|
gl_Position = matModelViewProjection * vec4(position, 1.0);
|
||||||
|
|
||||||
|
}
|
|
@ -65,7 +65,10 @@ export function defaultLine(geo, index) {
|
||||||
}
|
}
|
||||||
// mesh line
|
// mesh line
|
||||||
export function Line(path, props, positionsIndex) {
|
export function Line(path, props, positionsIndex) {
|
||||||
if (path.length === 1) path = path[0];// 面坐标转线坐标
|
// 区分path是面还是线
|
||||||
|
if (Array.isArray(path[0][0])) {
|
||||||
|
path = path[0]; // 面坐标转线坐标
|
||||||
|
}
|
||||||
const positions = [];
|
const positions = [];
|
||||||
const pickingIds = [];
|
const pickingIds = [];
|
||||||
const normal = [];
|
const normal = [];
|
||||||
|
@ -77,7 +80,8 @@ export function Line(path, props, positionsIndex) {
|
||||||
const sizes = [];
|
const sizes = [];
|
||||||
let c = 0;
|
let c = 0;
|
||||||
let index = positionsIndex;
|
let index = positionsIndex;
|
||||||
const { size, color, id } = props;
|
let { size, color, id } = props;
|
||||||
|
!Array.isArray(size) && (size = [ size ]);
|
||||||
path.forEach((point, pointIndex, list) => {
|
path.forEach((point, pointIndex, list) => {
|
||||||
const i = index;
|
const i = index;
|
||||||
colors.push(...color);
|
colors.push(...color);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// const Global = {};
|
// const Global = {};
|
||||||
const FONT_FAMILY = '"-apple-system", BlinkMacSystemFont, "Segoe UI", Roboto,"Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",SimSun, "sans-serif"';
|
const FONT_FAMILY = '"-apple-system", BlinkMacSystemFont, "Segoe UI", Roboto,"Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",SimSun, "sans-serif"';
|
||||||
const Global = {
|
const Global = {
|
||||||
version: '1.0.0',
|
version: '1.11.1',
|
||||||
scene: {
|
scene: {
|
||||||
mapType: 'AMAP',
|
mapType: 'AMAP',
|
||||||
zoom: 5,
|
zoom: 5,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import RasterLayer from './rasterLayer';
|
||||||
import HeatmapLayer from './heatmapLayer';
|
import HeatmapLayer from './heatmapLayer';
|
||||||
import TileLayer from './tile/tileLayer';
|
import TileLayer from './tile/tileLayer';
|
||||||
import ImageTileLayer from './tile/imageTileLayer';
|
import ImageTileLayer from './tile/imageTileLayer';
|
||||||
|
import VectorTileLayer from './tile/VectorTileLayer';
|
||||||
|
|
||||||
registerLayer('PolygonLayer', PolygonLayer);
|
registerLayer('PolygonLayer', PolygonLayer);
|
||||||
registerLayer('PointLayer', PointLayer);
|
registerLayer('PointLayer', PointLayer);
|
||||||
|
@ -16,7 +17,8 @@ registerLayer('RasterLayer', RasterLayer);
|
||||||
registerLayer('HeatmapLayer', HeatmapLayer);
|
registerLayer('HeatmapLayer', HeatmapLayer);
|
||||||
registerLayer('TileLayer', TileLayer);
|
registerLayer('TileLayer', TileLayer);
|
||||||
registerLayer('ImageTileLayer', ImageTileLayer);
|
registerLayer('ImageTileLayer', ImageTileLayer);
|
||||||
|
registerLayer('VectorTileLayer', VectorTileLayer);
|
||||||
|
|
||||||
export { LAYER_MAP } from './factory';
|
export { LAYER_MAP, getLayer } from './factory';
|
||||||
export { registerLayer };
|
export { registerLayer };
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ export default class LineLayer extends Layer {
|
||||||
if (this.shapeType === 'arc') {
|
if (this.shapeType === 'arc') {
|
||||||
DrawArc(attributes, layerCfg, this);
|
DrawArc(attributes, layerCfg, this);
|
||||||
} else {
|
} else {
|
||||||
DrawLine(attributes, layerCfg, this);
|
this.add(DrawLine(attributes, layerCfg, this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import HeatmapBuffer from '../../../geom/buffer/heatmap/heatmap';
|
import HeatmapBuffer from '../../../geom/buffer/heatmap/heatmap';
|
||||||
import { createColorRamp } from '../../../geom/buffer/heatmap/heatmap';
|
import { createColorRamp } from '../../../geom/buffer/heatmap/heatmap';
|
||||||
import { HeatmapIntensityMaterial, HeatmapColorizeMaterial } from '../../../geom/material/heatmapMateial';
|
import { HeatmapIntensityMaterial, HeatmapColorizeMaterial } from '../../../geom/material/heatmapMaterial';
|
||||||
// import Renderpass from '../../../core/engine/renderpass.bak';
|
// import Renderpass from '../../../core/engine/renderpass.bak';
|
||||||
import RenderPass from '../../../core/engine/render-pass';
|
import RenderPass from '../../../core/engine/render-pass';
|
||||||
import ShaderPass from '../../../core/engine/shader-pass';
|
import ShaderPass from '../../../core/engine/shader-pass';
|
||||||
|
|
|
@ -40,5 +40,5 @@ export default function DrawLine(attributes, cfg, layer) {
|
||||||
});
|
});
|
||||||
lineMaterial.setDefinesvalue('ANIMATE', true);
|
lineMaterial.setDefinesvalue('ANIMATE', true);
|
||||||
}
|
}
|
||||||
layer.add(lineMesh);
|
return lineMesh;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import TileLayer from './tileLayer';
|
||||||
|
import VectorTile from './vectorTile';
|
||||||
|
export default class VectorTileLayer extends TileLayer {
|
||||||
|
_createTile(key, layer) {
|
||||||
|
return new VectorTile(key, this.url, layer);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ export default class ImageTile extends Tile {
|
||||||
const image = document.createElement('img');
|
const image = document.createElement('img');
|
||||||
|
|
||||||
image.addEventListener('load', () => {
|
image.addEventListener('load', () => {
|
||||||
|
this._isLoaded = true;
|
||||||
this._createMesh(image);
|
this._createMesh(image);
|
||||||
this._ready = true;
|
this._ready = true;
|
||||||
}, false);
|
}, false);
|
||||||
|
@ -58,8 +58,8 @@ export default class ImageTile extends Tile {
|
||||||
buffer.attributes.texture = buffer.texture;
|
buffer.attributes.texture = buffer.texture;
|
||||||
const style = this.layer.get('styleOptions');
|
const style = this.layer.get('styleOptions');
|
||||||
const mesh = DrawImage(buffer.attributes, style);
|
const mesh = DrawImage(buffer.attributes, style);
|
||||||
this.Object3D.add(mesh);
|
this._object3D.add(mesh);
|
||||||
return this.Object3D;
|
return this._object3D;
|
||||||
}
|
}
|
||||||
_abortRequest() {
|
_abortRequest() {
|
||||||
if (!this._image) {
|
if (!this._image) {
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import * as THREE from '../../core/three';
|
import * as THREE from '../../core/three';
|
||||||
|
import EventEmitter from 'wolfy87-eventemitter';
|
||||||
import { toLngLatBounds, toBounds } from '@antv/geo-coord';
|
import { toLngLatBounds, toBounds } from '@antv/geo-coord';
|
||||||
const r2d = 180 / Math.PI;
|
const r2d = 180 / Math.PI;
|
||||||
const tileURLRegex = /\{([zxy])\}/g;
|
const tileURLRegex = /\{([zxy])\}/g;
|
||||||
|
|
||||||
export default class Tile {
|
export default class Tile extends EventEmitter {
|
||||||
constructor(key, url, layer) {
|
constructor(key, url, layer) {
|
||||||
|
super();
|
||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
this._tile = key.split('_').map(v => v * 1);
|
this._tile = key.split('_').map(v => v * 1);
|
||||||
this._path = url;
|
this._path = url;
|
||||||
|
@ -15,7 +17,10 @@ export default class Tile {
|
||||||
this._center = this._tileBounds.getCenter();
|
this._center = this._tileBounds.getCenter();
|
||||||
|
|
||||||
this._centerLnglat = this._tileLnglatBounds.getCenter();
|
this._centerLnglat = this._tileLnglatBounds.getCenter();
|
||||||
this.Object3D = new THREE.Object3D();
|
this._object3D = new THREE.Object3D();
|
||||||
|
this._object3D.onBeforeRender = () => {
|
||||||
|
};
|
||||||
|
this._isLoaded = false;
|
||||||
this.requestTileAsync();
|
this.requestTileAsync();
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,12 +39,12 @@ export default class Tile {
|
||||||
}
|
}
|
||||||
// 经纬度范围转瓦片范围
|
// 经纬度范围转瓦片范围
|
||||||
_tileBounds(lnglatBound) {
|
_tileBounds(lnglatBound) {
|
||||||
const ne = this.layer.scene.project([ lnglatBound.getNorthWest().lng, lnglatBound.getNorthEast().lat ]);
|
const ne = this.layer.scene.project([ lnglatBound.getNorthEast().lng, lnglatBound.getNorthEast().lat ]);
|
||||||
const sw = this.layer.scene.project([ lnglatBound.getSouthEast().lng, lnglatBound.getSouthWest().lat ]);
|
const sw = this.layer.scene.project([ lnglatBound.getSouthWest().lng, lnglatBound.getSouthWest().lat ]);
|
||||||
return toBounds(sw, ne);
|
return toBounds(sw, ne);
|
||||||
}
|
}
|
||||||
getMesh() {
|
getMesh() {
|
||||||
return this.Object3D;
|
return this._object3D;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +65,8 @@ export default class Tile {
|
||||||
const n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
|
const n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
|
||||||
return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
|
return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
|
||||||
}
|
}
|
||||||
|
_preRender() {
|
||||||
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
if (this._object3D && this._object3D.children) {
|
if (this._object3D && this._object3D.children) {
|
||||||
let child;
|
let child;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import Layer from '../../core/layer';
|
import Layer from '../../core/layer';
|
||||||
|
import source from '../../core/source';
|
||||||
import * as THREE from '../../core/three';
|
import * as THREE from '../../core/three';
|
||||||
|
import Util from '../../util';
|
||||||
import TileCache from './tileCache';
|
import TileCache from './tileCache';
|
||||||
import { throttle } from '@antv/util';
|
import { throttle } from '@antv/util';
|
||||||
import { toLngLat } from '@antv/geo-coord';
|
import { toLngLat } from '@antv/geo-coord';
|
||||||
|
@ -12,16 +14,28 @@ export default class TileLayer extends Layer {
|
||||||
this._tiles = new THREE.Object3D();
|
this._tiles = new THREE.Object3D();
|
||||||
this._tileKeys = [];
|
this._tileKeys = [];
|
||||||
this.tileList = [];
|
this.tileList = [];
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
source(url) {
|
source(url, cfg = {}) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
this.sourceCfg = cfg;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
tileSource(data) {
|
||||||
|
super.source(data, this.sourceCfg);
|
||||||
|
if (data instanceof source) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
this.sourceCfg.data = data;
|
||||||
|
this.sourceCfg.mapType = this.scene.mapType;
|
||||||
|
this.sourceCfg.zoom = this.scene.getZoom();
|
||||||
|
return new source(this.sourceCfg);
|
||||||
|
}
|
||||||
render() {
|
render() {
|
||||||
|
this._initControllers();
|
||||||
this._initMapEvent();
|
this._initMapEvent();
|
||||||
|
this._initAttrs();
|
||||||
this.draw();
|
this.draw();
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
draw() {
|
draw() {
|
||||||
this._object3D.add(this._tiles);
|
this._object3D.add(this._tiles);
|
||||||
|
@ -29,6 +43,44 @@ export default class TileLayer extends Layer {
|
||||||
}
|
}
|
||||||
drawTile() {
|
drawTile() {
|
||||||
|
|
||||||
|
}
|
||||||
|
_mapping(source) {
|
||||||
|
|
||||||
|
const attrs = this.get('attrs');
|
||||||
|
const mappedData = [];
|
||||||
|
// const data = this.layerSource.propertiesData;
|
||||||
|
const data = source.data.dataArray;
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const record = data[i];
|
||||||
|
const newRecord = {};
|
||||||
|
newRecord.id = data[i]._id;
|
||||||
|
for (const k in attrs) {
|
||||||
|
if (attrs.hasOwnProperty(k)) {
|
||||||
|
const attr = attrs[k];
|
||||||
|
const names = attr.names;
|
||||||
|
const values = this._getAttrValues(attr, record);
|
||||||
|
if (names.length > 1) { // position 之类的生成多个字段的属性
|
||||||
|
for (let j = 0; j < values.length; j++) {
|
||||||
|
const val = values[j];
|
||||||
|
const name = names[j];
|
||||||
|
newRecord[name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newRecord[names[0]] = values.length === 1 ? values[0] : values;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newRecord.coordinates = record.coordinates;
|
||||||
|
mappedData.push(newRecord);
|
||||||
|
}
|
||||||
|
// 通过透明度过滤数据
|
||||||
|
if (attrs.hasOwnProperty('filter')) {
|
||||||
|
mappedData.forEach(item => {
|
||||||
|
item.filter === false && (item.color[3] = 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return mappedData;
|
||||||
}
|
}
|
||||||
zoomchange(ev) {
|
zoomchange(ev) {
|
||||||
super.zoomchange(ev);
|
super.zoomchange(ev);
|
||||||
|
@ -56,8 +108,9 @@ export default class TileLayer extends Layer {
|
||||||
// console.log(NW.lng, NW.lat, SE.lng, SE.lat, NWPonint, SEPonint);
|
// console.log(NW.lng, NW.lat, SE.lng, SE.lat, NWPonint, SEPonint);
|
||||||
let updateTileList = [];
|
let updateTileList = [];
|
||||||
this.tileList = [];
|
this.tileList = [];
|
||||||
const halfx = Math.floor((maxXY.x - minXY.x) / 2) + 1;
|
const halfx = 1;
|
||||||
const halfy = Math.floor((maxXY.y - minXY.y) / 2) + 1;
|
const halfy = 1;
|
||||||
|
|
||||||
if (!(centerPoint.x > NWPoint.x && centerPoint.x < SEPoint.x)) { // 地图循环的问题
|
if (!(centerPoint.x > NWPoint.x && centerPoint.x < SEPoint.x)) { // 地图循环的问题
|
||||||
for (let i = 0; i < minXY.x; i++) {
|
for (let i = 0; i < minXY.x; i++) {
|
||||||
for (let j = Math.min(0, minXY.y - halfy); j < Math.max(maxXY.y + halfy, tileCount); j++) {
|
for (let j = Math.min(0, minXY.y - halfy); j < Math.max(maxXY.y + halfy, tileCount); j++) {
|
||||||
|
@ -90,10 +143,11 @@ export default class TileLayer extends Layer {
|
||||||
});
|
});
|
||||||
this._removeOutTiles();
|
this._removeOutTiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateTileList(updateTileList, x, y, z) {
|
_updateTileList(updateTileList, x, y, z) {
|
||||||
const key = [ x, y, z ].join('_');
|
const key = [ x, y, z ].join('_');
|
||||||
this.tileList.push(key);
|
this.tileList.push(key);
|
||||||
if (this._tileKeys.indexOf(key) === -1) {
|
if (this._tileKeys.indexOf(key) === -1 && updateTileList.indexOf(key) === -1) {
|
||||||
updateTileList.push(key);
|
updateTileList.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,14 +155,21 @@ export default class TileLayer extends Layer {
|
||||||
let tile = this._tileCache.getTile(key);
|
let tile = this._tileCache.getTile(key);
|
||||||
if (!tile) {
|
if (!tile) {
|
||||||
tile = this._createTile(key, layer);
|
tile = this._createTile(key, layer);
|
||||||
const mesh = tile.getMesh();
|
tile.on('tileLoaded', () => {
|
||||||
mesh.name = key;
|
if (this.tileList.indexOf(key) === -1) {
|
||||||
this._tileCache.setTile(tile, key);
|
return;
|
||||||
|
}
|
||||||
|
const mesh = tile.getMesh();
|
||||||
|
mesh.name = key;
|
||||||
|
this._tileCache.setTile(tile, key);
|
||||||
|
this._tileKeys.push(key);
|
||||||
|
mesh.children.length !== 0 && this._tiles.add(tile.getMesh());
|
||||||
|
this.scene._engine.update();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this._tiles.add(tile.getMesh());
|
||||||
this._tileKeys.push(key);
|
this._tileKeys.push(key);
|
||||||
// this.scene._engine.update();
|
|
||||||
}
|
}
|
||||||
this._tiles.add(tile.getMesh());
|
|
||||||
this._tileKeys.push(key);
|
|
||||||
}
|
}
|
||||||
// 移除视野外的tile
|
// 移除视野外的tile
|
||||||
_removeOutTiles() {
|
_removeOutTiles() {
|
||||||
|
@ -116,6 +177,8 @@ export default class TileLayer extends Layer {
|
||||||
const tile = this._tiles.children[i];
|
const tile = this._tiles.children[i];
|
||||||
const key = tile.name;
|
const key = tile.name;
|
||||||
if (this.tileList.indexOf(key) === -1) {
|
if (this.tileList.indexOf(key) === -1) {
|
||||||
|
const tileObj = this._tileCache.getTile(key);
|
||||||
|
tileObj && tileObj._abortRequest();
|
||||||
this._tiles.remove(tile);
|
this._tiles.remove(tile);
|
||||||
}
|
}
|
||||||
this._tileKeys = [].concat(this.tileList);
|
this._tileKeys = [].concat(this.tileList);
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
import Tile from './tile';
|
||||||
|
import { getArrayBuffer } from '../../util/ajax';
|
||||||
|
import PBF from 'pbf';
|
||||||
|
import * as VectorParser from '@mapbox/vector-tile';
|
||||||
|
import * as THREE from '../../core/three';
|
||||||
|
import MaskMaterial from '../../geom/material/tile/maskMaterial';
|
||||||
|
import { LineBuffer } from '../../geom/buffer/index';
|
||||||
|
import DrawLine from '../../layer/render/line/drawMeshLine';
|
||||||
|
|
||||||
|
export default class VectorTile extends Tile {
|
||||||
|
requestTileAsync() {
|
||||||
|
// Making this asynchronous really speeds up the LOD framerate
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this._mesh) {
|
||||||
|
// this._mesh = this._createMesh();
|
||||||
|
this._requestTile();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
_requestTile() {
|
||||||
|
const urlParams = {
|
||||||
|
x: this._tile[0],
|
||||||
|
y: this._tile[1],
|
||||||
|
z: this._tile[2]
|
||||||
|
};
|
||||||
|
|
||||||
|
const url = this._getTileURL(urlParams);
|
||||||
|
this.xhrRequest = getArrayBuffer({ url }, (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
this._noData = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._isLoaded = true;
|
||||||
|
this._parserData(data.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_creatSource(data) {
|
||||||
|
this.source = this.layer.tileSource(data);
|
||||||
|
}
|
||||||
|
_parserData(data) {
|
||||||
|
const tile = new VectorParser.VectorTile(new PBF(data));
|
||||||
|
// CHN_Cities_L CHN_Cities CHN_L
|
||||||
|
const layerName = 'county4326';
|
||||||
|
const features = [];
|
||||||
|
const vectorLayer = tile.layers[layerName];
|
||||||
|
for (let i = 0; i < vectorLayer.length; i++) {
|
||||||
|
const feature = vectorLayer.feature(i);
|
||||||
|
features.push(feature.toGeoJSON(this._tile[0], this._tile[1], this._tile[2]));
|
||||||
|
}
|
||||||
|
const geodata = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features
|
||||||
|
};
|
||||||
|
this._creatSource(geodata);
|
||||||
|
this._createMesh();
|
||||||
|
}
|
||||||
|
_createMesh() {
|
||||||
|
this.layerData = this.layer._mapping(this.source);
|
||||||
|
const style = this.layer.get('styleOptions');
|
||||||
|
const buffer = new LineBuffer({
|
||||||
|
layerData: this.layerData,
|
||||||
|
style,
|
||||||
|
shapeType: 'line'
|
||||||
|
|
||||||
|
});
|
||||||
|
const animateOptions = this.layer.get('animateOptions');
|
||||||
|
const activeOption = this.layer.get('activedOptions');
|
||||||
|
const layerCfg = {
|
||||||
|
zoom: this.layer.scene.getZoom(),
|
||||||
|
style,
|
||||||
|
animateOptions,
|
||||||
|
activeOption
|
||||||
|
};
|
||||||
|
this.mesh = new DrawLine(buffer.attributes, layerCfg, this.layer);
|
||||||
|
this.mesh.onBeforeRender = renderer => {
|
||||||
|
this._renderMask(renderer);
|
||||||
|
};
|
||||||
|
this.mesh.onAfterRender = renderer => {
|
||||||
|
const context = renderer.context;
|
||||||
|
context.disable(context.STENCIL_TEST);
|
||||||
|
};
|
||||||
|
this._object3D.add(this.mesh);
|
||||||
|
this.emit('tileLoaded');
|
||||||
|
return this._object3D;
|
||||||
|
}
|
||||||
|
_renderMask(renderer) {
|
||||||
|
const maskScene = new THREE.Scene();
|
||||||
|
this.maskScene = maskScene;
|
||||||
|
const tileMesh = this._tileMaskMesh();
|
||||||
|
maskScene.add(tileMesh);
|
||||||
|
const context = renderer.context;
|
||||||
|
renderer.autoClear = false;
|
||||||
|
renderer.clearDepth();
|
||||||
|
context.enable(context.STENCIL_TEST);
|
||||||
|
context.stencilOp(context.REPLACE, context.REPLACE, context.REPLACE);
|
||||||
|
context.stencilFunc(context.ALWAYS, 1, 0xffffffff);
|
||||||
|
context.clearStencil(0);
|
||||||
|
context.clear(context.STENCIL_BUFFER_BIT);
|
||||||
|
context.colorMask(false, false, false, false);
|
||||||
|
|
||||||
|
// config the stencil buffer to collect data for testing
|
||||||
|
this.layer.scene._engine.renderScene(maskScene);
|
||||||
|
context.colorMask(true, true, true, true);
|
||||||
|
context.depthMask(true);
|
||||||
|
renderer.clearDepth();
|
||||||
|
|
||||||
|
// only render where stencil is set to 1
|
||||||
|
|
||||||
|
context.stencilFunc(context.EQUAL, 1, 0xffffffff); // draw if == 1
|
||||||
|
context.stencilOp(context.KEEP, context.KEEP, context.KEEP);
|
||||||
|
}
|
||||||
|
_tileMaskMesh() {
|
||||||
|
const tilebound = this._tileBounds;
|
||||||
|
const bl = [ tilebound.getBottomLeft().x, tilebound.getBottomLeft().y, 0 ];
|
||||||
|
const br = [ tilebound.getBottomRight().x, tilebound.getBottomRight().y, 0 ];
|
||||||
|
const tl = [ tilebound.getTopLeft().x, tilebound.getTopLeft().y, 0 ];
|
||||||
|
const tr = [ tilebound.getTopRight().x, tilebound.getTopRight().y, 0 ];
|
||||||
|
const positions = [ ...bl, ...tr, ...br, ...bl, ...tl, ...tr ];
|
||||||
|
const geometry = new THREE.BufferGeometry();
|
||||||
|
geometry.addAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
|
||||||
|
const maskMaterial = new MaskMaterial();
|
||||||
|
const maskMesh = new THREE.Mesh(geometry, maskMaterial);
|
||||||
|
return maskMesh;
|
||||||
|
}
|
||||||
|
_abortRequest() {
|
||||||
|
if (!this.xhrRequest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.xhrRequest.abort();
|
||||||
|
}
|
||||||
|
destroy() {
|
||||||
|
|
||||||
|
this.mesh.destroy();
|
||||||
|
// if (this.maskScene) {
|
||||||
|
// this.maskScene.children[0].geometry = null;
|
||||||
|
// this.maskScene.children[0].material.dispose();
|
||||||
|
// this.maskScene.children[0].material = null;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,10 +48,10 @@ export default class LRUCache {
|
||||||
|
|
||||||
delete(key) {
|
delete(key) {
|
||||||
const value = this._cache[key];
|
const value = this._cache[key];
|
||||||
this.destroy(value);
|
|
||||||
if (value) {
|
if (value) {
|
||||||
this._deleteCache(key);
|
this._deleteCache(key);
|
||||||
this._deleteOrder(key);
|
this._deleteOrder(key);
|
||||||
|
this.destroy(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue