Merge branch 'feat_source_hooks' of https://github.com/antvis/L7 into feat_source_hooks

This commit is contained in:
lzxue 2022-11-07 16:30:58 +08:00
commit 45d239c3ff
31 changed files with 542 additions and 225 deletions

View File

@ -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);

View File

@ -24,8 +24,7 @@ export default () => {
parser: {
type: 'rasterTile',
tileSize: 256,
// zoomOffset: 0
// zoomOffset: 1,
},
},
);

View File

@ -0,0 +1,5 @@
---
title: SenTinel 底图
order: 2
---
<code src="./district/Sentinel-2.tsx"></code>

View File

@ -0,0 +1,5 @@
---
title: 北京瓦片
order: 2
---
<code src="./district/citytile.tsx"></code>

View File

@ -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',
}}
/>
);
};

View File

@ -123,7 +123,6 @@ export default () => {
scene.addLayer(line);
scene.addLayer(line2);
scene.addLayer(text);
scene.addLayer(debugerLayer);
});
}, []);

View File

@ -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',
}}
/>
);
};
//

View File

@ -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

View File

@ -22,7 +22,6 @@ export default () => {
)
.then((d) => d.json())
.then((data) => {
console.log(data);
const source = new Source(data, {
parser: {
type: 'geojsonvt',

View File

@ -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);
// })
});
});

View File

@ -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);
});
}, []);

View File

@ -0,0 +1,5 @@
---
title: 矢量 FarmLand
order: 2
---
<code src="./district/farmland.tsx"></code>

View File

@ -68,7 +68,7 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
active: false,
activeColor: '#2f54eb',
enableHighlight: false,
enableSelect: true,
enableSelect: false,
highlightColor: '#2f54eb',
activeMix: 0,
selectColor: 'blue',

View File

@ -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]);
}
}

View File

@ -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(

View File

@ -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(),

View File

@ -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 => {

View File

@ -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 []
}
}

View File

@ -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() {

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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[]) {}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
},
);

View File

@ -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;
}

View File

@ -0,0 +1,2 @@
export * from './interface';
export { default as VectorSource } from './vector';

View File

@ -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[] } };
};

View File

@ -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.');
}
}

View File

@ -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: `

View File

@ -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) {