feat: 完善矢量图层事件的数据拾取 (#1449)

* feat: change vector tile get data

* feat: 瓦片图层事件支持获取数据

* style: lint style

* feat: 修改瓦片图层事件获取数据的方法

* style: lint style

* fix: 修复 MaskLayer 失效

* feat: 完善矢量瓦片事件获取数据

* feat: geojson-vt 兼容新的数据解析逻辑

* style: lint style

* feat: add tile getMainLayer

* style: lint style

Co-authored-by: shihui <yiqianyao.yqy@alibaba-inc.com>
This commit is contained in:
YiQianYao 2022-10-31 14:29:21 +08:00 committed by GitHub
parent 58947c2461
commit cf6b0f8147
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 149 additions and 85 deletions

View File

@ -45,7 +45,7 @@ export default () => {
// const height = image.getHeight();
// const value0 = await image.readRasters();
const image1 = await tiff.getImage(1);
const image1 = await tiff.getImage(2);
const value1 = await image1.readRasters();
// console.log(value1)
@ -67,14 +67,43 @@ export default () => {
operation: {
// blue green red nir
// 标准真彩色 rgb
r: ['-', ['band', 2], 155],
g: ['-', ['band', 1], 184],
b: ['-', ['band', 0], 295],
// r: ['-', ['band', 2], 155],
// g: ['-', ['band', 1], 184],
// b: ['-', ['band', 0], 295],
// 标准假彩色 432
// // 标准假彩色 432
// r: ['-', ['band', 3], 295],
// g: ['-', ['band', 2], 184],
// b: ['-', ['band', 1], 295],
// 标准假彩色 432
// r: ['*', ['/', ['band', 3], 234], 255],
// g: ['*', ['/', ['band', 2], 296], 255],
// b: ['*', ['/', ['band', 1], 296], 255],
// r: ['-', ['band', 3], 234],
// g: ['-', ['band', 2], 296],
// b: ['-', ['band', 1], 296],
// r: ['/', ['band', 3], 234],
// g: ['/', ['band', 2], 296],
// b: ['/', ['band', 1], 296],
// r: ['/', ['band', 3], 2],
// g: ['/', ['band', 2], 2],
// b: ['/', ['band', 1], 2],
// r: ['band', 3],
// g: ['band', 2],
// b: ['band', 1],
r: ['-', ['band', 3], 113],
g: ['-', ['band', 2], 155],
b: ['-', ['band', 1], 184],
},
extent: [73.482190241, 3.82501784112, 135.106618732, 57.6300459963],
},
@ -89,9 +118,17 @@ export default () => {
// channelGMax: 131,
// channelBMax: 141
// channelRMax: 256,
// channelGMax: 256,
// channelBMax: 256
// channelRMax: 234,
// channelGMax: 296,
// channelBMax: 296
channelRMax: 234 - 133,
channelGMax: 296 - 155,
channelBMax: 296 - 184
// channelRMax: 255,
// channelGMax: 255,
// channelBMax: 255
});
scene.addLayer(layer);
});

View File

@ -16,7 +16,10 @@ export default () => {
}),
});
fetch('http://30.230.91.181:8080/water.geojson')
// fetch('http://30.230.91.181:8080/water.geojson')
fetch(
'https://gw.alipayobjects.com/os/bmw-prod/2b7aae6e-5f40-437f-8047-100e9a0d2808.json',
)
.then((d) => d.json())
.then((data) => {
console.log(data);

View File

@ -1,5 +1,5 @@
// @ts-ignore
import { Scene, RasterLayer } from '@antv/l7';
import { Scene, RasterLayer, MaskLayer } from '@antv/l7';
// @ts-ignore
import { Map } from '@antv/l7-maps';
import React, { useEffect } from 'react';
@ -16,26 +16,26 @@ export default () => {
}),
});
// const mask = new MaskLayer({
// sourceLayer: 'ecoregions2', // woods hillshade contour ecoregions ecoregions2 city
// }).source(
// 'http://ganos.oss-cn-hangzhou.aliyuncs.com/m2/rs_l7/{z}/{x}/{y}.pbf',
// {
// parser: {
// type: 'mvt',
// tileSize: 256,
// maxZoom: 9,
// extent: [-180, -85.051129, 179, 85.051129],
// },
// },
// );
const mask = new MaskLayer({
sourceLayer: 'ecoregions2', // woods hillshade contour ecoregions ecoregions2 city
}).source(
'http://ganos.oss-cn-hangzhou.aliyuncs.com/m2/rs_l7/{z}/{x}/{y}.pbf',
{
parser: {
type: 'mvt',
tileSize: 256,
maxZoom: 9,
extent: [-180, -85.051129, 179, 85.051129],
},
},
);
const layer = new RasterLayer({
zIndex: 1,
// mask: true,
mask: true,
}).source(
'https://www.google.cn/maps/vt?lyrs=s@820&gl=cn&x={x}&y={y}&z={z}',
// 'http://webst0{1-4}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
// 'https://www.google.cn/maps/vt?lyrs=s@820&gl=cn&x={x}&y={y}&z={z}',
'http://webst0{1-4}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
{
parser: {
type: 'rasterTile',
@ -46,7 +46,7 @@ export default () => {
);
scene.on('loaded', () => {
// scene.addLayer(mask);
scene.addLayer(mask);
scene.addLayer(layer);
});
}, []);

View File

@ -225,7 +225,7 @@ export default class PickingService implements IPickingService {
) {
const pickedFeatureIdx = decodePickingColor(pickedColors);
const rawFeature = layer.layerPickService.getFeatureById(pickedFeatureIdx, lngLat);
const rawFeature = layer.layerPickService.getFeatureById(pickedFeatureIdx);
if (
pickedFeatureIdx !== layer.getCurrentPickId() &&
type === 'mousemove'

View File

@ -225,27 +225,9 @@ export interface ITile {
sourceTile: SourceTile;
visible: boolean;
isLoaded: boolean;
getMainLayer(): ILayer | undefined;
getLayers(): ILayer[];
styleUpdate(...args: any): void;
initTileLayer(): Promise<void>;
lnglatInBounds(lnglat: {
lng: number;
lat: number;
}): boolean;
updateVisible(value: boolean): void;
updateOptions(key: string, value: any): void;
destroy(): void;
}
export interface ITile {
x: number;
y: number;
z: number;
key: string;
sourceTile: SourceTile;
visible: boolean;
isLoaded: boolean;
getLayers(): ILayer[];
getFeatureById(id: number): any;
styleUpdate(...args: any): void;
initTileLayer(): Promise<void>;
lnglatInBounds(lnglat: {

View File

@ -1,5 +1,6 @@
import { ILayerService, ITile, ITilePickService, ILngLat, IInteractionTarget } from '@antv/l7-core';
import { ILayerService, ITile, ITilePickService, IInteractionTarget } from '@antv/l7-core';
import { TileLayerService } from './TileLayerService';
import { TileSourceService } from './TileSourceService';
export interface ITilePickServiceOptions {
layerService: ILayerService;
tileLayerService: TileLayerService;
@ -10,18 +11,22 @@ const ACTIVE = 'active';
export class TilePickService implements ITilePickService{
private layerService: ILayerService;
private tileLayerService: TileLayerService;
private tileSourceService: TileSourceService;
private tilePickID = new Map();
constructor({ layerService, tileLayerService }: ITilePickServiceOptions) {
this.layerService = layerService;
this.tileLayerService = tileLayerService;
this.tileSourceService = new TileSourceService();
}
pickRender(target: IInteractionTarget) {
// 一个 TileLayer 有多个 Tile但是会同时触发事件的只有一个 Tile
const tile = this.tileLayerService.getVisibleTileBylngLat(target.lngLat);
if (tile) {
// TODO 多图层拾取
const pickLayer = tile.getLayers()[0];
pickLayer.layerPickService.pickRender(target)
const pickLayer = tile.getMainLayer();
if (pickLayer) {
pickLayer.layerPickService.pickRender(target)
}
}
}
selectFeature(pickedColors: Uint8Array | undefined) {
@ -80,30 +85,20 @@ export class TilePickService implements ITilePickService{
}
/** 从瓦片中根据数据 */
getFeatureById(pickedFeatureIdx: number, lngLat: ILngLat) {
const tile = this.tileLayerService.getVisibleTileBylngLat(lngLat)
if (!tile) {
getFeatureById(pickedFeatureIdx: number) {
// 提取当前可见瓦片
const tiles = this.tileLayerService.getTiles().filter(tile => tile.visible);
// 提取当前可见瓦片中匹配 ID 的 feature 列表
const features: any[] = [];
tiles.map(tile => {
features.push(...tile.getFeatureById(pickedFeatureIdx));
})
if (features.length <= 0) {
return null;
}
const layers = tile.getLayers();
let features = null;
// 瓦片数据各自独立分布,没有完整的集合
// TODO: 合并瓦片矢量数据,返回完整的的数据集
layers.some(layer => {
// 图层的 originData 可能并没有 id因此我们使用编码后的 dataArray
const data = layer.getSource().data.dataArray;
// _id 编码值可能根据字段进行编码,因此可能命中多个 feature
const pickedFeature = data.filter(d => d._id === pickedFeatureIdx)
if(pickedFeature.length > 0) {
features = pickedFeature;
return true;
} else {
return false;
}
})
return features;
// 将 feature 列表合并后返回
// 统一返回成 polygon 的格式 点、线、面可以通用
return this.tileSourceService.getCombineFeature(features);
}
}

View File

@ -0,0 +1,26 @@
import { IParseDataItem } from '@antv/l7-core';
import * as turf from '@turf/helpers';
import union from '@turf/union';
/**
* Tile
*/
export class TileSourceService {
public getCombineFeature(features: IParseDataItem[]) {
let p: any = null;
const properties = features[0];
features.map((feature) => {
const polygon = turf.polygon(feature.coordinates);
if (p === null) {
p = polygon;
} else {
p = union(p, polygon);
}
});
if (properties) {
p.properties = { ...properties };
}
return p;
}
}

View File

@ -25,8 +25,7 @@ export default class MaskTile extends Tile {
const { sourceLayer, featureId } = this.parent.getLayerConfig<{
featureId: string;
}>();
const features = this.sourceTile.data.layers[sourceLayer as string]
.features;
const features = this.getFeatures(sourceLayer)
return {
data: {
type: 'FeatureCollection',

View File

@ -68,10 +68,25 @@ export default abstract class Tile implements ITile{
});
}
public getFeatures(sourceLayer: string | undefined){
if(!sourceLayer || !this.sourceTile.data?.layers[sourceLayer]) return [];
/**
* Tile layer
*/
public getMainLayer(): ILayer | undefined {
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++ ) {
@ -88,6 +103,19 @@ export default abstract class Tile implements ITile{
return features;
}
/**
* 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 destroy() {
this.layers.forEach((layer) => layer.destroy());
}

View File

@ -60,13 +60,7 @@ export default class VectorTile extends Tile {
const { sourceLayer = 'defaultLayer', featureId = 'id'} = this.parent.getLayerConfig<{
featureId: string;
}>();
const vectorLayer = this.sourceTile.data.layers[sourceLayer as string]
if(!vectorLayer) {
return false
}
const features = vectorLayer.features;
const features = this.getFeatures(sourceLayer)
return {
data: {
type: 'FeatureCollection',