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",
|
||||
"version": "1.1.10",
|
||||
"version": "1.1.11",
|
||||
"description": "Large-scale WebGL-powered Geospatial Data Visualization",
|
||||
"main": "build/l7.js",
|
||||
"browser": "build/l7.js",
|
||||
|
|
|
@ -24,11 +24,14 @@ export default class Engine extends EventEmitter {
|
|||
});
|
||||
}
|
||||
update() {
|
||||
this._renderer.clear();
|
||||
this._renderer.render(this._scene, this._camera);
|
||||
this._initPostProcessing();
|
||||
}
|
||||
destroy() {
|
||||
|
||||
}
|
||||
renderScene(scene) {
|
||||
this._renderer.render(scene, this._camera);
|
||||
}
|
||||
run() {
|
||||
this.update();
|
||||
|
|
|
@ -9,7 +9,8 @@ export default class Renderer {
|
|||
initRender() {
|
||||
this.renderer = new THREE.WebGLRenderer({
|
||||
antialias: true,
|
||||
alpha: true
|
||||
alpha: true,
|
||||
autoClear: false
|
||||
});
|
||||
this.renderer.setClearColor(0xff0000, 0.0);
|
||||
this.pixelRatio = window.devicePixelRatio;
|
||||
|
|
|
@ -309,7 +309,7 @@ export default class Layer extends Base {
|
|||
}
|
||||
|
||||
createScale(field) {
|
||||
const data = this.layerSource.data.dataArray;
|
||||
const data = this.layerSource ? this.layerSource.data.dataArray : null;
|
||||
const scales = this.get('scales');
|
||||
let scale = scales[field];
|
||||
const scaleController = this.get('scaleController');
|
||||
|
@ -404,7 +404,7 @@ export default class Layer extends Base {
|
|||
const nextAttrs = this.get('attrOptions');
|
||||
const preStyle = this.get('preStyleOption');
|
||||
const nextStyle = this.get('styleOptions');
|
||||
if (preAttrs === undefined && preStyle === undefined) {
|
||||
if (preAttrs === undefined && preStyle === undefined) { // 首次渲染
|
||||
this._mapping();
|
||||
this._setPreOption();
|
||||
this._scaleByZoom();
|
||||
|
@ -490,12 +490,13 @@ export default class Layer extends Base {
|
|||
this.layerMesh.material.updateUninform(newOption);
|
||||
|
||||
}
|
||||
_mapping() {
|
||||
_mapping(source) {
|
||||
const self = this;
|
||||
const attrs = self.get('attrs');
|
||||
const mappedData = [];
|
||||
// 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++) {
|
||||
const record = data[i];
|
||||
const newRecord = {};
|
||||
|
@ -528,14 +529,16 @@ export default class Layer extends Base {
|
|||
});
|
||||
}
|
||||
this.layerData = mappedData;
|
||||
return mappedData;
|
||||
}
|
||||
|
||||
// 更新地图映射
|
||||
_updateMaping() {
|
||||
_updateMaping(source, layer) {
|
||||
const self = this;
|
||||
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++) {
|
||||
const record = data[i];
|
||||
for (const attrName in attrs) {
|
||||
|
@ -547,10 +550,10 @@ export default class Layer extends Base {
|
|||
for (let j = 0; j < values.length; j++) {
|
||||
const val = values[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 {
|
||||
this.layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
||||
layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
||||
|
||||
}
|
||||
attr.neadUpdate = true;
|
||||
|
@ -668,6 +671,7 @@ export default class Layer extends Base {
|
|||
pickAttr.needsUpdate = true;
|
||||
}
|
||||
_visibleWithZoom() {
|
||||
if (this._object3D === null) return;
|
||||
const zoom = this.scene.getZoom();
|
||||
const minZoom = this.get('minZoom');
|
||||
const maxZoom = this.get('maxZoom');
|
||||
|
@ -751,7 +755,6 @@ export default class Layer extends Base {
|
|||
this.clearMapEvent();
|
||||
if (this._object3D.type === 'composer') {
|
||||
this.remove(this._object3D);
|
||||
|
||||
return;
|
||||
}
|
||||
if (this._object3D && this._object3D.children) {
|
||||
|
@ -778,8 +781,19 @@ export default class Layer extends Base {
|
|||
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.scene._engine._scene.remove(this._object3D);
|
||||
this.layerData.length = 0;
|
||||
this.layerSource = null;
|
||||
this.scene._engine._picking.remove(this._pickingMesh);
|
||||
this.destroyed = true;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ export default class Scene extends Base {
|
|||
|
||||
_initEngine(mapContainer) {
|
||||
this._engine = new Engine(mapContainer, this);
|
||||
this.registerMapEvent();
|
||||
// this.registerMapEvent();
|
||||
this._engine.run();
|
||||
// this.workerPool = new WorkerPool();
|
||||
compileBuiltinModules();
|
||||
}
|
||||
|
@ -73,7 +74,6 @@ export default class Scene extends Base {
|
|||
}
|
||||
off(type, hander) {
|
||||
if (this.map) { this.map.off(type, hander); }
|
||||
|
||||
super.off(type, hander);
|
||||
}
|
||||
addImage() {
|
||||
|
|
|
@ -87,6 +87,7 @@ export default class LineBuffer extends BufferBase {
|
|||
layerData.forEach(item => {
|
||||
const props = item;
|
||||
const positionCount = positions.length / 3;
|
||||
// TODO 处理多个线段的情况
|
||||
const attr = lineShape.Line(item.coordinates, props, positionCount, (lineType !== 'soild'));
|
||||
positions.push(...attr.positions);
|
||||
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_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 { registerModule } from '../../util/shaderModule';
|
||||
import pick_color from './shaderChunks/pick_color.glsl';
|
||||
|
@ -65,5 +70,6 @@ export function compileBuiltinModules() {
|
|||
registerModule('image', { vs: image_vert, fs: image_frag });
|
||||
registerModule('raster', { vs: raster_vert, fs: raster_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
|
||||
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 pickingIds = [];
|
||||
const normal = [];
|
||||
|
@ -77,7 +80,8 @@ export function Line(path, props, positionsIndex) {
|
|||
const sizes = [];
|
||||
let c = 0;
|
||||
let index = positionsIndex;
|
||||
const { size, color, id } = props;
|
||||
let { size, color, id } = props;
|
||||
!Array.isArray(size) && (size = [ size ]);
|
||||
path.forEach((point, pointIndex, list) => {
|
||||
const i = index;
|
||||
colors.push(...color);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// 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 Global = {
|
||||
version: '1.0.0',
|
||||
version: '1.11.1',
|
||||
scene: {
|
||||
mapType: 'AMAP',
|
||||
zoom: 5,
|
||||
|
|
|
@ -7,6 +7,7 @@ import RasterLayer from './rasterLayer';
|
|||
import HeatmapLayer from './heatmapLayer';
|
||||
import TileLayer from './tile/tileLayer';
|
||||
import ImageTileLayer from './tile/imageTileLayer';
|
||||
import VectorTileLayer from './tile/VectorTileLayer';
|
||||
|
||||
registerLayer('PolygonLayer', PolygonLayer);
|
||||
registerLayer('PointLayer', PointLayer);
|
||||
|
@ -16,7 +17,8 @@ registerLayer('RasterLayer', RasterLayer);
|
|||
registerLayer('HeatmapLayer', HeatmapLayer);
|
||||
registerLayer('TileLayer', TileLayer);
|
||||
registerLayer('ImageTileLayer', ImageTileLayer);
|
||||
registerLayer('VectorTileLayer', VectorTileLayer);
|
||||
|
||||
export { LAYER_MAP } from './factory';
|
||||
export { LAYER_MAP, getLayer } from './factory';
|
||||
export { registerLayer };
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ export default class LineLayer extends Layer {
|
|||
if (this.shapeType === 'arc') {
|
||||
DrawArc(attributes, layerCfg, this);
|
||||
} else {
|
||||
DrawLine(attributes, layerCfg, this);
|
||||
this.add(DrawLine(attributes, layerCfg, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import HeatmapBuffer 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/render-pass';
|
||||
import ShaderPass from '../../../core/engine/shader-pass';
|
||||
|
|
|
@ -40,5 +40,5 @@ export default function DrawLine(attributes, cfg, layer) {
|
|||
});
|
||||
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');
|
||||
|
||||
image.addEventListener('load', () => {
|
||||
|
||||
this._isLoaded = true;
|
||||
this._createMesh(image);
|
||||
this._ready = true;
|
||||
}, false);
|
||||
|
@ -58,8 +58,8 @@ export default class ImageTile extends Tile {
|
|||
buffer.attributes.texture = buffer.texture;
|
||||
const style = this.layer.get('styleOptions');
|
||||
const mesh = DrawImage(buffer.attributes, style);
|
||||
this.Object3D.add(mesh);
|
||||
return this.Object3D;
|
||||
this._object3D.add(mesh);
|
||||
return this._object3D;
|
||||
}
|
||||
_abortRequest() {
|
||||
if (!this._image) {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import * as THREE from '../../core/three';
|
||||
import EventEmitter from 'wolfy87-eventemitter';
|
||||
import { toLngLatBounds, toBounds } from '@antv/geo-coord';
|
||||
const r2d = 180 / Math.PI;
|
||||
const tileURLRegex = /\{([zxy])\}/g;
|
||||
|
||||
export default class Tile {
|
||||
export default class Tile extends EventEmitter {
|
||||
constructor(key, url, layer) {
|
||||
super();
|
||||
this.layer = layer;
|
||||
this._tile = key.split('_').map(v => v * 1);
|
||||
this._path = url;
|
||||
|
@ -15,7 +17,10 @@ export default class Tile {
|
|||
this._center = this._tileBounds.getCenter();
|
||||
|
||||
this._centerLnglat = this._tileLnglatBounds.getCenter();
|
||||
this.Object3D = new THREE.Object3D();
|
||||
this._object3D = new THREE.Object3D();
|
||||
this._object3D.onBeforeRender = () => {
|
||||
};
|
||||
this._isLoaded = false;
|
||||
this.requestTileAsync();
|
||||
|
||||
|
||||
|
@ -34,12 +39,12 @@ export default class Tile {
|
|||
}
|
||||
// 经纬度范围转瓦片范围
|
||||
_tileBounds(lnglatBound) {
|
||||
const ne = this.layer.scene.project([ lnglatBound.getNorthWest().lng, lnglatBound.getNorthEast().lat ]);
|
||||
const sw = this.layer.scene.project([ lnglatBound.getSouthEast().lng, lnglatBound.getSouthWest().lat ]);
|
||||
const ne = this.layer.scene.project([ lnglatBound.getNorthEast().lng, lnglatBound.getNorthEast().lat ]);
|
||||
const sw = this.layer.scene.project([ lnglatBound.getSouthWest().lng, lnglatBound.getSouthWest().lat ]);
|
||||
return toBounds(sw, ne);
|
||||
}
|
||||
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);
|
||||
return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
|
||||
}
|
||||
_preRender() {
|
||||
}
|
||||
destroy() {
|
||||
if (this._object3D && this._object3D.children) {
|
||||
let child;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import Layer from '../../core/layer';
|
||||
import source from '../../core/source';
|
||||
import * as THREE from '../../core/three';
|
||||
import Util from '../../util';
|
||||
import TileCache from './tileCache';
|
||||
import { throttle } from '@antv/util';
|
||||
import { toLngLat } from '@antv/geo-coord';
|
||||
|
@ -12,16 +14,28 @@ export default class TileLayer extends Layer {
|
|||
this._tiles = new THREE.Object3D();
|
||||
this._tileKeys = [];
|
||||
this.tileList = [];
|
||||
|
||||
|
||||
}
|
||||
source(url) {
|
||||
source(url, cfg = {}) {
|
||||
this.url = url;
|
||||
this.sourceCfg = cfg;
|
||||
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() {
|
||||
this._initControllers();
|
||||
this._initMapEvent();
|
||||
this._initAttrs();
|
||||
this.draw();
|
||||
return this;
|
||||
}
|
||||
draw() {
|
||||
this._object3D.add(this._tiles);
|
||||
|
@ -29,6 +43,44 @@ export default class TileLayer extends Layer {
|
|||
}
|
||||
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) {
|
||||
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);
|
||||
let updateTileList = [];
|
||||
this.tileList = [];
|
||||
const halfx = Math.floor((maxXY.x - minXY.x) / 2) + 1;
|
||||
const halfy = Math.floor((maxXY.y - minXY.y) / 2) + 1;
|
||||
const halfx = 1;
|
||||
const halfy = 1;
|
||||
|
||||
if (!(centerPoint.x > NWPoint.x && centerPoint.x < SEPoint.x)) { // 地图循环的问题
|
||||
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++) {
|
||||
|
@ -90,10 +143,11 @@ export default class TileLayer extends Layer {
|
|||
});
|
||||
this._removeOutTiles();
|
||||
}
|
||||
|
||||
_updateTileList(updateTileList, x, y, z) {
|
||||
const key = [ x, y, z ].join('_');
|
||||
this.tileList.push(key);
|
||||
if (this._tileKeys.indexOf(key) === -1) {
|
||||
if (this._tileKeys.indexOf(key) === -1 && updateTileList.indexOf(key) === -1) {
|
||||
updateTileList.push(key);
|
||||
}
|
||||
}
|
||||
|
@ -101,14 +155,21 @@ export default class TileLayer extends Layer {
|
|||
let tile = this._tileCache.getTile(key);
|
||||
if (!tile) {
|
||||
tile = this._createTile(key, layer);
|
||||
const mesh = tile.getMesh();
|
||||
mesh.name = key;
|
||||
this._tileCache.setTile(tile, key);
|
||||
tile.on('tileLoaded', () => {
|
||||
if (this.tileList.indexOf(key) === -1) {
|
||||
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.scene._engine.update();
|
||||
}
|
||||
this._tiles.add(tile.getMesh());
|
||||
this._tileKeys.push(key);
|
||||
}
|
||||
// 移除视野外的tile
|
||||
_removeOutTiles() {
|
||||
|
@ -116,6 +177,8 @@ export default class TileLayer extends Layer {
|
|||
const tile = this._tiles.children[i];
|
||||
const key = tile.name;
|
||||
if (this.tileList.indexOf(key) === -1) {
|
||||
const tileObj = this._tileCache.getTile(key);
|
||||
tileObj && tileObj._abortRequest();
|
||||
this._tiles.remove(tile);
|
||||
}
|
||||
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) {
|
||||
const value = this._cache[key];
|
||||
this.destroy(value);
|
||||
if (value) {
|
||||
this._deleteCache(key);
|
||||
this._deleteOrder(key);
|
||||
this.destroy(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue