Chore tile (#1417)

* fix: 拾取操作

* fix: 文件大小写

* fix: mask map async

* fix: remove cancleExtent

* fix: rm bottom color

* chore: tileLayer 创建机制
This commit is contained in:
@thinkinggis 2022-10-20 18:43:28 +08:00 committed by GitHub
parent 605ced75fe
commit c9a229c821
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 139 additions and 1268 deletions

View File

@ -3,8 +3,8 @@ import {
Scene,
Source,
PolygonLayer,
LineLayer,
TileDebugLayer,
// LineLayer,
// TileDebugLayer,
} from '@antv/l7';
// @ts-ignore
import { GaodeMap } from '@antv/l7-maps';
@ -76,22 +76,22 @@ 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';
// });
water_surface.on('click', (e) => {
console.log(e);
@ -101,9 +101,9 @@ export default () => {
console.log(water_surface);
});
scene.addLayer(water_surface);
scene.addLayer(line);
const debugerLayer = new TileDebugLayer();
scene.addLayer(debugerLayer);
// scene.addLayer(line);
// const debugerLayer = new TileDebugLayer();
// scene.addLayer(debugerLayer);
});
}, []);
return (

View File

@ -229,22 +229,13 @@ export interface ITilePickService {
}
export interface ITileLayerManager extends IBaseTileLayerManager{
tilePickService: ITilePickService;
pickLayers(target: IInteractionTarget): boolean;
destroy(): void;
}
export interface IBaseTileLayer {
sourceLayer: string;
parent: ILayer;
tileLayerManager: ITileLayerManager;
tilesetManager: TilesetManager | undefined;
pickRender(target: IInteractionTarget):void;
selectFeature(pickedColors: Uint8Array | undefined):void;
highlightPickedFeature(pickedColors: Uint8Array | undefined):void;
children: ILayer[];
scaleField: any;
render(isPicking?: boolean): void;
destroy(): void;
}
@ -368,8 +359,6 @@ export interface ILayer {
getAttribute(name: string): IStyleAttribute | undefined;
getLayerConfig<T>(): Partial<ILayerConfig & ISceneConfig & T>;
getLayerAttributeConfig():Partial<ILayerAttributesOption>
setBottomColor(color: string): void;
getBottomColor(): string;
getContainer(): Container;
setContainer(container: Container, sceneContainer: Container): void;
setCurrentPickId(id: number | null): void;

View File

@ -64,6 +64,7 @@ export type IJsonData = IJsonItem[];
export interface ISource {
inited: boolean;
isTile: boolean
data: IParserData;
center: [number, number];
parser: IParserCfg;

View File

@ -223,9 +223,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
private animateStatus: boolean = false;
// Tip: layer 保底颜色
private bottomColor = 'rgba(0, 0, 0, 0)';
private isDestroyed: boolean = false;
// private pickingPassRender: IPass<'pixelPicking'>;
@ -304,14 +301,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
return this.container;
}
public setBottomColor(color: string) {
this.bottomColor = color;
}
public getBottomColor() {
return this.bottomColor;
}
public addPlugin(plugin: ILayerPlugin): ILayer {
this.plugins.push(plugin);
return this;
@ -1312,6 +1301,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}>
throw new Error('Method not implemented.');
}
public async rebuildModels() {
console.log('2222');
await this.buildModels();
}

View File

@ -57,7 +57,6 @@ export default class DataMappingPlugin implements ILayerPlugin {
if (layer.layerModelNeedUpdate || !source || !source.inited) {
return;
}
const bottomColor = layer.getBottomColor();
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
const filter = styleAttributeService.getLayerStyleAttribute('filter');
const { dataArray } = source.data;
@ -70,7 +69,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
// 数据过滤完 再执行数据映射
if (filter?.needRemapping && filter?.scale) {
filterData = dataArray.filter((record: IParseDataItem) => {
return this.applyAttributeMapping(filter, record, bottomColor)[0];
return this.applyAttributeMapping(filter, record)[0];
});
}
@ -82,7 +81,6 @@ export default class DataMappingPlugin implements ILayerPlugin {
attributes,
filterData,
undefined,
bottomColor,
);
layer.setEncodedData(encodeData);
filter.needRemapping = false;
@ -92,7 +90,6 @@ export default class DataMappingPlugin implements ILayerPlugin {
attributesToRemapping,
filterData,
layer.getEncodedData(),
bottomColor,
);
layer.setEncodedData(encodeData);
}
@ -107,7 +104,6 @@ export default class DataMappingPlugin implements ILayerPlugin {
styleAttributeService,
}: { styleAttributeService: IStyleAttributeService },
) {
const bottomColor = layer.getBottomColor();
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
const filter = styleAttributeService.getLayerStyleAttribute('filter');
const { dataArray } = layer.getSource().data;
@ -115,7 +111,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
// 数据过滤完 再执行数据映射
if (filter?.scale) {
filterData = dataArray.filter((record: IParseDataItem) => {
return this.applyAttributeMapping(filter, record, bottomColor)[0];
return this.applyAttributeMapping(filter, record)[0];
});
}
// Tip: layer 对数据做处理
@ -123,13 +119,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
// 在各个 layer 中继承
filterData = layer.processData(filterData);
const encodeData = this.mapping(
layer,
attributes,
filterData,
undefined,
bottomColor,
);
const encodeData = this.mapping(layer, attributes, filterData, undefined);
layer.setEncodedData(encodeData);
// 对外暴露事件
layer.emit('dataUpdate', null);

View File

@ -1,6 +1,7 @@
import { ILayer, ILayerPlugin } from '@antv/l7-core';
import { injectable } from 'inversify';
import 'reflect-metadata';
import TileLayer from '../tile/tileLayer/BaseLayer';
/**
* Layer Model
*/
@ -25,6 +26,10 @@ export default class LayerModelPlugin implements ILayerPlugin {
public apply(layer: ILayer) {
layer.hooks.init.tapPromise('LayerModelPlugin', async () => {
if (layer.getSource().isTile) {
layer.tileLayer = new TileLayer(layer);
return;
}
await this.initLayerModel(layer);
});
@ -32,8 +37,13 @@ export default class LayerModelPlugin implements ILayerPlugin {
'LayerModelPlugin',
async (flag: boolean) => {
if (!flag) {
// TileLayer 不需要rebuilder
return false;
}
if (layer.getSource().isTile) {
layer.tileLayer = new TileLayer(layer);
return;
}
await this.prepareLayerModel(layer);
},
);

View File

@ -1,10 +1,10 @@
import TileModel from '../../tile/models/tileModel';
import LineModel from '../../line/models/line';
import PointExtrudeModel from '../../point/models/extrude';
import PointFillModel from '../../point/models/fill';
import IMageModel from '../../point/models/image';
import NormalModel from '../../point/models/normal';
import TextModel from '../../point/models/text';
import PolygonTileModel from '../../tile/models/tileModel';
import ExtrudeModel from './extrude';
import FillModel from './fill';
import Ocean from './ocean';
@ -24,8 +24,8 @@ export type PolygonModelType =
| 'ocean'
| 'vectorpolygon'
| 'tile';
const PolygonModels: { [key in PolygonModelType]: any } = {
vectorpolygon: TileModel,
fill: FillModel,
line: LineModel,
extrude: ExtrudeModel,
@ -37,7 +37,7 @@ const PolygonModels: { [key in PolygonModelType]: any } = {
water: Water,
ocean: Ocean,
// point_fill: PointModels.fill,
vectorpolygon: PolygonTileModel,
tile: TilePolygonModel,
};
export default PolygonModels;

View File

@ -1,233 +0,0 @@
import {
IInteractionTarget,
ILayer,
IMapService,
IPickingService,
IRendererService,
ISubLayerInitOptions,
ITileLayerManager,
ITilePickService,
ITileRenderService,
ITransform,
ScaleAttributeType,
} from '@antv/l7-core';
import { Base } from './base';
import { generateColorRamp, IColorRamp } from '@antv/l7-utils';
import { getLayerShape, getMaskValue } from '../utils';
import { TileStyleService, ITileStyleService } from '../style/TileStyleService';
import { TilePickService } from '../interaction/TilePickService';
import { TileRenderService } from '../render/TileRenderService';
import { styles, IStyles, Attributes } from '../style/constants';
import { updateTexture, updateLayersConfig, setStyleAttributeField } from '../style/utils';
export class TileLayerManager extends Base implements ITileLayerManager {
public tilePickService: ITilePickService;
public tileStyleService: ITileStyleService;
public tileRenderService: ITileRenderService
private transforms: ITransform[];
constructor(
parent: ILayer,
mapService: IMapService,
rendererService: IRendererService,
pickingService: IPickingService,
transforms: ITransform[]
) {
super();
this.parent = parent;
this.children = parent.layerChildren;
this.mapService = mapService;
this.rendererService = rendererService;
this.transforms = transforms;
this.tileRenderService = new TileRenderService(rendererService);
this.tilePickService = new TilePickService(
parent,
rendererService,
pickingService,
this.children,
this.tileRenderService
);
this.tileStyleService = new TileStyleService();
this.setSubLayerInitOption();
this.setConfigListener();
this.initTileFactory();
}
public render(): void {
this.tileStyleService.checkConfig(this.parent);
this.tileRenderService.render(this.children);
}
public pickLayers(target: IInteractionTarget) {
return this.tilePickService.pick(this.children, target);
}
private setSubLayerInitOption() {
const {
zIndex = 0,
opacity = 1,
mask = false,
stroke = '#fff',
strokeWidth = 0,
strokeOpacity = 1,
clampLow = true,
clampHigh = true,
domain = [0, 1],
rampColors = {
colors: [
'rgb(166,97,26)',
'rgb(223,194,125)',
'rgb(245,245,245)',
'rgb(128,205,193)',
'rgb(1,133,113)',
],
positions: [0, 0.25, 0.5, 0.75, 1.0],
},
featureId = 'id',
workerEnabled = false,
sourceLayer,
pixelConstant = 0,
pixelConstantR = 256 * 256,
pixelConstantG = 256,
pixelConstantB = 1,
pixelConstantRGB = 0.1,
visible,
} = this.parent.getLayerConfig() as ISubLayerInitOptions;
const colorValue = this.tileStyleService.getAttributeScale(
this.parent,
'color',
);
const sizeValue = this.tileStyleService.getAttributeScale(
this.parent,
'size',
);
const source = this.parent.getSource();
const { coords } = source?.data?.tilesetOptions || {};
const parentParserType = source.getParserType();
const layerShape = getLayerShape(this.parent.type, this.parent);
this.initOptions = {
visible,
layerType: this.parent.type,
transforms: this.transforms,
shape: layerShape,
zIndex,
opacity,
sourceLayer: this.getSourceLayer(parentParserType, sourceLayer),
coords,
featureId,
color: colorValue,
size: sizeValue,
mask: getMaskValue(this.parent.type, mask),
stroke,
strokeWidth,
strokeOpacity,
// raster tiff
clampLow,
clampHigh,
domain,
rampColors,
// worker
workerEnabled,
pixelConstant,
pixelConstantR,
pixelConstantG,
pixelConstantB,
pixelConstantRGB,
};
if (rampColors) {
// 构建统一的色带贴图
const { createTexture2D } = this.rendererService;
const imageData = generateColorRamp(rampColors as IColorRamp) as ImageData;
const colorTexture = createTexture2D({
data: imageData.data,
width: imageData.width,
height: imageData.height,
flipY: false,
});
this.initOptions.colorTexture = colorTexture;
}
}
private getInitOptionValue(field: string) {
switch(field) {
case 'color': return this.parent.getAttribute('color')?.scale;
case 'shape': return this.parent.getAttribute('shape')?.scale;
case 'size': return this.parent.getAttribute('size')?.scale;
// @ts-ignore
default: return this.initOptions[field];
}
}
private setInitOptionValue(field: string, value: any) {
// @ts-ignore
this.initOptions[field] = value;
}
private setConfigListener() {
const styleConfigs = styles[this.parent.type as IStyles] || [];
styleConfigs.map(style => {
this.tileStyleService.setConfig(style, this.getInitOptionValue(style));
})
this.tileStyleService.on('updateConfig', (updateConfigs) => {
updateConfigs.map((key: string) => {
return this.updateStyle(key);
});
});
}
private updateAttribute(style: string) {
if(Attributes.includes(style)) {
const scaleValue = this.parent.getAttribute(style)?.scale;
if (!scaleValue) {
return;
}
this.children.map((child) => {
return setStyleAttributeField(
child,
this.parent,
style as ScaleAttributeType,
scaleValue,
);
});
}
}
private updateStyle(style: string) {
let updateValue = null;
if (Attributes.includes(style)) {
this.updateAttribute(style);
} else {
const layerConfig = this.parent.getLayerConfig() as ISubLayerInitOptions;
if (!(style in layerConfig)) {
return;
}
// @ts-ignore
const config = layerConfig[style];
updateValue = config;
switch(style) {
case 'rampColors':
const texture = updateTexture(config, this.children, this.rendererService)
this.initOptions.colorTexture = texture;
break;
default:
updateLayersConfig(this.children, style, config);
}
}
this.setInitOptionValue(style, updateValue);
}
public destroy(): void {
this.tilePickService.destroy();
}
}

View File

@ -1,7 +1,7 @@
import { IModelUniform, ITexture2D, IRendererService } from '@antv/l7-core';
import BaseModel from '../../core/BaseModel';
import { TileLayer } from '../tileLayer/TileLayer';
import { MapTileLayer } from '../tileLayer/MapTileLayer';
import TileLayer from '../tileLayer/BaseLayer';
// import { MapTileLayer } from '../tileLayer/MapTileLayer';
import { IColorRamp, generateColorRamp } from '@antv/l7-utils';
interface ITileLayerStyleOptions {
rampColors?: IColorRamp;
@ -12,29 +12,16 @@ export default class TileModel extends BaseModel {
return {};
}
private getTileLayer(usage?: string) {
switch(usage) {
case 'basemap':
return MapTileLayer;
default:
return TileLayer;
}
private getTileLayer() {
return TileLayer;
}
public initModels() {
const source = this.layer.getSource();
this.initTileResource();
const { usage } = this.layer.getLayerConfig();
if (source?.data.isTile && !this.layer.tileLayer) {
const tileLayer = this.getTileLayer(usage);
this.layer.tileLayer = new tileLayer({
parent: this.layer,
rendererService: this.rendererService,
mapService: this.mapService,
layerService: this.layerService,
pickingService: this.pickingService,
transforms: source.transforms,
});
const tileLayer = this.getTileLayer();
this.layer.tileLayer = new tileLayer(this.layer);
}
return this.buildModels();

View File

@ -1,8 +1,6 @@
import {
ILayer,
IRendererService,
ScaleAttributeType,
IScaleValue
} from '@antv/l7-core';
import { generateColorRamp, IColorRamp } from '@antv/l7-utils';
@ -40,34 +38,6 @@ export function updateLayersConfig(layers: ILayer[], key: string, value: any) {
});
}
export function setStyleAttributeField(
layer: ILayer,
parent: ILayer,
style: ScaleAttributeType,
value: IScaleValue | undefined | string | string[],
) {
if (Array.isArray(value)) {
// @ts-ignore
layer[style](...value);
return;
}
if (typeof value === 'string') {
layer[style](value);
return;
}
const defaultValue = getDefaultStyleAttributeField(layer, parent.type, style);
if (!value) {
layer[style](defaultValue);
return layer;
}
const params = parseScaleValue(value, style);
if (params.length === 0) {
layer[style](defaultValue);
} else {
// @ts-ignore
layer[style](...params);
}
}
export function getDefaultStyleAttributeField(layer: ILayer, type: string, style: string) {
switch (style) {
@ -104,31 +74,3 @@ export function getLayerShape(layerType: string, layer: ILayer) {
}
}
export function parseScaleValue(value: IScaleValue | string, type: string) {
if (type === 'shape') {
if (typeof value === 'string') {
return [value];
} else if (value?.field) {
return [value?.field];
} else {
return [];
}
}
const { field, values, callback } = value as IScaleValue;
if (field && values && Array.isArray(values)) {
return [field, values];
} else if (field && callback) {
return [field, callback];
} else if (field) {
return [field];
}
return [];
}
export function setScale(layer: ILayer, parent: ILayer) {
const scaleOptions = parent.tileLayer.scaleField;
const scaleKeys = Object.keys(scaleOptions);
scaleKeys.map((key) => {
layer.scale(key, scaleOptions[key]);
});
}

View File

@ -12,7 +12,6 @@ export default class DebugTile extends Tile {
.size(1)
.shape('line')
.color('red');
console.log(lineLayer)
const pointLayer = new PointLayer()
.source([pointData],{
parser: {

View File

@ -9,8 +9,13 @@ export default class VectorTile extends Tile {
const vectorLayer = getTileLayer(this.parent.type);
const maskLayer = getMaskLayer(this.parent.type);
layerOptions.mask = !!maskLayer;
const sourceOptions = this.getSourceOption();
if(!sourceOptions){
this.isLoaded = true;
return
}
const layer = new vectorLayer({...layerOptions}).source(
sourceOptions.data,
sourceOptions.options,
@ -42,14 +47,22 @@ export default class VectorTile extends Tile {
await this.addLayer(layer);
this.isLoaded = true;
}
// Todo 校验数据有效性
protected beforeInit() {
}
protected getSourceOption() {
const rawSource = this.parent.getSource();
const { sourceLayer, featureId } = this.parent.getLayerConfig<{
featureId: string;
}>();
const features = this.sourceTile.data.layers[sourceLayer as string]
.features;
const vectorLayer = this.sourceTile.data.layers[sourceLayer as string]
if(!vectorLayer) {
return false
}
const features = vectorLayer.features;
return {
data: {
type: 'FeatureCollection',

View File

@ -1,381 +0,0 @@
import {
ILayer,
IMapService,
IParseDataItem,
IRendererService,
ISubLayerInitOptions,
} from '@antv/l7-core';
import Source from '@antv/l7-source';
import { SourceTile, TilesetManager } from '@antv/l7-utils';
import { setStyleAttributeField, setScale } from '../style/utils';
import { registerLayers } from '../utils';
import { readRasterValue } from '../interaction/getRasterData';
import VectorLayer from './layers/vectorLayer';
import * as turf from '@turf/helpers';
import union from '@turf/union';
import clone from '@turf/clone';
import polygonToLineString from '@turf/polygon-to-line';
import {
CacheEvent,
ILayerTileConfig,
ITileFactory,
ITileFactoryOptions,
ITileStyles,
Timeout,
} from '../interface';
type IEvent = { lngLat: {lng: number, lat: number}, x: number, y: number, value: any};
const EMPTY_FEATURE_DATA = {
features: [],
featureId: null,
vectorTileLayer: null,
source: null,
};
export default class TileFactory implements ITileFactory {
public type: string;
public parentLayer: ILayer;
public mapService: IMapService;
public rendererService: IRendererService;
public outSideEventTimer: Timeout | null = null;
protected zoomOffset: number;
protected tilesetManager: TilesetManager;
public layers: ILayer[];
public loaded: false;
// 用于记录图层内事件,辅助判断图层外事件逻辑
private eventCache = {
click: 0,
mousemove: 0,
mouseup: 0,
mousedown: 0,
contextmenu: 0,
};
constructor(option: ITileFactoryOptions) {
this.parentLayer = option.parent;
this.mapService = option.mapService;
this.rendererService = option.rendererService;
const source = this.parentLayer.getSource();
this.zoomOffset = source.parser.zoomOffset || 0;
this.tilesetManager = source.tileset as TilesetManager;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public createTile(tile: SourceTile, initOptions: ISubLayerInitOptions) {
return {
layers: [] as ILayer[]
};
}
public getFeatureData(tile: SourceTile, initOptions: ISubLayerInitOptions) {
const { sourceLayer, featureId, transforms = [], layerType, shape } = initOptions;
if (!sourceLayer) {
return EMPTY_FEATURE_DATA;
}
const vectorTileLayer = tile.data.layers[sourceLayer];
const features = vectorTileLayer?.features;
if (!(Array.isArray(features) && features.length > 0)) {
return EMPTY_FEATURE_DATA;
} else {
let geofeatures = [];
if(layerType === 'LineLayer' && shape === 'simple') {
features.map(feature => {
const cloneFeature = clone(feature);
if(cloneFeature.geometry.type === 'MultiPolygon') {
// @ts-ignore
const linefeatures = polygonToLineString(cloneFeature).features
geofeatures.push(...linefeatures)
} else if(cloneFeature.geometry.type === 'Polygon') {
cloneFeature.geometry.type = 'MultiLineString'
geofeatures.push(cloneFeature);
} else {
geofeatures.push(cloneFeature);
}
})
} else {
geofeatures = features;
}
const source = new Source(
{
type: 'FeatureCollection',
features: geofeatures,
},
{
parser: {
type: 'geojson',
featureId,
cancelExtent: true
},
transforms
},
);
return {
features: geofeatures,
featureId,
vectorTileLayer,
source,
};
}
}
public createLayer(tileLayerOption: ILayerTileConfig) {
const {
L7Layer,
tile,
initOptions,
vectorTileLayer,
source,
needListen = true,
} = tileLayerOption;
const { mask, color, layerType, size, shape, usage, basemapColor, basemapSize } = initOptions;
const FactoryTileLayer = L7Layer ? L7Layer : VectorLayer;
const layer = new FactoryTileLayer({
tileOrigin: vectorTileLayer?.l7TileOrigin,
coord: vectorTileLayer?.l7TileCoord,
needListen,
...this.getLayerInitOption(initOptions),
visible: tile.isVisible,
});
if(layerType) layer.type = layerType;
// Tip: sign tile layer
layer.isTileLayer = true; // vector 、raster
// vector layer set event
if (layer.isVector && usage !== 'basemap') {
this.emitEvent([layer]);
layer.select(true);
}
// set source
layer.source(source);
// set scale attribute field
setStyleAttributeField(layer, this.parentLayer, 'shape', shape);
if(usage !== 'basemap') {
// set scale
setScale(layer, this.parentLayer);
setStyleAttributeField(layer, this.parentLayer, 'color', color);
setStyleAttributeField(layer, this.parentLayer, 'size', size);
} else {
layer.style({
color: basemapColor,
size: basemapSize
})
}
// set mask
if (mask && layer.isVector) {
const masklayer = new VectorLayer({layerType: "MaskLayer"})
.source({
type: 'FeatureCollection',
features: [tile.bboxPolygon],
}, {
parser: {
type: 'geojson',
cancelExtent: true
}
});
registerLayers(this.parentLayer, [masklayer]);
layer.addMaskLayer(masklayer);
}
this.layers = [layer];
return layer;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public updateStyle(styles: ITileStyles) {
return '';
}
protected getTile(lng: number, lat: number) {
const zoom = this.mapService.getZoom();
return this.tilesetManager.getTileByLngLat(lng, lat, zoom);
}
private bindVectorEvent(layer: ILayer) {
layer.on('click', (e) => {
this.eventCache.click = 1;
this.getFeatureAndEmitEvent('subLayerClick', e);
});
layer.on('mousemove', (e) => {
this.eventCache.mousemove = 1;
this.getFeatureAndEmitEvent('subLayerMouseMove', e);
});
layer.on('mouseenter', (e) => {
this.getFeatureAndEmitEvent('subLayerMouseEnter', e);
});
}
private readRasterTile(e: IEvent, name: string) {
const { lng, lat } = e.lngLat;
const tile = this.getTile(lng, lat);
if(!tile) return;
const data = readRasterValue(tile, this.mapService, e.x, e.y);
e.value = data;
this.parentLayer.emit(name, e);
}
private bindRasterEvent(layer: ILayer) {
layer.on('click', (e) => {
this.eventCache.click = 1;
this.readRasterTile(e, 'subLayerClick');
});
layer.on('mousemove', (e) => {
this.eventCache.mousemove = 1;
this.readRasterTile(e, 'subLayerMouseMove');
});
layer.on('mouseenter', (e) => {
this.readRasterTile(e, 'subLayerMouseMove');
});
}
private bindCommonEvent(layer: ILayer) {
layer.on('mouseup', (e) => {
this.eventCache.mouseup = 1;
this.getFeatureAndEmitEvent('subLayerMouseUp', e);
});
layer.on('mouseout', (e) => {
this.getFeatureAndEmitEvent('subLayerMouseOut', e);
});
layer.on('mousedown', (e) => {
this.eventCache.mousedown = 1;
this.getFeatureAndEmitEvent('subLayerMouseDown', e);
});
layer.on('contextmenu', (e) => {
this.eventCache.contextmenu = 1;
this.getFeatureAndEmitEvent('subLayerContextmenu', e);
});
// out side
layer.on('unclick', (e) =>
this.handleOutsideEvent('click', 'subLayerUnClick', layer, e),
);
layer.on('unmouseup', (e) =>
this.handleOutsideEvent('mouseup', 'subLayerUnMouseUp', layer, e),
);
layer.on('unmousedown', (e) =>
this.handleOutsideEvent('mousedown', 'subLayerUnMouseDown', layer, e),
);
layer.on('uncontextmenu', (e) =>
this.handleOutsideEvent(
'contextmenu',
'subLayerUnContextmenu',
layer,
e,
),
);
}
protected emitEvent(layers: ILayer[]) {
layers.map((layer) => {
layer.once('inited', () => {
this.bindVectorEvent(layer);
this.bindCommonEvent(layer);
});
});
}
protected emitRasterEvent(layers: ILayer[]) {
layers.map((layer) => {
layer.once('inited', () => {
this.bindRasterEvent(layer);
this.bindCommonEvent(layer);
});
});
}
protected 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;
}
{
p = union(p, polygon);
}
});
if (properties) {
p.properties = { ...properties };
}
return p;
}
protected getFeatureAndEmitEvent(
eventName: string,
e: any,
) {
const featureId = e.featureId;
const features = this.getAllFeatures(featureId);
try {
e.feature = this.getCombineFeature(features);
} catch (err) {
console.warn('Combine Featuer Err! Return First Feature!');
e.feature = features[0];
}
this.parentLayer.emit(eventName, e);
}
private getAllFeatures(featureId: number) {
const allLayers: ILayer[] = this.parentLayer.tileLayer.children;
const features: IParseDataItem[] = [];
allLayers.map((layer) => {
const source = layer.getSource();
source.data.dataArray.map((feature) => {
if (feature._id === featureId) {
features.push(feature);
}
});
});
return features;
}
private getLayerInitOption(initOptions: ISubLayerInitOptions) {
const option = { ...initOptions };
delete option.color;
delete option.shape;
delete option.size;
delete option.coords;
delete option.sourceLayer;
delete option.coords;
return option;
}
private handleOutsideEvent(
type: CacheEvent,
emitType: string,
layer: ILayer,
e: any,
) {
if (this.outSideEventTimer) {
clearTimeout(this.outSideEventTimer);
this.outSideEventTimer = null;
}
this.outSideEventTimer = setTimeout(() => {
if (this.eventCache[type] > 0) {
this.eventCache[type] = 0;
} else {
this.getFeatureAndEmitEvent(emitType, e);
}
}, 64);
}
}

View File

@ -1,72 +0,0 @@
import { ILayer, ISubLayerInitOptions } from '@antv/l7-core';
import { SourceTile } from '@antv/l7-utils';
import { ITileFactoryOptions } from '../interface';
import TileFactory from './base';
import VectorLayer from './layers/vectorLayer';
export default class TestTile extends TileFactory {
public parentLayer: ILayer;
constructor(option: ITileFactoryOptions) {
super(option);
this.parentLayer = option.parent;
}
public createTile(tile: SourceTile, initOptions: ISubLayerInitOptions) {
const { sourceLayer } = initOptions;
if (!sourceLayer) {
return {
layers: [],
};
}
const vectorTileLayer = tile.data.layers[sourceLayer];
const features = vectorTileLayer?.features;
if (features.length === 0) {
return {
layers: [],
};
}
const properties = features[0].properties;
const text = new VectorLayer({
layerType: 'PointLayer',
minZoom: tile.z -1,
maxZoom: tile.z +1,
usage: 'basemap',
needListen: false
})
.source([properties], {
parser: {
type: 'json',
x: 'textLng',
y: 'textLat',
}
})
.shape(`${tile.x}/${tile.y}/${tile.z}`)
.style({
size: 20,
color: '#000',
stroke: '#fff',
strokeWidth: 2
});
const line = new VectorLayer({ layerType: 'LineLayer', usage: 'basemap', needListen: false })
.source({
type: 'FeatureCollection',
features: features,
}, {
parser: {
type: 'geojson',
}
})
.shape('simple')
.style({
color: '#f00'
});
return {
layers: [line,text],
};
}
}

View File

@ -1,36 +0,0 @@
import { ILayer, ISubLayerInitOptions } from '@antv/l7-core';
import Source from '@antv/l7-source';
import { SourceTile } from '@antv/l7-utils';
import { ITileFactoryOptions } from '../interface';
import TileFactory from './base';
export default class VectorMaskTile extends TileFactory {
public parentLayer: ILayer;
constructor(option: ITileFactoryOptions) {
super(option);
this.parentLayer = option.parent;
}
public createTile(tile: SourceTile, initOptions: ISubLayerInitOptions) {
const { features, vectorTileLayer, source } = this.getFeatureData(
tile,
initOptions,
);
if (features.length === 0) {
return {
layers: [],
};
}
const layer = this.createLayer({
tile,
initOptions,
vectorTileLayer,
source: source as Source,
needListen: false
});
return {
layers: [layer],
};
}
}

View File

@ -1,33 +0,0 @@
import { ILayer, ISubLayerInitOptions } from '@antv/l7-core';
import Source from '@antv/l7-source';
import { SourceTile } from '@antv/l7-utils';
import ImageLayer from '../../image';
import { ITileFactoryOptions } from '../interface';
import TileFactory from './base';
export default class RasterTile extends TileFactory {
public parentLayer: ILayer;
constructor(option: ITileFactoryOptions) {
super(option);
this.parentLayer = option.parent;
}
public createTile(tile: SourceTile, initOptions: ISubLayerInitOptions) {
const source = new Source(tile.data, {
parser: {
type: 'image',
extent: tile.bounds,
},
});
const layer = this.createLayer({
L7Layer: ImageLayer,
tile,
initOptions,
source,
});
return {
layers: [layer],
};
}
}

View File

@ -1,57 +0,0 @@
import { ILayer, ISubLayerInitOptions } from '@antv/l7-core';
import { SourceTile } from '@antv/l7-utils';
import { ITileFactoryOptions } from '../interface';
import TileFactory from './base';
import RasterDataLayer from './layers/rasterDataLayer';
export default class RasterTiffTile extends TileFactory {
public parentLayer: ILayer;
constructor(option: ITileFactoryOptions) {
super(option);
this.parentLayer = option.parent;
}
public createTile(tile: SourceTile, initOptions: ISubLayerInitOptions) {
const {
colorTexture,
opacity,
domain,
clampHigh,
clampLow,
mask,
} = initOptions;
const rasterData = tile.data;
if (!rasterData.data) {
console.warn('raster data not exist!');
return {
layers: [],
};
}
const dataType = this.parentLayer?.getSource()?.parser?.dataType;
const layer = new RasterDataLayer({
visible: tile.isVisible,
mask,
})
.source(rasterData.data, {
parser: {
// 数据栅格分为单通道栅格和多通道彩色栅格
type: dataType === 'rgb' ? 'rasterRgb': 'raster',
width: rasterData.width,
height: rasterData.height,
extent: tile.bboxPolygon.bbox,
},
})
.style({
colorTexture,
opacity,
domain,
clampHigh,
clampLow,
});
this.emitRasterEvent([layer]);
return {
layers: [layer],
};
}
}

View File

@ -1,35 +0,0 @@
import { ILayer, ISubLayerInitOptions } from '@antv/l7-core';
import Source from '@antv/l7-source';
import { SourceTile } from '@antv/l7-utils';
import { ITileFactoryOptions } from '../interface';
import TileFactory from './base';
export default class VectorTile extends TileFactory {
public parentLayer: ILayer;
constructor(option: ITileFactoryOptions) {
super(option);
this.parentLayer = option.parent;
}
public createTile(tile: SourceTile, initOptions: ISubLayerInitOptions) {
const { features, vectorTileLayer, source } = this.getFeatureData(
tile,
initOptions,
);
if (features.length === 0) {
return {
layers: [],
};
}
const layer = this.createLayer({
tile,
initOptions,
vectorTileLayer,
source: source as Source,
});
return {
layers: [layer],
};
}
}

View File

@ -1,32 +1,75 @@
import { ILayer, IMapService, ILayerService, ISource,IInteractionTarget } from '@antv/l7-core';
import {
ILayer,
IMapService,
ILayerService,
IRendererService,
TYPES,
ISource,
IPickingService,
IInteractionTarget
} from '@antv/l7-core';
import { SourceTile, TilesetManager } from '@antv/l7-utils';
import { debounce } from 'lodash';
import { TileLayerService } from '../service/TileLayerService';
import { TilePickService } from '../service/TilePickService';
import { debounce } from 'lodash';
import { getTileFactory } from '../tileFactory'
export class Base {
public tileLayerManager: any;
export default class BaseTileLayer {
private parent: ILayer;
public tileLayerService: TileLayerService;
public get children() {
return this.tileLayerManager.children;
}
public sourceLayer: string;
public parent: ILayer;
public initedTileset: boolean = false; // 瓦片是否加载成功
public tilesetManager: TilesetManager | undefined; // 瓦片数据管理器
public scaleField: any;
protected mapService: IMapService;
protected layerService: ILayerService;
protected tilePickService: TilePickService
protected rendererService: IRendererService;
protected pickingService:IPickingService;
protected tilePickService: TilePickService;
public tilesetManager: TilesetManager; // 瓦片数据管理器
public initedTileset: boolean = false; // 瓦片是否加载成功
protected lastViewStates: {
zoom: number;
latLonBounds: [number, number, number, number];
};
constructor(parent: ILayer) {
this.parent = parent;
const container = this.parent.getContainer();
this.rendererService = container.get<IRendererService>(
TYPES.IRendererService,
);
this.layerService = container.get<ILayerService>(TYPES.ILayerService);
this.mapService = container.get<IMapService>(TYPES.IMapService);
this.pickingService = container.get<IPickingService>(
TYPES.IPickingService,
);
// 初始化瓦片管理服务
this.tileLayerService = new TileLayerService({
rendererService: this.rendererService,
layerService:this.layerService,
parent
})
// 初始化拾取服务
this.tilePickService = new TilePickService({
tileLayerService: this.tileLayerService,
layerService:this.layerService,
})
this.initTileSetManager();
}
protected initTileSetManager() {
const source: ISource = this.parent.getSource();
this.tilesetManager = source.tileset as TilesetManager;
if (!this.initedTileset) {
this.bindTilesetEvent();
this.initedTileset = true;
}
const { latLonBounds, zoom } = this.getCurrentView();
this.tilesetManager?.update(zoom, latLonBounds);
}
protected mapchange() {
const { latLonBounds, zoom } = this.getCurrentView();
@ -52,7 +95,6 @@ export class Base {
this.tilesetManager?.throttleUpdate(zoom, latLonBounds);
}
protected getCurrentView() {
const bounds = this.mapService.getBounds();
const latLonBounds: [number, number, number, number] = [
@ -66,23 +108,7 @@ export class Base {
return { latLonBounds, zoom };
}
protected initTileSetManager() {
const source: ISource = this.parent.getSource();
this.tilesetManager = source.tileset as TilesetManager;
if (!this.initedTileset) {
this.bindTilesetEvent();
this.initedTileset = true;
}
const { latLonBounds, zoom } = this.getCurrentView();
this.tilesetManager?.update(zoom, latLonBounds);
}
private bindTilesetEvent() {
if (!this.tilesetManager) {
return;
}
// 瓦片数据加载成功
// eslint-disable-next-line @typescript-eslint/no-unused-vars
this.tilesetManager.on('tile-loaded', (tile: SourceTile) => {
@ -111,7 +137,7 @@ export class Base {
this.mapService.on('zoomend', () => this.mapchange());
this.mapService.on('moveend', () => this.viewchange());
}
public render() {
this.tileLayerService.render();
}
@ -150,6 +176,10 @@ export class Base {
const tileInstance = getTileFactory(this.parent);
const tileLayer = new tileInstance(tile, this.parent);
await tileLayer.initTileLayer();
if(tileLayer.getLayers().length!==0) {
this.tileLayerService.addTile(tileLayer);
this.layerService.reRender()
}
this.tileLayerService.addTile(tileLayer);
this.layerService.reRender()
} else {
@ -166,14 +196,15 @@ export class Base {
}
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;
}
}
// 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;
}

View File

@ -1,36 +0,0 @@
import {
IBaseTileLayer,
ITileLayerOPtions,
// IBaseTileLayerManager,
} from '@antv/l7-core';
import { BaseMapTileLayerManager } from '../manager/mapLayerManager';
import { Base } from './base';
export class MapTileLayer extends Base implements IBaseTileLayer {
// public tileLayerManager: IBaseTileLayerManager;
constructor({
parent,
rendererService,
mapService,
layerService,
}: ITileLayerOPtions) {
super();
const parentSource = parent.getSource();
const { sourceLayer } =
parentSource?.data?.tilesetOptions || {};
this.sourceLayer = sourceLayer;
this.parent = parent;
this.mapService = mapService;
this.layerService = layerService;
this.tileLayerManager = new BaseMapTileLayerManager(
parent,
mapService,
rendererService,
);
this.initTileSetManager();
}
}

View File

@ -1,185 +0,0 @@
import {
IInteractionTarget,
ILayer,
ITileLayer,
ITileLayerManager,
ITileLayerOPtions,
} from '@antv/l7-core';
import { TileLayerService } from '../service/TileLayerService';
import { TilePickService } from '../service/TilePickService'
import { Base } from './base';
import { setSelect, setHighlight, setPickState, clearPickState } from '../interaction/utils';
export class TileLayer extends Base implements ITileLayer {
public get children() {
return this.tileLayerManager.children;
}
public tileLayerManager: ITileLayerManager;
public tilePickService:TilePickService;
private pickColors: {
select: any;
active: any;
} = {
select: null,
active: null,
};
constructor({
parent,
rendererService,
mapService,
layerService,
}: ITileLayerOPtions) {
super();
this.sourceLayer = parent.getLayerConfig()?.sourceLayer as string;
this.parent = parent;
this.mapService = mapService;
this.layerService = layerService;
// 初始化瓦片管理服务
this.tileLayerService = new TileLayerService({
rendererService,
layerService,
parent
})
// 初始化拾取服务
this.tilePickService = new TilePickService({
tileLayerService: this.tileLayerService,
layerService,
})
// this.tileLayerManager = new TileLayerManager(
// parent,
// mapService,
// rendererService,
// pickingService,
// transforms
// );
this.initTileSetManager();
// this.bindSubLayerEvent();
// this.bindSubLayerPick();
// this.scaleField = this.parent.getScaleOptions();
}
public clearPick(type: string) {
// Tip: 瓦片只有在 mousemove 的时候需要设置清除
if (type === 'mousemove') {
this.tileLayerManager.tilePickService.clearPick();
}
}
/**
* select
*/
public clearPickState() {
clearPickState(this.children)
}
/**
*
* @param target
* @returns
*/
public pickLayers(target: IInteractionTarget) {
return this.tileLayerManager.pickLayers(target);
}
public setPickState(layers: ILayer[]) {
setPickState(layers, this.pickColors);
}
private bindSubLayerPick() {
this.tileLayerManager.tilePickService.on('pick', (e) => {
// @ts-ignore
const [r, g, b] = e.pickedColors;
if (e.type === 'click') {
const restLayers = this.children
.filter(
(child) => child.inited && child.isVisible() && child.isVector,
)
.filter((child) => child !== e.layer);
const renderList = this.layerService.getRenderList();
const color = setSelect(restLayers, [r, g, b], renderList)
this.pickColors.select = color;
} else {
setHighlight(this.children, [r, g, b]);
this.pickColors.active = [r, g, b];
}
});
this.tileLayerManager.tilePickService.on('unpick', () => {
this.pickColors.active = null;
});
}
protected bindSubLayerEvent() {
/**
* layer.on('click', (ev) => {}); // 鼠标左键点击图层事件
* layer.on('mouseenter', (ev) => {}); // 鼠标进入图层要素
* layer.on('mousemove', (ev) => {}); // 鼠标在图层上移动时触发
* layer.on('mouseout', (ev) => {}); // 鼠标移出图层要素时触发
* layer.on('mouseup', (ev) => {}); // 鼠标在图层上单击抬起时触发
* layer.on('mousedown', (ev) => {}); // 鼠标在图层上单击按下时触发
* layer.on('contextmenu', (ev) => {}); // 图层要素点击右键菜单
*
*
* layer.on('unclick', (ev) => {}); // 图层外点击
* layer.on('unmousemove', (ev) => {}); // 图层外移动
* layer.on('unmouseup', (ev) => {}); // 图层外鼠标抬起
* layer.on('unmousedown', (ev) => {}); // 图层外单击按下时触发
* layer.on('uncontextmenu', (ev) => {}); // 图层外点击右键
* layer.on('unpick', (ev) => {}); // 图层外的操作的所有事件
*/
this.parent.on('subLayerClick', (e) => {
this.parent.emit('click', { ...e });
});
this.parent.on('subLayerMouseMove', (e) =>
this.parent.emit('mousemove', { ...e }),
);
this.parent.on('subLayerMouseUp', (e) =>
this.parent.emit('mouseup', { ...e }),
);
this.parent.on('subLayerMouseEnter', (e) =>
this.parent.emit('mouseenter', { ...e }),
);
this.parent.on('subLayerMouseOut', (e) =>
this.parent.emit('mouseout', { ...e }),
);
this.parent.on('subLayerMouseDown', (e) =>
this.parent.emit('mousedown', { ...e }),
);
this.parent.on('subLayerContextmenu', (e) =>
this.parent.emit('contextmenu', { ...e }),
);
// vector layer 图层外事件
this.parent.on('subLayerUnClick', (e) =>
this.parent.emit('unclick', { ...e }),
);
this.parent.on('subLayerUnMouseMove', (e) =>
this.parent.emit('unmousemove', { ...e }),
);
this.parent.on('subLayerUnMouseUp', (e) =>
this.parent.emit('unmouseup', { ...e }),
);
this.parent.on('subLayerUnMouseDown', (e) =>
this.parent.emit('unmousedown', { ...e }),
);
this.parent.on('subLayerUnContextmenu', (e) =>
this.parent.emit('uncontextmenu', { ...e }),
);
}
}

View File

@ -11,7 +11,7 @@ import {
} from '@antv/l7-core';
import { Version } from '@antv/l7-maps';
import Source from '@antv/l7-source';
import { isColor, normalize, rgb2arr } from '@antv/l7-utils';
import { normalize, rgb2arr } from '@antv/l7-utils';
import { ILineLayerStyleOptions } from '../core/interface';
import { cloneDeep } from 'lodash';
@ -121,7 +121,6 @@ function unProjectCoordinates(coordinates: any, mapService: IMapService) {
function applyAttributeMapping(
attribute: IStyleAttribute,
record: { [key: string]: unknown },
minimumColor?: string,
) {
if (!attribute.scale) {
return [];
@ -137,9 +136,7 @@ function applyAttributeMapping(
});
const mappingResult = attribute.mapping ? attribute.mapping(params) : [];
if (attribute.name === 'color' && !isColor(mappingResult[0])) {
return [minimumColor];
}
return mappingResult;
}
@ -148,7 +145,6 @@ function mapping(
data: IParseDataItem[],
fontService: IFontService,
mapService: IMapService,
minimumColor?: string,
layer?: ILayer,
): IEncodeFeature[] {
const {
@ -165,7 +161,7 @@ function mapping(
attributes
.filter((attribute) => attribute.scale !== undefined)
.forEach((attribute: IStyleAttribute) => {
let values = applyAttributeMapping(attribute, record, minimumColor);
let values = applyAttributeMapping(attribute, record);
attribute.needRemapping = false;
@ -213,7 +209,6 @@ export function calculateData(
options: ISourceCFG | undefined,
): IEncodeFeature[] {
const source = new Source(data, options);
const bottomColor = layer.getBottomColor();
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
const { dataArray } = source.data;
const filterData = dataArray;
@ -223,7 +218,6 @@ export function calculateData(
filterData,
fontService,
mapService,
bottomColor,
layer,
);
source.destroy();

View File

@ -31,9 +31,10 @@ function mergeCustomizer(objValue: any, srcValue: any) {
return srcValue;
}
}
//
export default class Source extends EventEmitter implements ISource {
public type: string = 'source';
public isTile: boolean = false;
public inited: boolean = false;
public data: IParserData;
public center: [number, number];
@ -301,6 +302,7 @@ export default class Source extends EventEmitter implements ISource {
if (!tilesetOptions) {
return;
}
this.isTile = true;
if (this.tileset) {
this.tileset.updateOptions(tilesetOptions);
return this.tileset;

View File

@ -234,13 +234,4 @@ export default class ThreeJSLayer
public addAnimateMixer(mixer: AnimationMixer) {
this.animateMixer.push(mixer);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public setBottomColor(color: string): void {
console.warn('empty function');
}
public getBottomColor() {
return 'rgba(0, 0, 0, 0)';
}
}