mirror of https://gitee.com/antv-l7/antv-l7
feat(tile): fix point tile layer
This commit is contained in:
parent
44d405ce93
commit
b6d2109a68
|
@ -47,6 +47,7 @@ scene.on('loaded', () => {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.source(city)
|
.source(city)
|
||||||
|
.active(false)
|
||||||
.color('pm2_5_24h',["#FFF5B8","#FFDC7D","#FFAB5C","#F27049","#D42F31","#730D1C"])
|
.color('pm2_5_24h',["#FFF5B8","#FFDC7D","#FFAB5C","#F27049","#D42F31","#730D1C"])
|
||||||
.shape('fill')
|
.shape('fill')
|
||||||
.style({
|
.style({
|
||||||
|
|
|
@ -25,39 +25,58 @@
|
||||||
|
|
||||||
const scene = new L7.Scene({
|
const scene = new L7.Scene({
|
||||||
id: 'map',
|
id: 'map',
|
||||||
mapStyle: 'light', // 样式URL
|
mapStyle: 'dark', // 样式URL
|
||||||
center: [120.05859375,30.29701788337204 ],
|
center: [116.5909,39.9225 ],
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
hash:true,
|
hash:true,
|
||||||
zoom: 11,
|
zoom: 14,
|
||||||
|
|
||||||
});
|
});
|
||||||
window.scene = scene;
|
window.scene = scene;
|
||||||
scene.on('loaded', () => {
|
scene.on('loaded', () => {
|
||||||
const layer = scene.VectorTileLayer({
|
const layer = scene.VectorTileLayer({
|
||||||
zIndex:0,
|
zIndex:0,
|
||||||
layerType:'polygon'
|
layerType:'point'
|
||||||
})
|
})
|
||||||
//.source('https://pre-lbs-show.taobao.com/gettile?x={x}&y={y}&z={z}&pipeId=pipe_vt_test')
|
//.source('https://pre-lbs-show.taobao.com/gettile?x={x}&y={y}&z={z}&pipeId=pipe_vt_test')
|
||||||
|
|
||||||
|
// http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point/{z}/{x}/{y}.pbf
|
||||||
// https://mvt.amap.com/district/CHN2/8/203/105/4096?key=
|
// https://mvt.amap.com/district/CHN2/8/203/105/4096?key=
|
||||||
.source('http://localhost:5000/test.mbtile/{z}/{x}/{y}.pbf',{
|
.source('http://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/thinkgis/tile/point2/{z}/{x}/{y}.pbf',{
|
||||||
parser:{
|
parser:{
|
||||||
type: 'mvt',
|
type: 'mvt',
|
||||||
sourceLayer:'county4326',
|
sourceLayer:'layer',
|
||||||
idField:'OBJECTID',
|
//idField:'OBJECTID',
|
||||||
maxZoom: 10,
|
maxZoom: 17,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.shape('line')
|
.scale({
|
||||||
.active({fill:'red'})
|
total:{
|
||||||
.color('red')
|
min:0,
|
||||||
.render();
|
max:1000000,
|
||||||
layer.on('click',(feature)=>{
|
type:'log'
|
||||||
console.log(feature);
|
}
|
||||||
})
|
})
|
||||||
|
// cylinder
|
||||||
|
.shape('hexagon')
|
||||||
|
.size(2)
|
||||||
|
.active(false)
|
||||||
|
.color('total', ['#d53e4f','#f46d43','#fdae61','#fee08b','#ffffbf','#e6f598','#abdda4','#66c2a5','#3288bd'].reverse())
|
||||||
|
//.color('#0D408C')
|
||||||
|
.style({
|
||||||
|
opacity:1.0
|
||||||
|
})
|
||||||
|
.render(
|
||||||
|
);
|
||||||
|
//layer.on('mousemove',(feature)=>{
|
||||||
|
// console.log(feature);
|
||||||
|
// })
|
||||||
console.log(layer);
|
console.log(layer);
|
||||||
});
|
});
|
||||||
|
//OBJECTID',(id)=>{
|
||||||
|
// const index = id % 8;
|
||||||
|
//return ['#9e0142','#d53e4f','#f46d43','#fdae61','#fee08b','#ffffbf','#e6f598','#abdda4','#66c2a5','#3288bd','#5e4fa2'][index];
|
||||||
|
//}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -71,9 +71,9 @@ class Picking {
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_updateRender() {
|
// _updateRender() {
|
||||||
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
|
// this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
|
||||||
}
|
// }
|
||||||
|
|
||||||
_pick(point, normalisedPoint, layerId) {
|
_pick(point, normalisedPoint, layerId) {
|
||||||
this._update(point);
|
this._update(point);
|
||||||
|
|
|
@ -168,6 +168,7 @@ export default class Layer extends Base {
|
||||||
} else {
|
} else {
|
||||||
scaleDefs[field] = cfg;
|
scaleDefs[field] = cfg;
|
||||||
}
|
}
|
||||||
|
console.log(options);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
shape(field, values) {
|
shape(field, values) {
|
||||||
|
@ -373,11 +374,14 @@ export default class Layer extends Base {
|
||||||
|
|
||||||
setActive(id, color) {
|
setActive(id, color) {
|
||||||
this._activeIds = id;
|
this._activeIds = id;
|
||||||
this.layerMesh.material.setUniformsValue('u_activeId', id);
|
|
||||||
if (!Array.isArray(color)) {
|
if (!Array.isArray(color)) {
|
||||||
color = ColorUtil.color2RGBA(color);
|
color = ColorUtil.color2RGBA(color);
|
||||||
}
|
}
|
||||||
updateObjecteUniform(this._object3D, { u_activeColor: color });
|
updateObjecteUniform(this._object3D, {
|
||||||
|
u_activeColor: color,
|
||||||
|
u_activeId: id
|
||||||
|
});
|
||||||
|
this.scene._engine.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
_addActiveFeature(e) {
|
_addActiveFeature(e) {
|
||||||
|
@ -623,23 +627,31 @@ export default class Layer extends Base {
|
||||||
}
|
}
|
||||||
this._activeIds = featureId;
|
this._activeIds = featureId;
|
||||||
// TODO 瓦片图层获取选中数据信息
|
// TODO 瓦片图层获取选中数据信息
|
||||||
// const feature = this.layerSource.getSelectFeature(featureId);
|
const { feature, style } = this.getSelectFeature(featureId);
|
||||||
const lnglat = this.scene.containerToLngLat(point2d);
|
const lnglat = this.scene.containerToLngLat(point2d);
|
||||||
// const style = this.layerData[featureId - 1];
|
// const style = this.layerData[featureId - 1];
|
||||||
const target = {
|
const target = {
|
||||||
featureId,
|
featureId,
|
||||||
// feature,
|
feature,
|
||||||
// style,
|
style,
|
||||||
pixel: point2d,
|
pixel: point2d,
|
||||||
type,
|
type,
|
||||||
lnglat: { lng: lnglat.lng, lat: lnglat.lat }
|
lnglat: { lng: lnglat.lng, lat: lnglat.lat }
|
||||||
};
|
};
|
||||||
if (featureId >= 0 || this._activeIds !== null) { // 拾取到元素,或者离开元素
|
if (featureId >= 0 || this._activeIds >= 0) { // 拾取到元素,或者离开元素
|
||||||
this.emit(type, target);
|
this.emit(type, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
getSelectFeature(featureId) {
|
||||||
|
const feature = this.layerSource.getSelectFeature(featureId);
|
||||||
|
const style = this.layerData[featureId - 1];
|
||||||
|
return {
|
||||||
|
feature,
|
||||||
|
style
|
||||||
|
};
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 用于过滤数据
|
* 用于过滤数据
|
||||||
* @param {*} object 更新颜色和数据过滤
|
* @param {*} object 更新颜色和数据过滤
|
||||||
|
|
|
@ -25,8 +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._engine.run();
|
||||||
// this.workerPool = new WorkerPool();
|
// this.workerPool = new WorkerPool();
|
||||||
compileBuiltinModules();
|
compileBuiltinModules();
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,9 @@ export default class Source extends Base {
|
||||||
const { type = 'geojson' } = parser;
|
const { type = 'geojson' } = parser;
|
||||||
const data = this.get('data');
|
const data = this.get('data');
|
||||||
this.originData = getParser(type)(data, parser);
|
this.originData = getParser(type)(data, parser);
|
||||||
this.data = clone(this.originData);
|
this.data = {
|
||||||
|
dataArray: clone(this.originData.dataArray)
|
||||||
|
};
|
||||||
this.data.extent = extent(this.data.dataArray);
|
this.data.extent = extent(this.data.dataArray);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,5 @@ export default function NormalBuffer(layerData) {
|
||||||
attributes.sizes.push(size);
|
attributes.sizes.push(size);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,8 @@ export default function DrawFill(layerData, layer) {
|
||||||
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.a_size, 3));
|
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.a_size, 3));
|
||||||
const material = new PolygonMaterial({
|
const material = new PolygonMaterial({
|
||||||
u_opacity: style.opacity,
|
u_opacity: style.opacity,
|
||||||
u_activeColor: activeOption.fill
|
u_activeColor: activeOption.fill,
|
||||||
|
u_zoom: layer.scene.getZoom()
|
||||||
}, {
|
}, {
|
||||||
SHAPE: true
|
SHAPE: true
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,7 @@ export default function DrawImage(layerData, layer) {
|
||||||
const { strokeWidth, stroke, opacity } = style;
|
const { strokeWidth, stroke, opacity } = style;
|
||||||
const texture = layer.scene.image.texture;
|
const texture = layer.scene.image.texture;
|
||||||
const attributes = PointBuffer.ImageBuffer(layerData, {
|
const attributes = PointBuffer.ImageBuffer(layerData, {
|
||||||
imagePos: this.scene.image.imagePos
|
imagePos: layer.scene.image.imagePos
|
||||||
});
|
});
|
||||||
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
|
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
|
||||||
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
|
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import Tile from './tile';
|
import Tile from './tile';
|
||||||
import ImageBuffer from '../../geom/buffer/image';
|
import ImageBuffer from '../../geom/buffer/image';
|
||||||
import DrawImage from '../render/image/drawImage';
|
import DrawImage from '../render/image/drawImage';
|
||||||
|
import * as THREE from '../../core/three';
|
||||||
export default class ImageTile extends Tile {
|
export default class ImageTile extends Tile {
|
||||||
requestTileAsync() {
|
requestTileAsync() {
|
||||||
// Making this asynchronous really speeds up the LOD framerate
|
// Making this asynchronous really speeds up the LOD framerate
|
||||||
|
@ -13,30 +14,34 @@ export default class ImageTile extends Tile {
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
_requestTile() {
|
_requestTile() {
|
||||||
const urlParams = {
|
const image = this._createDebugMesh();
|
||||||
x: this._tile[0],
|
|
||||||
y: this._tile[1],
|
|
||||||
z: this._tile[2]
|
|
||||||
};
|
|
||||||
|
|
||||||
const url = this._getTileURL(urlParams);
|
|
||||||
const image = document.createElement('img');
|
|
||||||
|
|
||||||
image.addEventListener('load', () => {
|
|
||||||
this._isLoaded = true;
|
|
||||||
this._createMesh(image);
|
this._createMesh(image);
|
||||||
this._ready = true;
|
this.emit('tileLoaded');
|
||||||
}, false);
|
// return;
|
||||||
|
// const urlParams = {
|
||||||
|
// x: this._tile[0],
|
||||||
|
// y: this._tile[1],
|
||||||
|
// z: this._tile[2]
|
||||||
|
// };
|
||||||
|
|
||||||
// image.addEventListener('progress', event => {}, false);
|
// const url = this._getTileURL(urlParams);
|
||||||
// image.addEventListener('error', event => {}, false);
|
// const image = document.createElement('img');
|
||||||
|
|
||||||
image.crossOrigin = '';
|
// image.addEventListener('load', () => {
|
||||||
|
// this._isLoaded = true;
|
||||||
|
// this._createMesh(image);
|
||||||
|
// this._ready = true;
|
||||||
|
// }, false);
|
||||||
|
|
||||||
// Load image
|
// // image.addEventListener('progress', event => {}, false);
|
||||||
image.src = url;
|
// // image.addEventListener('error', event => {}, false);
|
||||||
|
|
||||||
this._image = image;
|
// image.crossOrigin = '';
|
||||||
|
|
||||||
|
// // Load image
|
||||||
|
// image.src = url;
|
||||||
|
|
||||||
|
// this._image = image;
|
||||||
}
|
}
|
||||||
_getBufferData(images) {
|
_getBufferData(images) {
|
||||||
const NW = this._tileBounds.getTopLeft();
|
const NW = this._tileBounds.getTopLeft();
|
||||||
|
@ -61,6 +66,18 @@ export default class ImageTile extends Tile {
|
||||||
this._object3D.add(mesh);
|
this._object3D.add(mesh);
|
||||||
return this._object3D;
|
return this._object3D;
|
||||||
}
|
}
|
||||||
|
_createDebugMesh() {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
canvas.width = 256;
|
||||||
|
canvas.height = 256;
|
||||||
|
context.font = 'Bold 20px Helvetica Neue, Verdana, Arial';
|
||||||
|
context.fillStyle = '#ff0000';
|
||||||
|
context.fillText(this._tile.join('/'), 20, 20);
|
||||||
|
context.rect(0, 0, 256, 256);
|
||||||
|
context.stroke();
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
_abortRequest() {
|
_abortRequest() {
|
||||||
if (!this._image) {
|
if (!this._image) {
|
||||||
return;
|
return;
|
||||||
|
@ -68,7 +85,9 @@ export default class ImageTile extends Tile {
|
||||||
|
|
||||||
this._image.src = '';
|
this._image.src = '';
|
||||||
}
|
}
|
||||||
|
getSelectFeature() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
// Cancel any pending requests
|
// Cancel any pending requests
|
||||||
this._abortRequest();
|
this._abortRequest();
|
||||||
|
|
|
@ -37,10 +37,10 @@ export default class Tile extends Base {
|
||||||
this._object3D.onBeforeRender = () => {
|
this._object3D.onBeforeRender = () => {
|
||||||
};
|
};
|
||||||
this._isLoaded = false;
|
this._isLoaded = false;
|
||||||
this._initControllers();
|
|
||||||
this.requestTileAsync(data => this._init(data));
|
this.requestTileAsync(data => this._init(data));
|
||||||
}
|
}
|
||||||
_init(data) {
|
_init(data) {
|
||||||
|
this._initControllers();
|
||||||
this._creatSource(data);
|
this._creatSource(data);
|
||||||
this._initTileAttrs();
|
this._initTileAttrs();
|
||||||
this._mapping();
|
this._mapping();
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
import Layer from '../../core/layer';
|
import Layer from '../../core/layer';
|
||||||
import source from '../../core/source';
|
import source from '../../core/source';
|
||||||
import * as THREE from '../../core/three';
|
import * as THREE from '../../core/three';
|
||||||
|
import Global from '../../global';
|
||||||
|
const { pointShape } = Global;
|
||||||
|
import { updateObjecteUniform } from '../../util/object3d-util';
|
||||||
import TileCache from './tileCache';
|
import TileCache from './tileCache';
|
||||||
import pickingFragmentShader from '../../core/engine/picking/picking_frag.glsl';
|
import pickingFragmentShader from '../../core/engine/picking/picking_frag.glsl';
|
||||||
import { throttle, deepMix } from '@antv/util';
|
import { throttle, deepMix } from '@antv/util';
|
||||||
import { toLngLat } from '@antv/geo-coord';
|
import { toLngLat, Bounds, Point } from '@antv/geo-coord';
|
||||||
|
import { wrapNum } from '@antv/geo-coord/lib/util/index';
|
||||||
import { epsg3857 } from '@antv/geo-coord/lib/geo/crs/crs-epsg3857';
|
import { epsg3857 } from '@antv/geo-coord/lib/geo/crs/crs-epsg3857';
|
||||||
export default class TileLayer extends Layer {
|
export default class TileLayer extends Layer {
|
||||||
constructor(scene, cfg) {
|
constructor(scene, cfg) {
|
||||||
super(scene, cfg);
|
super(scene, {
|
||||||
this._tileCache = new TileCache(50, this._destroyTile);
|
...cfg,
|
||||||
|
keepBuffer: 2
|
||||||
|
});
|
||||||
|
this._tileCache = new TileCache(100, this._destroyTile);
|
||||||
this._crs = epsg3857;
|
this._crs = epsg3857;
|
||||||
this._tiles = new THREE.Object3D();
|
this._tiles = new THREE.Object3D();
|
||||||
this._pickTiles = new THREE.Object3D();
|
this._pickTiles = new THREE.Object3D();
|
||||||
|
@ -17,7 +24,7 @@ export default class TileLayer extends Layer {
|
||||||
this.scene._engine._picking.add(this._pickTiles);
|
this.scene._engine._picking.add(this._pickTiles);
|
||||||
this._tiles.frustumCulled = false;
|
this._tiles.frustumCulled = false;
|
||||||
this._tileKeys = [];
|
this._tileKeys = [];
|
||||||
this.tileList = [];
|
this.tileList = {};
|
||||||
}
|
}
|
||||||
shape(field, values) {
|
shape(field, values) {
|
||||||
const layerType = this.get('layerType');
|
const layerType = this.get('layerType');
|
||||||
|
@ -45,9 +52,9 @@ export default class TileLayer extends Layer {
|
||||||
return new source(tileSourceCfg);
|
return new source(tileSourceCfg);
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
this._initControllers();
|
// this._initControllers();
|
||||||
this._initMapEvent();
|
this._initMapEvent();
|
||||||
this._initAttrs();
|
// this._initAttrs();
|
||||||
this._initInteraction();
|
this._initInteraction();
|
||||||
this.draw();
|
this.draw();
|
||||||
return this;
|
return this;
|
||||||
|
@ -56,86 +63,118 @@ export default class TileLayer extends Layer {
|
||||||
this._object3D.add(this._tiles);
|
this._object3D.add(this._tiles);
|
||||||
this._calculateLOD();
|
this._calculateLOD();
|
||||||
}
|
}
|
||||||
|
|
||||||
drawTile() {
|
drawTile() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomchange(ev) {
|
zoomchange(ev) {
|
||||||
super.zoomchange(ev);
|
super.zoomchange(ev);
|
||||||
throttle(this._calculateLOD, 200);
|
throttle(this._calculateLOD, 200);
|
||||||
this._calculateLOD();
|
this._calculateLOD();
|
||||||
}
|
}
|
||||||
|
|
||||||
dragend(ev) {
|
dragend(ev) {
|
||||||
super.dragend(ev);
|
super.dragend(ev);
|
||||||
this._calculateLOD();
|
this._calculateLOD();
|
||||||
|
|
||||||
}
|
}
|
||||||
_calculateLOD() {
|
_calculateLOD() {
|
||||||
const viewPort = this.scene.getBounds().toBounds();
|
/**
|
||||||
const SE = viewPort.getSouthEast();
|
* 加载完成 active
|
||||||
const NW = viewPort.getNorthWest();
|
* 需要显示 current
|
||||||
|
* 是否保留 retain
|
||||||
|
*/
|
||||||
|
this.updateTileList = [];
|
||||||
const zoom = Math.round(this.scene.getZoom()) - 1;
|
const zoom = Math.round(this.scene.getZoom()) - 1;
|
||||||
const tileCount = Math.pow(2, zoom);
|
|
||||||
const center = this.scene.getCenter();
|
const center = this.scene.getCenter();
|
||||||
const NWPoint = this._crs.lngLatToPoint(toLngLat(NW.lng, NW.lat), zoom);
|
|
||||||
const SEPoint = this._crs.lngLatToPoint(toLngLat(SE.lng, SE.lat), zoom);
|
|
||||||
const centerPoint = this._crs.lngLatToPoint(toLngLat(center.lng, center.lat), zoom);
|
const centerPoint = this._crs.lngLatToPoint(toLngLat(center.lng, center.lat), zoom);
|
||||||
const centerXY = centerPoint.divideBy(256).round();
|
const centerXY = centerPoint.divideBy(256).round();
|
||||||
const minXY = NWPoint.divideBy(256).round();
|
const pixelBounds = this._getPixelBounds();
|
||||||
const maxXY = SEPoint.divideBy(256).round();
|
const tileRange = this._pxBoundsToTileRange(pixelBounds);
|
||||||
// console.log(NW.lng, NW.lat, SE.lng, SE.lat, NWPonint, SEPonint);
|
const margin = this.get('keepBuffer');
|
||||||
let updateTileList = [];
|
this.noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([ margin, -margin ]),
|
||||||
this.tileList = [];
|
tileRange.getTopRight().add([ margin, -margin ]));
|
||||||
const halfx = 1;
|
if (!(isFinite(tileRange.min.x) &&
|
||||||
const halfy = 1;
|
isFinite(tileRange.min.y) &&
|
||||||
|
isFinite(tileRange.max.x) &&
|
||||||
if (!(centerPoint.x > NWPoint.x && centerPoint.x < SEPoint.x)) { // 地图循环的问题
|
isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }
|
||||||
for (let i = 0; i < minXY.x; i++) {
|
for (let j = tileRange.min.y; j <= tileRange.max.y; j++) {
|
||||||
for (let j = Math.min(0, minXY.y - halfy); j < Math.max(maxXY.y + halfy, tileCount); j++) {
|
for (let i = tileRange.min.x; i <= tileRange.max.x; i++) {
|
||||||
this._updateTileList(updateTileList, i, j, zoom);
|
const coords = [ i, j, zoom ];
|
||||||
}
|
const tile = this.tileList[coords.join('_')];
|
||||||
}
|
if (tile) {
|
||||||
for (let i = maxXY.x; i < tileCount; i++) {
|
tile.current = true;
|
||||||
for (let j = Math.min(0, minXY.y - halfy); j < Math.max(maxXY.y + halfy, tileCount); j++) {
|
} else {
|
||||||
this._updateTileList(updateTileList, i, j, zoom);
|
this.tileList[coords.join('_')] = {
|
||||||
|
current: true,
|
||||||
|
coords
|
||||||
|
};
|
||||||
|
this.updateTileList.push(coords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let i = Math.max(0, minXY.x - halfx); i < Math.min(maxXY.x + halfx, tileCount); i++) {
|
this.updateTileList.sort((a, b) => {
|
||||||
for (let j = Math.max(0, minXY.y - halfy); j < Math.min(maxXY.y + halfy, tileCount); j++) {
|
const tile1 = a;
|
||||||
this._updateTileList(updateTileList, i, j, zoom);
|
const tile2 = b;
|
||||||
}
|
|
||||||
}
|
|
||||||
// 过滤掉已经存在的
|
|
||||||
// tileList = tileList.filter(tile => {
|
|
||||||
// })
|
|
||||||
updateTileList = updateTileList.sort((a, b) => {
|
|
||||||
const tile1 = a.split('_');
|
|
||||||
const tile2 = b.split('_');
|
|
||||||
const d1 = Math.pow((tile1[0] * 1 - centerXY.x), 2) + Math.pow((tile1[1] * 1 - centerXY.y), 2);
|
const d1 = Math.pow((tile1[0] * 1 - centerXY.x), 2) + Math.pow((tile1[1] * 1 - centerXY.y), 2);
|
||||||
const d2 = Math.pow((tile2[0] * 1 - centerXY.x), 2) + Math.pow((tile2[1] * 1 - centerXY.y), 2);
|
const d2 = Math.pow((tile2[0] * 1 - centerXY.x), 2) + Math.pow((tile2[1] * 1 - centerXY.y), 2);
|
||||||
return d1 - d2;
|
return d1 - d2;
|
||||||
});
|
});
|
||||||
updateTileList.forEach(key => {
|
this._pruneTiles();
|
||||||
|
// 更新瓦片数据
|
||||||
|
this.updateTileList.forEach(coords => {
|
||||||
|
const key = coords.join('_');
|
||||||
|
if (this.tileList[key].current) {
|
||||||
this._requestTile(key, this);
|
this._requestTile(key, this);
|
||||||
});
|
|
||||||
this._removeOutTiles();
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
_updateTileList(updateTileList, x, y, z) {
|
}
|
||||||
|
_getShape(layerData) {
|
||||||
|
let shape = null;
|
||||||
|
if (!layerData[0].hasOwnProperty('shape')) {
|
||||||
|
return 'normal';
|
||||||
|
}
|
||||||
|
for (let i = 0; i < layerData.length; i++) {
|
||||||
|
shape = layerData[i].shape;
|
||||||
|
if (shape !== undefined) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
pointShape['2d'].indexOf(shape) !== -1 ||
|
||||||
|
pointShape['3d'].indexOf(shape) !== -1
|
||||||
|
) {
|
||||||
|
return 'fill';
|
||||||
|
} else if (this.scene.image.imagesIds.indexOf(shape) !== -1) {
|
||||||
|
return 'image';
|
||||||
|
}
|
||||||
|
return 'text';
|
||||||
|
}
|
||||||
|
_updateTileList(x, y, z) {
|
||||||
const key = [ x, y, z ].join('_');
|
const key = [ x, y, z ].join('_');
|
||||||
this.tileList.push(key);
|
const tile = this.tileList[key];
|
||||||
if (this._tileKeys.indexOf(key) === -1 && updateTileList.indexOf(key) === -1) {
|
if (tile) {
|
||||||
updateTileList.push(key);
|
tile.current = true;
|
||||||
|
} else {
|
||||||
|
this.tileList[key] = {
|
||||||
|
current: true,
|
||||||
|
active: false,
|
||||||
|
coords: key.split('_')
|
||||||
|
};
|
||||||
|
this.updateTileList.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_requestTile(key, layer) {
|
_requestTile(key, layer) {
|
||||||
|
const t = this.tileList[key];
|
||||||
|
if (!t) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
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);
|
||||||
tile.on('tileLoaded', () => {
|
tile.on('tileLoaded', () => {
|
||||||
if (this.tileList.indexOf(key) === -1) {
|
t.active = true;
|
||||||
return;
|
|
||||||
}
|
|
||||||
const mesh = tile.getMesh();
|
const mesh = tile.getMesh();
|
||||||
mesh.name = key;
|
mesh.name = key;
|
||||||
this._tileCache.setTile(tile, key);
|
this._tileCache.setTile(tile, key);
|
||||||
|
@ -144,12 +183,16 @@ export default class TileLayer extends Layer {
|
||||||
this._tiles.add(tile.getMesh());
|
this._tiles.add(tile.getMesh());
|
||||||
this._addPickTile(tile.getMesh());
|
this._addPickTile(tile.getMesh());
|
||||||
}
|
}
|
||||||
|
this.scene._engine.update();
|
||||||
|
this._pruneTiles();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._tiles.add(tile.getMesh());
|
this._tiles.add(tile.getMesh());
|
||||||
|
t.active = true;
|
||||||
this._addPickTile(tile.getMesh());
|
this._addPickTile(tile.getMesh());
|
||||||
this._tileKeys.push(key);
|
this._tileKeys.push(key);
|
||||||
this.scene._engine.update();
|
this.scene._engine.update();
|
||||||
|
this._pruneTiles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_addPickTile(meshobj) {
|
_addPickTile(meshobj) {
|
||||||
|
@ -165,19 +208,104 @@ export default class TileLayer extends Layer {
|
||||||
this._pickTiles.add(pickingMesh);
|
this._pickTiles.add(pickingMesh);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
getSelectFeature(id) {
|
||||||
|
let feat = null;
|
||||||
|
this._tileKeys.forEach(key => {
|
||||||
|
const tile = this._tileCache.getTile(key);
|
||||||
|
const feature = tile ? tile.getSelectFeature(id) : null;
|
||||||
|
if (feature !== null) {
|
||||||
|
feat = feature;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { feature: feat };
|
||||||
|
}
|
||||||
|
_pruneTiles() {
|
||||||
|
let tile;
|
||||||
|
const zoom = Math.round(this.scene.getZoom()) - 1;
|
||||||
|
for (const key in this.tileList) {
|
||||||
|
const c = this.tileList[key].coords;
|
||||||
|
if (c[2] !== zoom || !this.noPruneRange.contains(new Point(c[0], c[1]))) {
|
||||||
|
this.tileList[key].current = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in this.tileList) {
|
||||||
|
tile = this.tileList[key];
|
||||||
|
tile.retain = tile.current;
|
||||||
|
}
|
||||||
|
for (const key in this.tileList) {
|
||||||
|
tile = this.tileList[key];
|
||||||
|
if (tile.current && !tile.active) {
|
||||||
|
const [ x, y, z ] = key.split('_').map(v => v * 1);
|
||||||
|
if (!this._retainParent(x, y, z, z - 5)) {
|
||||||
|
this._retainChildren(x, y, z, z + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
this._removeOutTiles();
|
||||||
|
}
|
||||||
|
_retainParent(x, y, z, minZoom) {
|
||||||
|
const x2 = Math.floor(x / 2);
|
||||||
|
const y2 = Math.floor(y / 2);
|
||||||
|
const z2 = z - 1;
|
||||||
|
const tile = this.tileList[[ x2, y2, z2 ].join('_')];
|
||||||
|
if (tile && tile.active) {
|
||||||
|
tile.retain = true;
|
||||||
|
return true;
|
||||||
|
} else if (tile && tile.loaded) {
|
||||||
|
tile.retain = true;
|
||||||
|
}
|
||||||
|
if (z2 > minZoom) {
|
||||||
|
return this._retainParent(x2, y2, z2, minZoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
_retainChildren(x, y, z, maxZoom) {
|
||||||
|
for (let i = 2 * x; i < 2 * x + 2; i++) {
|
||||||
|
for (let j = 2 * y; j < 2 * y + 2; j++) {
|
||||||
|
const key = [ i, j, z + 1 ].join('_');
|
||||||
|
const tile = this.tileList[key];
|
||||||
|
if (tile && tile.active) {
|
||||||
|
tile.retain = true;
|
||||||
|
continue;
|
||||||
|
} else if (tile && tile.loaded) {
|
||||||
|
tile.retain = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z + 1 < maxZoom) {
|
||||||
|
this._retainChildren(i, j, z + 1, maxZoom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// 移除视野外的tile
|
// 移除视野外的tile
|
||||||
_removeOutTiles() {
|
_removeOutTiles() {
|
||||||
for (let i = this._tiles.children.length - 1; i >= 0; i--) {
|
for (const key in this.tileList) {
|
||||||
const tile = this._tiles.children[i];
|
if (!this.tileList[key].retain) {
|
||||||
const key = tile.name;
|
|
||||||
if (this.tileList.indexOf(key) === -1) {
|
|
||||||
const tileObj = this._tileCache.getTile(key);
|
const tileObj = this._tileCache.getTile(key);
|
||||||
tileObj && tileObj._abortRequest();
|
if (tileObj) {
|
||||||
|
tileObj._abortRequest();
|
||||||
|
this._tiles.remove(tileObj.getMesh());
|
||||||
|
}
|
||||||
|
delete this.tileList[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this._tiles.children.length > Object.keys(this.tileList).length) {
|
||||||
|
this._tiles.children.forEach(tile => {
|
||||||
|
const key = tile.name;
|
||||||
|
if (!this.tileList[key]) {
|
||||||
this._tiles.remove(tile);
|
this._tiles.remove(tile);
|
||||||
}
|
}
|
||||||
this._tileKeys = [].concat(this.tileList);
|
});
|
||||||
}
|
} // 移除 空的geom
|
||||||
|
this.scene._engine.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_removeTiles() {
|
_removeTiles() {
|
||||||
if (!this._tiles || !this._tiles.children) {
|
if (!this._tiles || !this._tiles.children) {
|
||||||
return;
|
return;
|
||||||
|
@ -187,10 +315,51 @@ export default class TileLayer extends Layer {
|
||||||
this._tiles.remove(this._tiles.children[i]);
|
this._tiles.remove(this._tiles.children[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_getPixelBounds() {
|
||||||
|
const viewPort = this.scene.getBounds().toBounds();
|
||||||
|
const NE = viewPort.getNorthEast();
|
||||||
|
const SW = viewPort.getSouthWest();
|
||||||
|
const zoom = Math.round(this.scene.getZoom()) - 1;
|
||||||
|
const center = this.scene.getCenter();
|
||||||
|
const NEPoint = this._crs.lngLatToPoint(toLngLat(NE.lng, NE.lat), zoom);
|
||||||
|
const SWPoint = this._crs.lngLatToPoint(toLngLat(SW.lng, SW.lat), zoom);
|
||||||
|
const centerPoint = this._crs.lngLatToPoint(toLngLat(center.lng, center.lat), zoom);
|
||||||
|
const topHeight = centerPoint.y - NEPoint.y;
|
||||||
|
const bottomHeight = SWPoint.y - centerPoint.y;
|
||||||
|
// 跨日界线的情况
|
||||||
|
let leftWidth;
|
||||||
|
let rightWidth;
|
||||||
|
if (center.lng - NE.lng > 0 || center.lng - SW.lng < 0) {
|
||||||
|
const width = Math.pow(2, zoom) * 256 / 360 * (180 - NE.lng) + Math.pow(2, zoom) * 256 / 360 * (SW.lng + 180);
|
||||||
|
if (center.lng - NE.lng > 0) { // 日界线在右侧
|
||||||
|
leftWidth = Math.pow(2, zoom) * 256 / 360 * (center.lng - NE.lng);
|
||||||
|
rightWidth = width - leftWidth;
|
||||||
|
} else {
|
||||||
|
rightWidth = Math.pow(2, zoom) * 256 / 360 * (SW.lng - center.lng);
|
||||||
|
leftWidth = width - rightWidth;
|
||||||
|
}
|
||||||
|
} else { // 不跨日界线
|
||||||
|
leftWidth = Math.pow(2, zoom) * 256 / 360 * (center.lng - SW.lng);
|
||||||
|
rightWidth = Math.pow(2, zoom) * 256 / 360 * (NE.lng - center.lng);
|
||||||
|
}
|
||||||
|
const pixelBounds = new Bounds(centerPoint.subtract(leftWidth, topHeight), centerPoint.add(rightWidth, bottomHeight));
|
||||||
|
return pixelBounds;
|
||||||
|
}
|
||||||
|
_pxBoundsToTileRange(pixelBounds) {
|
||||||
|
return new Bounds(
|
||||||
|
pixelBounds.min.divideBy(256).floor(),
|
||||||
|
pixelBounds.max.divideBy(256).ceil().subtract([ 1, 1 ])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_wrapCoords(coords) {
|
||||||
|
const wrapX = [ 0, Math.pow(2, coords[2]) ];
|
||||||
|
const newX = wrapNum(coords[0], wrapX);
|
||||||
|
return [ newX, coords[1], coords[2] ];
|
||||||
|
}
|
||||||
_destroyTile(tile) {
|
_destroyTile(tile) {
|
||||||
tile.destroy();
|
tile.destroy();
|
||||||
tile = null;
|
tile = null;
|
||||||
}
|
}
|
||||||
desttroy() {
|
destroy() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Tile from './tile';
|
import Tile from './tile';
|
||||||
import { getArrayBuffer } from '../../util/ajax';
|
import { getArrayBuffer } from '../../util/ajax';
|
||||||
import { destoryObject } from '../../util/object3d-util';
|
import { destoryObject, updateObjecteUniform } from '../../util/object3d-util';
|
||||||
import * as THREE from '../../core/three';
|
import * as THREE from '../../core/three';
|
||||||
import MaskMaterial from '../../geom/material/tile/maskMaterial';
|
import MaskMaterial from '../../geom/material/tile/maskMaterial';
|
||||||
import { getRender } from '../render/index';
|
import { getRender } from '../render/index';
|
||||||
|
@ -39,6 +39,9 @@ export default class VectorTile extends Tile {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_createMesh() {
|
_createMesh() {
|
||||||
|
if (this.layer.get('layerType') === 'point') {
|
||||||
|
this.layer.shape = this.layer._getShape(this.layerData);
|
||||||
|
}
|
||||||
this.mesh = getRender(this.layer.get('layerType'), this.layer.shape)(this.layerData, this.layer);
|
this.mesh = getRender(this.layer.get('layerType'), this.layer.shape)(this.layerData, this.layer);
|
||||||
this.mesh.onBeforeRender = renderer => {
|
this.mesh.onBeforeRender = renderer => {
|
||||||
this._renderMask(renderer);
|
this._renderMask(renderer);
|
||||||
|
@ -52,6 +55,14 @@ export default class VectorTile extends Tile {
|
||||||
return this._object3D;
|
return this._object3D;
|
||||||
}
|
}
|
||||||
_renderMask(renderer) {
|
_renderMask(renderer) {
|
||||||
|
const zoom = this.layer.scene.getZoom();
|
||||||
|
updateObjecteUniform(this.mesh, {
|
||||||
|
u_time: this.layer.scene._engine.clock.getElapsedTime(),
|
||||||
|
u_zoom: zoom
|
||||||
|
});
|
||||||
|
if (this.layer.get('layerType') === 'point') { // 点图层目前不需要mask
|
||||||
|
return;
|
||||||
|
}
|
||||||
const maskScene = new THREE.Scene();
|
const maskScene = new THREE.Scene();
|
||||||
this.maskScene = maskScene;
|
this.maskScene = maskScene;
|
||||||
const tileMesh = this._tileMaskMesh();
|
const tileMesh = this._tileMaskMesh();
|
||||||
|
@ -97,6 +108,13 @@ export default class VectorTile extends Tile {
|
||||||
|
|
||||||
this.xhrRequest.abort();
|
this.xhrRequest.abort();
|
||||||
}
|
}
|
||||||
|
getSelectFeature(id) {
|
||||||
|
const featureIndex = this.source.originData.featureKeys[id];
|
||||||
|
if (featureIndex) {
|
||||||
|
return this.source.originData.dataArray[featureIndex];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
super.destroy();
|
super.destroy();
|
||||||
destoryObject(this.maskScene);
|
destoryObject(this.maskScene);
|
||||||
|
|
|
@ -1,27 +1,35 @@
|
||||||
import * as turfMeta from '@turf/meta';
|
import * as turfMeta from '@turf/meta';
|
||||||
import { getCoords } from '@turf/invariant';
|
import { getCoords } from '@turf/invariant';
|
||||||
|
import { BKDRHash } from '../../util/bkdr-hash';
|
||||||
export default function geoJSON(data, cfg) {
|
export default function geoJSON(data, cfg) {
|
||||||
const resultData = [];
|
const resultData = [];
|
||||||
|
const featureKeys = {};
|
||||||
data.features = data.features.filter(item => {
|
data.features = data.features.filter(item => {
|
||||||
return item != null && item.geometry && item.geometry.type && item.geometry.coordinates && item.geometry.coordinates.length > 0;
|
return item != null && item.geometry && item.geometry.type && item.geometry.coordinates && item.geometry.coordinates.length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 数据为空时处理
|
// 数据为空时处理
|
||||||
turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
|
turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
|
||||||
const coord = getCoords(currentFeature);
|
const coord = getCoords(currentFeature);
|
||||||
let id = featureIndex + 1;
|
let id = featureIndex + 1;
|
||||||
if (cfg.idField) {
|
// if (cfg.idField) {
|
||||||
id = currentFeature.properties[cfg.idField];
|
// const value = currentFeature.properties[cfg.idField];
|
||||||
}
|
// // id = value;
|
||||||
|
// id = BKDRHash(value) % 1000019;
|
||||||
|
// if (featureKeys[id] && featureIndex !== featureKeys[id]) {
|
||||||
|
// // TODO 哈希冲突解决方法
|
||||||
|
// console.log('哈希冲突', value);
|
||||||
|
// }
|
||||||
|
// featureKeys[id] = featureIndex;
|
||||||
|
// }
|
||||||
const dataItem = {
|
const dataItem = {
|
||||||
...currentFeature.properties,
|
...currentFeature.properties,
|
||||||
coordinates: coord,
|
coordinates: coord,
|
||||||
_id: id
|
_id: currentFeature.properties[cfg.idField]
|
||||||
};
|
};
|
||||||
resultData.push(dataItem);
|
resultData.push(dataItem);
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
dataArray: resultData
|
dataArray: resultData,
|
||||||
|
featureKeys
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
export function BKDRHash(str) {
|
||||||
|
const seed = 131;
|
||||||
|
const seed2 = 137;
|
||||||
|
let hash = 0;
|
||||||
|
// make hash more sensitive for short string like 'a', 'b', 'c'
|
||||||
|
str += 'x';
|
||||||
|
// Note: Number.MAX_SAFE_INTEGER equals 9007199254740991
|
||||||
|
const MAX_SAFE_INTEGER = parseInt(9007199254740991 / seed2);
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
if (hash > MAX_SAFE_INTEGER) {
|
||||||
|
hash = parseInt(hash / seed2);
|
||||||
|
}
|
||||||
|
hash = hash * seed + str.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
Loading…
Reference in New Issue