mirror of https://gitee.com/antv-l7/antv-l7
Merge branch 'feat_source_hooks' of https://github.com/antvis/L7 into feat_source_hooks
This commit is contained in:
commit
45d239c3ff
|
@ -21,7 +21,7 @@ const Demo: React.FC = () => {
|
|||
scene.on('loaded', () => {
|
||||
const drawer = new DrawPolygon(scene, {
|
||||
areaOptions: {},
|
||||
liveUpdate: true,
|
||||
// liveUpdate: true,
|
||||
});
|
||||
setPolygonDrawer(drawer);
|
||||
console.log(drawer);
|
||||
|
|
|
@ -24,8 +24,7 @@ export default () => {
|
|||
parser: {
|
||||
type: 'rasterTile',
|
||||
tileSize: 256,
|
||||
// zoomOffset: 0
|
||||
// zoomOffset: 1,
|
||||
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: SenTinel 底图
|
||||
order: 2
|
||||
---
|
||||
<code src="./district/Sentinel-2.tsx"></code>
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 北京瓦片
|
||||
order: 2
|
||||
---
|
||||
<code src="./district/citytile.tsx"></code>
|
|
@ -0,0 +1,45 @@
|
|||
// @ts-ignore
|
||||
import { Scene, RasterLayer, TileDebugLayer } from '@antv/l7';
|
||||
// @ts-ignore
|
||||
import { Map } from '@antv/l7-maps';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
export default () => {
|
||||
useEffect(() => {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
stencil: true,
|
||||
map: new Map({
|
||||
center: [113.270854, 23.141717],
|
||||
zoom: 11,
|
||||
}),
|
||||
});
|
||||
|
||||
const url1 =
|
||||
'https://tiles.maps.eox.at/wmts/1.0.0/s2cloudless-2020_3857_512/default/GoogleMapsCompatible_512/{z}/{y}/{x}.jpg';
|
||||
const layer1 = new RasterLayer({
|
||||
zIndex: 1,
|
||||
}).source(url1, {
|
||||
parser: {
|
||||
type: 'rasterTile',
|
||||
tileSize: 512,
|
||||
updateStrategy: 'realtime',
|
||||
},
|
||||
});
|
||||
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer1);
|
||||
const debugerLayer = new TileDebugLayer();
|
||||
scene.addLayer(debugerLayer);
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
height: '500px',
|
||||
position: 'relative',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -123,7 +123,6 @@ export default () => {
|
|||
scene.addLayer(line);
|
||||
scene.addLayer(line2);
|
||||
scene.addLayer(text);
|
||||
|
||||
scene.addLayer(debugerLayer);
|
||||
});
|
||||
}, []);
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
// @ts-ignore
|
||||
import { Scene, Source, PolygonLayer, LineLayer } from '@antv/l7';
|
||||
// @ts-ignore
|
||||
import { GaodeMapV2 } from '@antv/l7-maps';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
export default () => {
|
||||
useEffect(() => {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
stencil: true,
|
||||
map: new GaodeMapV2({
|
||||
center: [116.39852, 39.918255],
|
||||
zoom: 9,
|
||||
}),
|
||||
});
|
||||
|
||||
const source = new Source(
|
||||
'https://pre-gridwise.alibaba-inc.com/tile/test?z={z}&x={x}&y={y}',
|
||||
{
|
||||
parser: {
|
||||
type: 'mvt',
|
||||
tileSize: 256,
|
||||
// minZoom: 9,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const layer = new PolygonLayer({
|
||||
featureId: 'space_id',
|
||||
zIndex: 3,
|
||||
mask: false,
|
||||
sourceLayer: 'default', // woods hillshade contour ecoregions ecoregions2 city
|
||||
})
|
||||
.source(source)
|
||||
.shape('fill')
|
||||
.scale('space_val', {
|
||||
type: 'quantize',
|
||||
domain: [0, 100],
|
||||
})
|
||||
.color('space_val', [
|
||||
'#f2f0f7',
|
||||
'#cbc9e2',
|
||||
'#9e9ac8',
|
||||
'#756bb1',
|
||||
'#54278f',
|
||||
])
|
||||
.style({
|
||||
opacity: 0.8,
|
||||
});
|
||||
|
||||
const layer2 = new LineLayer({
|
||||
featureId: 'space_id',
|
||||
zIndex: 3,
|
||||
mask: false,
|
||||
sourceLayer: 'default', // woods hillshade contour ecoregions ecoregions2 city
|
||||
})
|
||||
.source(source)
|
||||
.shape('simple')
|
||||
.size(0.8)
|
||||
.color('#3E6Eff')
|
||||
.style({
|
||||
opacity: 1,
|
||||
});
|
||||
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer);
|
||||
scene.addLayer(layer2);
|
||||
|
||||
// const debugerLayer = new TileDebugLayer();
|
||||
// scene.addLayer(debugerLayer);
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
height: '100vh',
|
||||
position: 'relative',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
//
|
|
@ -0,0 +1,139 @@
|
|||
// @ts-ignore
|
||||
import {
|
||||
Scene,
|
||||
Source,
|
||||
PolygonLayer,
|
||||
TileDebugLayer,
|
||||
RasterLayer,
|
||||
PointLayer,
|
||||
} from '@antv/l7';
|
||||
// @ts-ignore
|
||||
import { Map } from '@antv/l7-maps';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
export default () => {
|
||||
useEffect(() => {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
stencil: true,
|
||||
map: new Map({
|
||||
center: [-95.7548387434569, 44.82687715672517],
|
||||
zoom: 9,
|
||||
}),
|
||||
});
|
||||
|
||||
const url1 =
|
||||
'https://api.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.webp?sku=101ifSAcKcVFs&access_token=pk.eyJ1IjoidW5mb2xkZWRpbmMiLCJhIjoiY2s5ZG90MjMzMDV6eDNkbnh2cDJvbHl4NyJ9.BT2LAvHi31vNNEplsgxucQ';
|
||||
const layer1 = new RasterLayer({
|
||||
zIndex: 1,
|
||||
}).source(url1, {
|
||||
parser: {
|
||||
type: 'rasterTile',
|
||||
tileSize: 256,
|
||||
},
|
||||
});
|
||||
|
||||
const source = new Source(
|
||||
'https://cdn.unfolded.ai/indigo/hexify_v5/{z}/{x}/{y}.pbf',
|
||||
{
|
||||
parser: {
|
||||
type: 'mvt',
|
||||
tileSize: 256,
|
||||
// minZoom: 9,
|
||||
},
|
||||
},
|
||||
);
|
||||
// const source2 = new Source(
|
||||
// 'https://cdn.unfolded.ai/indigo/hexify_v5/{z}/{x}/{y}.pbf',
|
||||
// {
|
||||
// parser: {
|
||||
// type: 'mvt',
|
||||
// tileSize: 256,
|
||||
// maxZoom: 9,
|
||||
// },
|
||||
// },
|
||||
// );
|
||||
const layer = new PolygonLayer({
|
||||
featureId: 'id',
|
||||
zIndex: 3,
|
||||
minZoom: 9,
|
||||
sourceLayer: 'state_s10_27', // woods hillshade contour ecoregions ecoregions2 city
|
||||
})
|
||||
.source(source)
|
||||
.shape('line')
|
||||
.color('#000')
|
||||
.size(0.3)
|
||||
.style({
|
||||
opacity: 1,
|
||||
});
|
||||
|
||||
const layer2 = new PolygonLayer({
|
||||
featureId: 'id',
|
||||
zIndex: 2,
|
||||
minZoom: 9,
|
||||
sourceLayer: 'state_s10_27', // woods hillshade contour ecoregions ecoregions2 city
|
||||
})
|
||||
.source(source)
|
||||
.shape('fill')
|
||||
.scale('croptype', {
|
||||
type: 'quantize',
|
||||
domain: [0, 4],
|
||||
})
|
||||
.color('croptype', [
|
||||
'#C1C9CC',
|
||||
'#DFB02F',
|
||||
'#7F8120',
|
||||
'#DCD0A4',
|
||||
'#AD5633',
|
||||
])
|
||||
.style({
|
||||
opacity: 1,
|
||||
});
|
||||
|
||||
const layer3 = new PointLayer({
|
||||
featureId: 'id',
|
||||
zIndex: 2,
|
||||
maxZoom: 9,
|
||||
mask: true,
|
||||
sourceLayer: 'parcel_pointgeojsonl', // woods hillshade contour ecoregions ecoregions2 city
|
||||
})
|
||||
.source(source)
|
||||
.shape('hexagon')
|
||||
.size(2)
|
||||
.scale('croptype', {
|
||||
type: 'quantize',
|
||||
domain: [0, 4],
|
||||
})
|
||||
.color('croptype', [
|
||||
'#C1C9CC',
|
||||
'#DFB02F',
|
||||
'#7F8120',
|
||||
'#DCD0A4',
|
||||
'#AD5633',
|
||||
])
|
||||
.style({
|
||||
opacity: 1,
|
||||
});
|
||||
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer);
|
||||
scene.addLayer(layer1);
|
||||
scene.addLayer(layer2);
|
||||
scene.addLayer(layer3);
|
||||
|
||||
const debugerLayer = new TileDebugLayer();
|
||||
scene.addLayer(debugerLayer);
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
height: '500px',
|
||||
position: 'relative',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// https://pre-gridwise.alibaba-inc.com/tile/test?z=13&x=6746&y=3104
|
|
@ -22,7 +22,6 @@ export default () => {
|
|||
)
|
||||
.then((d) => d.json())
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
const source = new Source(data, {
|
||||
parser: {
|
||||
type: 'geojsonvt',
|
||||
|
|
|
@ -129,18 +129,7 @@ export default () => {
|
|||
// layer.on('click', (e) => {
|
||||
// console.log('layer click');
|
||||
// console.log(e);
|
||||
// });
|
||||
|
||||
setTimeout(() => {
|
||||
layer.style({
|
||||
opacity: 0.6,
|
||||
rampColors: {
|
||||
colors: ['#f00', '#ff0'],
|
||||
positions: [0, 1],
|
||||
},
|
||||
});
|
||||
scene.render();
|
||||
}, 2000);
|
||||
// })
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -3,26 +3,34 @@ import {
|
|||
Scene,
|
||||
Source,
|
||||
PolygonLayer,
|
||||
LineLayer,
|
||||
TileDebugLayer,
|
||||
PointLayer,
|
||||
} from '@antv/l7';
|
||||
// @ts-ignore
|
||||
import { Map } from '@antv/l7-maps';
|
||||
import { GaodeMapV2 } from '@antv/l7-maps';
|
||||
import React, { useEffect } from 'react';
|
||||
import { data } from './data';
|
||||
|
||||
export default () => {
|
||||
useEffect(() => {
|
||||
const counts = [10000, 5000, 1000, 500, 100];
|
||||
const color = ['#41ae76', '#99d8c9', '#ccece6', '#e5f5f9', '#f7fcfd'];
|
||||
const color = [
|
||||
'#e41a1c',
|
||||
'#377eb8',
|
||||
'#4daf4a',
|
||||
'#984ea3',
|
||||
'#ff7f00',
|
||||
'#ffff33',
|
||||
];
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
stencil: true,
|
||||
map: new Map({
|
||||
center: [120, 30],
|
||||
map: new GaodeMapV2({
|
||||
center: [100, 30],
|
||||
// zoom: 12,
|
||||
minZoom: 0,
|
||||
zoom: 3,
|
||||
zoom: 2,
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -61,7 +69,7 @@ export default () => {
|
|||
return c.name == namestr;
|
||||
});
|
||||
if (!country) {
|
||||
return '#fff';
|
||||
return '#ffff33';
|
||||
}
|
||||
const qz = ((country.qz as unknown) as number) * 1;
|
||||
if (qz > counts[0]) {
|
||||
|
@ -77,30 +85,32 @@ export default () => {
|
|||
}
|
||||
});
|
||||
|
||||
// const line = new LineLayer({
|
||||
// sourceLayer: 'WLD_L',
|
||||
// zIndex: 2,
|
||||
// })
|
||||
// .source(source)
|
||||
// .shape('line')
|
||||
// .size(0.6)
|
||||
// .color('type', (t) => {
|
||||
// if (t === '0') {
|
||||
// return 'red';
|
||||
// }
|
||||
// if (t === '2') {
|
||||
// return '#09f';
|
||||
// }
|
||||
// return '#fc9272';
|
||||
// });
|
||||
const line = new LineLayer({
|
||||
sourceLayer: 'WLD_L',
|
||||
zIndex: 2,
|
||||
})
|
||||
.source(source)
|
||||
.shape('line')
|
||||
.size(0.6)
|
||||
.color('type', (t) => {
|
||||
if (t === '0') {
|
||||
return 'red';
|
||||
}
|
||||
if (t === '2') {
|
||||
return '#09f';
|
||||
}
|
||||
return '#fc9272';
|
||||
});
|
||||
|
||||
const text = new PointLayer({
|
||||
sourceLayer: 'WLD',
|
||||
// blend: 'normal',
|
||||
blend: 'normal',
|
||||
zIndex: 10,
|
||||
})
|
||||
.source(source)
|
||||
.shape('id', 'text')
|
||||
.shape('NAME_CHN', (NAME_CHN) => {
|
||||
return unicode2Char(NAME_CHN);
|
||||
})
|
||||
.size(12)
|
||||
.color('#000');
|
||||
|
||||
|
@ -114,8 +124,8 @@ export default () => {
|
|||
|
||||
scene.addLayer(water_surface);
|
||||
scene.addLayer(text);
|
||||
// scene.addLayer(line);
|
||||
const debugerLayer = new TileDebugLayer({ zIndex: 1 });
|
||||
scene.addLayer(line);
|
||||
const debugerLayer = new TileDebugLayer();
|
||||
scene.addLayer(debugerLayer);
|
||||
});
|
||||
}, []);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 矢量 FarmLand
|
||||
order: 2
|
||||
---
|
||||
<code src="./district/farmland.tsx"></code>
|
|
@ -68,7 +68,7 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
|
|||
active: false,
|
||||
activeColor: '#2f54eb',
|
||||
enableHighlight: false,
|
||||
enableSelect: true,
|
||||
enableSelect: false,
|
||||
highlightColor: '#2f54eb',
|
||||
activeMix: 0,
|
||||
selectColor: 'blue',
|
||||
|
|
|
@ -209,14 +209,8 @@ export default class PickingService implements IPickingService {
|
|||
data: new Uint8Array(1 * 1 * 4),
|
||||
framebuffer: this.pickingFBO,
|
||||
});
|
||||
this.pickedColors = pickedColors;
|
||||
|
||||
// let pickedColors = new Uint8Array(4)
|
||||
// this.rendererService.getGLContext().readPixels(
|
||||
// Math.floor(xInDevicePixel / this.pickBufferScale),
|
||||
// Math.floor((height - (y + 1) * DOM.DPR) / this.pickBufferScale),
|
||||
// 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pickedColors)
|
||||
// console.log(pickedColors[0] == pixels[0] && pickedColors[1] == pixels[1] && pickedColors[2] == pixels[2])
|
||||
this.pickedColors = pickedColors;
|
||||
|
||||
if (
|
||||
pickedColors[0] !== 0 ||
|
||||
|
@ -224,7 +218,7 @@ export default class PickingService implements IPickingService {
|
|||
pickedColors[2] !== 0
|
||||
) {
|
||||
const pickedFeatureIdx = decodePickingColor(pickedColors);
|
||||
|
||||
// 瓦片数据获取性能问题需要优化
|
||||
const rawFeature = layer.layerPickService.getFeatureById(pickedFeatureIdx);
|
||||
if (
|
||||
pickedFeatureIdx !== layer.getCurrentPickId() &&
|
||||
|
@ -362,6 +356,7 @@ export default class PickingService implements IPickingService {
|
|||
return layer.needPick(target.type)})
|
||||
.reverse()
|
||||
.some((layer) => {
|
||||
|
||||
clear({
|
||||
framebuffer: this.pickingFBO,
|
||||
color: [0, 0, 0, 0],
|
||||
|
@ -369,34 +364,8 @@ export default class PickingService implements IPickingService {
|
|||
depth: 1,
|
||||
});
|
||||
|
||||
// Tip: clear last picked tilelayer state
|
||||
// this.pickedTileLayers.map((pickedTileLayer) =>
|
||||
// (pickedTileLayer.tileLayer as ITileLayer)?.clearPick(target.type),
|
||||
// );
|
||||
|
||||
// Tip: 如果当前 layer 是瓦片图层,则走瓦片图层独立的拾取逻辑
|
||||
// if (layer.tileLayer && (layer.tileLayer as ITileLayer).pickLayers) {
|
||||
// return (layer.tileLayer as ITileLayer).pickLayers(target);
|
||||
// }
|
||||
|
||||
// 将当前的 layer 绘制到 pickingFBO
|
||||
// 普通图层和瓦片图层的 layerPickService 拥有不同的 pickRender 方法
|
||||
layer.layerPickService.pickRender(target);
|
||||
|
||||
// layer.hooks.beforePickingEncode.call();
|
||||
|
||||
// if (layer.masks.length > 0) {
|
||||
// // 若存在 mask,则在 pick 阶段的绘制也启用
|
||||
// layer.masks.map(async (m: ILayer) => {
|
||||
// m.hooks.beforeRender.call();
|
||||
// m.render();
|
||||
// m.hooks.afterRender.call();
|
||||
// });
|
||||
// }
|
||||
// layer.renderModels(true);
|
||||
// layer.hooks.afterPickingEncode.call();
|
||||
const isPicked = this.pickFromPickingFBO(layer, target);
|
||||
|
||||
this.layerService.pickedLayerId = isPicked ? +layer.id : -1;
|
||||
return isPicked && !layer.getLayerConfig().enablePropagation;
|
||||
});
|
||||
|
@ -422,31 +391,4 @@ export default class PickingService implements IPickingService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* highlight 如果直接修改选中 feature 的 buffer,存在两个问题:
|
||||
* 1. 鼠标移走时无法恢复
|
||||
* 2. 无法实现高亮颜色与原始原色的 alpha 混合
|
||||
* 因此高亮还是放在 shader 中做比较好
|
||||
* @example
|
||||
* this.layer.color('name', ['#000000'], {
|
||||
* featureRange: {
|
||||
* startIndex: pickedFeatureIdx,
|
||||
* endIndex: pickedFeatureIdx + 1,
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
private highlightPickedFeature(
|
||||
layer: ILayer,
|
||||
pickedColors: Uint8Array | undefined,
|
||||
) {
|
||||
// @ts-ignore
|
||||
const [r, g, b] = pickedColors;
|
||||
layer.hooks.beforeHighlight.call([r, g, b]);
|
||||
}
|
||||
|
||||
private selectFeature(layer: ILayer, pickedColors: Uint8Array | undefined) {
|
||||
// @ts-ignore
|
||||
const [r, g, b] = pickedColors;
|
||||
layer.hooks.beforeSelect.call([r, g, b]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -870,7 +870,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
|
|||
minZoom = -Infinity,
|
||||
maxZoom = Infinity,
|
||||
} = this.getLayerConfig();
|
||||
return !!visible && zoom >= minZoom && zoom <= maxZoom;
|
||||
return !!visible && zoom >= minZoom && zoom < maxZoom;
|
||||
}
|
||||
|
||||
public setMultiPass(
|
||||
|
|
|
@ -25,6 +25,7 @@ export default class FillModel extends BaseModel {
|
|||
dir: 'in',
|
||||
},
|
||||
} = this.layer.getLayerConfig() as IPolygonLayerStyleOptions;
|
||||
|
||||
if (this.dataTextureTest && this.dataTextureNeedUpdate({ opacity })) {
|
||||
this.judgeStyleAttributes({ opacity });
|
||||
const encodeData = this.layer.getEncodedData();
|
||||
|
@ -52,7 +53,9 @@ export default class FillModel extends BaseModel {
|
|||
width: 1,
|
||||
height: 1,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
u_dataTexture: this.dataTexture, // 数据纹理 - 有数据映射的时候纹理中带数据,若没有任何数据映射时纹理是 [1]
|
||||
u_cellTypeLayout: this.getCellTypeLayout(),
|
||||
|
|
|
@ -53,14 +53,52 @@ export class TileLayerService {
|
|||
}
|
||||
updateTileVisible(sourceTile: SourceTile) {
|
||||
const tile = this.getTile(sourceTile.key);
|
||||
// if(sourceTile.isVisible) {
|
||||
// // 不可见 => 可见 兄弟节点加载完成
|
||||
// if(sourceTile.parent) {
|
||||
// const flag = this.isChildrenLoaded(sourceTile.parent)
|
||||
// tile?.updateVisible(flag);
|
||||
// } else {
|
||||
// tile?.updateVisible(true);
|
||||
// }
|
||||
|
||||
// } else {
|
||||
// // 可见 => 不可见 兄弟节点加载完成
|
||||
// if(sourceTile.parent) {
|
||||
// const flag = this.isChildrenLoaded(sourceTile.parent)
|
||||
// tile?.updateVisible(!flag);
|
||||
// } else {
|
||||
// tile?.updateVisible(false);
|
||||
// }
|
||||
// }
|
||||
|
||||
tile?.updateVisible(sourceTile.isVisible);
|
||||
|
||||
}
|
||||
beforeRender() {
|
||||
// TODO 统一处理状态更新 attribute style
|
||||
|
||||
public isParentLoaded(sourceTile: SourceTile): boolean {
|
||||
const parentTile = sourceTile.parent;
|
||||
if(!parentTile) {
|
||||
return true
|
||||
}
|
||||
const tile = this.getTile(parentTile?.key)
|
||||
if(tile?.isLoaded) { // 递归父级
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
public isChildrenLoaded(sourceTile: SourceTile):boolean {
|
||||
const childrenTile = sourceTile?.children;
|
||||
if(childrenTile.length === 0) {
|
||||
return true
|
||||
}
|
||||
return childrenTile.some((tile:SourceTile)=>{
|
||||
const tileLayer = this.getTile(tile?.key)
|
||||
return tileLayer?.isLoaded === false
|
||||
})
|
||||
}
|
||||
async render() {
|
||||
const layers = this.getRenderLayers();
|
||||
layers.map(async layer => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { ILayerService, ITile, ITilePickService, IInteractionTarget } from '@antv/l7-core';
|
||||
import { decodePickingColor, encodePickingColor } from '@antv/l7-utils';
|
||||
import { TileLayerService } from './TileLayerService';
|
||||
import { TileSourceService } from './TileSourceService';
|
||||
export interface ITilePickServiceOptions {
|
||||
|
@ -24,15 +25,14 @@ export class TilePickService implements ITilePickService{
|
|||
if (tile) {
|
||||
// TODO 多图层拾取
|
||||
const pickLayer = tile.getMainLayer();
|
||||
if (pickLayer) {
|
||||
pickLayer.layerPickService.pickRender(target)
|
||||
}
|
||||
pickLayer?.layerPickService.pickRender(target)
|
||||
|
||||
}
|
||||
}
|
||||
selectFeature(pickedColors: Uint8Array | undefined) {
|
||||
// @ts-ignore
|
||||
const [r, g, b] = pickedColors;
|
||||
const id = this.clor2PickId(r, g, b);
|
||||
const id = this.color2PickId(r, g, b);
|
||||
this.tilePickID.set(SELECT, id);
|
||||
this.updateHighLight(r, g, b, SELECT);
|
||||
}
|
||||
|
@ -40,24 +40,23 @@ export class TilePickService implements ITilePickService{
|
|||
highlightPickedFeature(pickedColors: Uint8Array | undefined) {
|
||||
// @ts-ignore
|
||||
const [r, g, b] = pickedColors;
|
||||
const id = this.clor2PickId(r, g, b);
|
||||
const id = this.color2PickId(r, g, b);
|
||||
this.tilePickID.set(ACTIVE, id);
|
||||
this.updateHighLight(r, g, b, ACTIVE);
|
||||
}
|
||||
|
||||
updateHighLight(r: number, g: number, b: number, type: string){
|
||||
this.tileLayerService.tiles.map((tile: ITile) => {
|
||||
const layers = tile.getLayers();
|
||||
layers.forEach((layer) => {
|
||||
const layer = tile.getMainLayer();
|
||||
switch(type) {
|
||||
case SELECT:
|
||||
layer.hooks.beforeSelect.call([r, g, b]);
|
||||
layer?.hooks.beforeSelect.call([r, g, b]);
|
||||
break;
|
||||
case ACTIVE:
|
||||
layer.hooks.beforeHighlight.call([r, g, b]);
|
||||
layer?.hooks.beforeHighlight.call([r, g, b]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -76,12 +75,12 @@ export class TilePickService implements ITilePickService{
|
|||
}
|
||||
}
|
||||
|
||||
private clor2PickId (r: number, g: number, b: number){
|
||||
return r + '-' + g + '-' + b;
|
||||
private color2PickId (r: number, g: number, b: number){
|
||||
return decodePickingColor(new Uint8Array([r,g,b]))
|
||||
}
|
||||
|
||||
private pickId2Color(str: string){
|
||||
return str.split('-').map(n => +n)
|
||||
private pickId2Color(str: number){
|
||||
return encodePickingColor(str )
|
||||
}
|
||||
|
||||
/** 从瓦片中根据数据 */
|
||||
|
@ -99,6 +98,9 @@ export class TilePickService implements ITilePickService{
|
|||
}
|
||||
// 将 feature 列表合并后返回
|
||||
// 统一返回成 polygon 的格式 点、线、面可以通用
|
||||
return this.tileSourceService.getCombineFeature(features);
|
||||
|
||||
// const data = this.tileSourceService.getCombineFeature(features);
|
||||
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ILayer, createLayerContainer, ILngLat, ITile } from '@antv/l7-core';
|
||||
import { SourceTile } from '@antv/l7-utils';
|
||||
import { Container } from 'inversify';
|
||||
import { Feature, Properties } from '@turf/helpers';
|
||||
|
||||
export default abstract class Tile implements ITile{
|
||||
public x: number;
|
||||
public y: number;
|
||||
|
@ -35,6 +35,7 @@ export default abstract class Tile implements ITile{
|
|||
return lng >= minLng && lng <= maxLng && lat >= minLat && lat <= maxLat;
|
||||
}
|
||||
|
||||
|
||||
protected async addMask(layer: ILayer, mask: ILayer) {
|
||||
const container = createLayerContainer(
|
||||
this.parent.sceneContainer as Container,
|
||||
|
@ -75,45 +76,17 @@ export default abstract class Tile implements ITile{
|
|||
return this.layers[0];
|
||||
}
|
||||
|
||||
public getFeatures(sourceLayer: string | undefined){
|
||||
if(!sourceLayer || !this.sourceTile.data?.layers[sourceLayer]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const vectorTile = this.sourceTile.data?.layers[sourceLayer];
|
||||
|
||||
if(Array.isArray(vectorTile.features)) {
|
||||
// 数据不需要被解析 geojson-vt 类型
|
||||
return vectorTile.features;
|
||||
}
|
||||
|
||||
const { x, y, z } = this.sourceTile;
|
||||
const features: Feature<GeoJSON.Geometry, Properties>[] = [];
|
||||
for( let i = 0; i < vectorTile.length; i++ ) {
|
||||
const vectorTileFeature = vectorTile.feature(i);
|
||||
const feature = vectorTileFeature.toGeoJSON(x, y, z);
|
||||
features.push({
|
||||
...feature,
|
||||
properties: {
|
||||
id: feature.id,
|
||||
...feature.properties,
|
||||
},
|
||||
})
|
||||
}
|
||||
return features;
|
||||
public getFeatures(sourceLayer: string | undefined):any[] {
|
||||
return []
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在一个 Tile 中可能存在一个相同 ID 的 feature
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
public getFeatureById(id: number) {
|
||||
const layer = this.getMainLayer();
|
||||
if (!layer) {
|
||||
return [];
|
||||
}
|
||||
return layer.getSource().data.dataArray.filter(d => d._id === id);
|
||||
public getFeatureById(id: number):any[] {
|
||||
return []
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import { ILayer, ILayerAttributesOption } from '@antv/l7-core';
|
||||
import Tile from './Tile';
|
||||
import { getTileLayer, getMaskLayer } from './util';
|
||||
|
||||
import { getTileLayer, isNeedMask } from './util';
|
||||
import MaskLayer from '../../mask';
|
||||
import { VectorSource } from '@antv/l7-source'
|
||||
|
||||
export default class VectorTile extends Tile {
|
||||
public async initTileLayer(): Promise<void> {
|
||||
const attributes = this.parent.getLayerAttributeConfig();
|
||||
const layerOptions = this.parent.getLayerConfig()
|
||||
layerOptions.mask = isNeedMask(this.parent.type) ||layerOptions.mask;
|
||||
const vectorLayer = getTileLayer(this.parent.type);
|
||||
const maskLayer = getMaskLayer(this.parent.type);
|
||||
layerOptions.mask = !!maskLayer;
|
||||
|
||||
|
||||
|
||||
const sourceOptions = this.getSourceOption();
|
||||
if(!sourceOptions){
|
||||
this.isLoaded = true;
|
||||
|
@ -21,7 +20,7 @@ export default class VectorTile extends Tile {
|
|||
sourceOptions.data,
|
||||
sourceOptions.options,
|
||||
);
|
||||
|
||||
|
||||
|
||||
// 初始化数据映射
|
||||
Object.keys(attributes).forEach((type) => {
|
||||
|
@ -29,8 +28,17 @@ export default class VectorTile extends Tile {
|
|||
// @ts-ignore
|
||||
layer[attr](attributes[attr]?.field, attributes[attr]?.values);
|
||||
});
|
||||
if (maskLayer) {
|
||||
const mask = new maskLayer({layerType: "MaskLayer"})
|
||||
if(layerOptions.mask ) {
|
||||
await this.addTileMask(layer)
|
||||
}
|
||||
|
||||
await this.addLayer(layer);
|
||||
this.setLayerMinMaxZoom(layer);
|
||||
this.isLoaded = true;
|
||||
}
|
||||
// Todo 校验数据有效性
|
||||
protected async addTileMask(layer: ILayer) {
|
||||
const mask = new MaskLayer({layerType: "MaskLayer"})
|
||||
.source({
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
|
@ -39,19 +47,10 @@ export default class VectorTile extends Tile {
|
|||
}, {
|
||||
parser: {
|
||||
type: 'geojson',
|
||||
featureId: 'id'
|
||||
}
|
||||
})
|
||||
// .style({
|
||||
// opacity: 1
|
||||
// });
|
||||
await this.addMask(layer, mask)
|
||||
}
|
||||
await this.addLayer(layer);
|
||||
this.setLayerMinMaxZoom(layer);
|
||||
this.isLoaded = true;
|
||||
}
|
||||
// Todo 校验数据有效性
|
||||
protected beforeInit() {
|
||||
|
||||
}
|
||||
protected getSourceOption() {
|
||||
|
@ -86,4 +85,22 @@ export default class VectorTile extends Tile {
|
|||
}
|
||||
|
||||
}
|
||||
public getFeatures(sourceLayer: string){
|
||||
const source = this.sourceTile.data as VectorSource;
|
||||
return source.getTileData(sourceLayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在一个 Tile 中可能存在一个相同 ID 的 feature
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
public getFeatureById(id: number) {
|
||||
const layer = this.getMainLayer();
|
||||
if (!layer) {
|
||||
return [];
|
||||
}
|
||||
return layer.getSource().data.dataArray.filter(d => d._id === id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import PointLayer from '../../point/index';
|
||||
import LineLayer from '../../line';
|
||||
import PolygonLayer from '../../polygon';
|
||||
import MaskLayer from '../../mask';
|
||||
|
||||
|
||||
export function getTileLayer(type: string) {
|
||||
if(type === 'PolygonLayer') {
|
||||
|
@ -18,15 +18,6 @@ export function getTileLayer(type: string) {
|
|||
|
||||
}
|
||||
|
||||
export function getMaskLayer(type: string){
|
||||
switch(type) {
|
||||
case 'PolygonLayer':
|
||||
case 'LineLayer':
|
||||
return MaskLayer;
|
||||
case 'PointLayer':
|
||||
case 'RasterLayer':
|
||||
return undefined;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
export function isNeedMask(type: string) {
|
||||
return ['PolygonLayer','LineLayer'].indexOf(type) !== -1
|
||||
}
|
|
@ -181,10 +181,12 @@ export default class BaseTileLayer {
|
|||
if (!this.tilesetManager) {
|
||||
return;
|
||||
}
|
||||
const minZoom = this.parent.getMinZoom();
|
||||
const maxZoom = this.parent.getMaxZoom()
|
||||
await Promise.all(this.tilesetManager.tiles
|
||||
.filter((tile: SourceTile) => tile.isLoaded) // 过滤未加载完成的
|
||||
.filter((tile: SourceTile) => tile.isVisibleChange) // 过滤未发生变化的
|
||||
.filter((tile: SourceTile) => this.isTileReady(tile)) // 过滤未发生变化的
|
||||
.filter((tile: SourceTile) => tile.z>= minZoom && tile.z < maxZoom)
|
||||
.map(async (tile: SourceTile) => {
|
||||
if (!this.tileLayerService.hasTile(tile.key)) {
|
||||
const tileInstance = getTileFactory(this.parent);
|
||||
|
@ -193,11 +195,11 @@ export default class BaseTileLayer {
|
|||
this.tilePickService.setPickState();
|
||||
if(tileLayer.getLayers().length!==0) {
|
||||
this.tileLayerService.addTile(tileLayer);
|
||||
this.tileLayerService.updateTileVisible(tile);
|
||||
this.layerService.reRender()
|
||||
}
|
||||
this.tileLayerService.addTile(tileLayer);
|
||||
this.layerService.reRender()
|
||||
} else {
|
||||
} else {// 已加载瓦片
|
||||
|
||||
this.tileLayerService.updateTileVisible(tile);
|
||||
this.tilePickService.setPickState();
|
||||
this.layerService.reRender()
|
||||
|
@ -210,21 +212,6 @@ export default class BaseTileLayer {
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public isTileReady(tile: SourceTile) {
|
||||
|
||||
// if (tile.data?.layers && this.sourceLayer) {
|
||||
// // vector
|
||||
// const vectorTileLayer = tile.data.layers[this.sourceLayer];
|
||||
// const features = vectorTileLayer?.features;
|
||||
// if (!(Array.isArray(features) && features.length > 0)) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public setPickState(layers: ILayer[]) {}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import { aggregatorToGrid } from './transform/grid';
|
|||
import { pointToHexbin } from './transform/hexagon';
|
||||
import { join } from './transform/join';
|
||||
import { map } from './transform/map';
|
||||
export * from './source/index';
|
||||
|
||||
registerParser('rasterTile', rasterTile);
|
||||
registerParser('mvt', mapboxVectorTile);
|
||||
|
|
|
@ -36,16 +36,13 @@ function getFeatureID(feature: Feature<Geometries, Properties>, key?: string) {
|
|||
if (key === undefined) {
|
||||
return null;
|
||||
}
|
||||
if (key === 'id' && feature.id) {
|
||||
// 标准 mapbox vector feature
|
||||
return feature.id;
|
||||
}
|
||||
// @ts-ignore
|
||||
if (feature[key]) {
|
||||
if (feature.properties[key]) {
|
||||
// 单独指定要素
|
||||
// @ts-ignore
|
||||
return feature[key];
|
||||
return feature.properties[key];
|
||||
}
|
||||
|
||||
if (feature.properties && feature.properties[key]) {
|
||||
// 根据 properties 要素的属性进行编码
|
||||
return djb2hash(feature.properties[key] + '') % 1000019;
|
||||
|
@ -59,7 +56,6 @@ export default function geoJSON(
|
|||
): IParserData {
|
||||
const resultData: IParseDataItem[] = [];
|
||||
const featureKeys: IFeatureKey = {};
|
||||
|
||||
if (!data.features) {
|
||||
data.features = [];
|
||||
return {
|
||||
|
@ -95,6 +91,7 @@ export default function geoJSON(
|
|||
if (featureId === null) {
|
||||
featureId = featureIndex;
|
||||
}
|
||||
|
||||
const sortedID = featureId;
|
||||
|
||||
const coord = getCoords(currentFeature);
|
||||
|
|
|
@ -7,10 +7,10 @@ import {
|
|||
TileLoadParams,
|
||||
TilesetManagerOptions,
|
||||
} from '@antv/l7-utils';
|
||||
import { VectorTile, VectorTileLayer } from '@mapbox/vector-tile';
|
||||
import { VectorTileLayer } from '@mapbox/vector-tile';
|
||||
import { Feature } from '@turf/helpers';
|
||||
import Protobuf from 'pbf';
|
||||
import { IParserData } from '../interface';
|
||||
import VectorSource from '../source/vector';
|
||||
|
||||
const DEFAULT_CONFIG: Partial<TilesetManagerOptions> = {
|
||||
tileSize: 256,
|
||||
|
@ -29,7 +29,7 @@ const getVectorTile = async (
|
|||
tileParams: TileLoadParams,
|
||||
tile: SourceTile,
|
||||
requestParameters?: Partial<RequestParameters>,
|
||||
): Promise<MapboxVectorTile> => {
|
||||
): Promise<VectorSource | undefined> => {
|
||||
const tileUrl = getURLFromTemplate(url, tileParams);
|
||||
return new Promise((resolve) => {
|
||||
const xhr = getArrayBuffer(
|
||||
|
@ -39,12 +39,13 @@ const getVectorTile = async (
|
|||
},
|
||||
(err, data) => {
|
||||
if (err || !data) {
|
||||
resolve({ layers: {} });
|
||||
resolve(undefined);
|
||||
} else {
|
||||
const vectorTile = new VectorTile(
|
||||
new Protobuf(data),
|
||||
) as MapboxVectorTile;
|
||||
resolve(vectorTile);
|
||||
const vectorSource = new VectorSource(data, tile.x, tile.y, tile.z);
|
||||
// const vectorTile = new VectorTile(
|
||||
// new Protobuf(data),
|
||||
// ) as MapboxVectorTile;
|
||||
resolve(vectorSource);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import { ITileSource } from './interface';
|
||||
export default abstract class BaseSource implements ITileSource {
|
||||
protected x: number;
|
||||
protected y: number;
|
||||
protected z: number;
|
||||
constructor(data: any, x: number, y: number, z: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
public abstract getTileData(layer: string): any;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './interface';
|
||||
export { default as VectorSource } from './vector';
|
|
@ -0,0 +1,9 @@
|
|||
import { VectorTileLayer } from '@mapbox/vector-tile';
|
||||
import { Feature } from '@turf/helpers';
|
||||
export interface ITileSource {
|
||||
getTileData(layer: string): any;
|
||||
}
|
||||
|
||||
export type MapboxVectorTile = {
|
||||
layers: { [_: string]: VectorTileLayer & { features: Feature[] } };
|
||||
};
|
|
@ -0,0 +1,60 @@
|
|||
import { VectorTile } from '@mapbox/vector-tile';
|
||||
import { Feature, Properties } from '@turf/helpers';
|
||||
import Protobuf from 'pbf';
|
||||
import { ITileSource, MapboxVectorTile } from './interface';
|
||||
export default class VectorSource implements ITileSource {
|
||||
private vectorTile: VectorTile;
|
||||
private vectorLayerCache: {
|
||||
[key: string]: Array<Feature<GeoJSON.Geometry, Properties>>;
|
||||
} = {};
|
||||
private x: number;
|
||||
private y: number;
|
||||
private z: number;
|
||||
|
||||
constructor(data: ArrayBuffer, x: number, y: number, z: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.vectorTile = new VectorTile(new Protobuf(data)) as MapboxVectorTile;
|
||||
}
|
||||
|
||||
public getTileData(sourceLayer: string) {
|
||||
if (!sourceLayer || !this.vectorTile.layers[sourceLayer]) {
|
||||
return [];
|
||||
}
|
||||
// 优先走缓存
|
||||
if (this.vectorLayerCache[sourceLayer]) {
|
||||
return this.vectorLayerCache[sourceLayer];
|
||||
}
|
||||
|
||||
const vectorTile = this.vectorTile.layers[sourceLayer];
|
||||
|
||||
// @ts-ignore
|
||||
if (Array.isArray(vectorTile.features)) {
|
||||
// 数据不需要被解析 geojson-vt 类型
|
||||
// @ts-ignore
|
||||
this.vectorLayerCache[sourceLayer] = vectorTile.features;
|
||||
// @ts-ignore
|
||||
return vectorTile.features;
|
||||
}
|
||||
|
||||
const features: Array<Feature<GeoJSON.Geometry, Properties>> = [];
|
||||
for (let i = 0; i < vectorTile.length; i++) {
|
||||
const vectorTileFeature = vectorTile.feature(i);
|
||||
const feature = vectorTileFeature.toGeoJSON(this.x, this.y, this.z);
|
||||
|
||||
features.push({
|
||||
...feature,
|
||||
properties: {
|
||||
id: feature.id,
|
||||
...feature.properties,
|
||||
},
|
||||
});
|
||||
}
|
||||
this.vectorLayerCache[sourceLayer] = features;
|
||||
return features;
|
||||
}
|
||||
public getFeatureById() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
|
@ -105,6 +105,7 @@ export class SourceTile extends EventEmitter {
|
|||
const polygon = bboxPolygon(this.bounds as TileBounds, {
|
||||
properties: {
|
||||
key: this.key,
|
||||
id: this.key,
|
||||
bbox: this.bounds,
|
||||
center,
|
||||
meta: `
|
||||
|
|
|
@ -109,10 +109,11 @@ export class TilesetManager extends EventEmitter {
|
|||
verifyZoom,
|
||||
latLonBoundsBuffer,
|
||||
).filter((tile) => {
|
||||
// 处理数据 warp
|
||||
return (
|
||||
this.options.warp || (tile.x >= 0 && tile.x <= Math.pow(verifyZoom, 2))
|
||||
this.options.warp || (tile.x >= 0 && tile.x < Math.pow(2, verifyZoom))
|
||||
);
|
||||
}); // TODO 数据循环
|
||||
});
|
||||
this.currentTiles = tileIndices.map(({ x, y, z }) => {
|
||||
let tile = this.getTile(x, y, z);
|
||||
if (tile) {
|
||||
|
|
Loading…
Reference in New Issue