diff --git a/dev-demos/features/tile/testTile.md b/dev-demos/features/tile/testTile.md
new file mode 100644
index 0000000000..79ed00771f
--- /dev/null
+++ b/dev-demos/features/tile/testTile.md
@@ -0,0 +1,2 @@
+### Test Tile
+
\ No newline at end of file
diff --git a/dev-demos/features/tile/testTile.tsx b/dev-demos/features/tile/testTile.tsx
new file mode 100644
index 0000000000..394ed4a59d
--- /dev/null
+++ b/dev-demos/features/tile/testTile.tsx
@@ -0,0 +1,33 @@
+import { Scene, TileDebugLayer } from '@antv/l7';
+import { Mapbox } from '@antv/l7-maps';
+import React, { useEffect } from 'react';
+
+export default () => {
+ useEffect(() => {
+ const scene = new Scene({
+ id: 'map',
+ // stencil: true,
+ map: new Mapbox({
+ center: [121.268, 30.3628],
+ pitch: 0,
+ // style: 'blank',
+ zoom: 4,
+ }),
+ });
+
+ const layer = new TileDebugLayer();
+
+ scene.on('loaded', () => {
+ scene.addLayer(layer);
+ });
+ }, []);
+ return (
+
+ );
+};
diff --git a/packages/core/src/services/layer/ILayerService.ts b/packages/core/src/services/layer/ILayerService.ts
index 1b4cbd0b49..e7b392e578 100644
--- a/packages/core/src/services/layer/ILayerService.ts
+++ b/packages/core/src/services/layer/ILayerService.ts
@@ -265,6 +265,10 @@ export interface ILayer {
masks: ILayer[]; // 图层的 mask 列表
sceneContainer: Container | undefined;
dataState: IDataState; // 数据流状态
+ defaultSourceConfig: {
+ data: any[],
+ options: ISourceCFG | undefined,
+ },
pickedFeatureID: number | null;
hooks: {
init: SyncBailHook;
diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts
index 89ab6a53d9..20b12f35e6 100644
--- a/packages/layers/src/core/BaseLayer.ts
+++ b/packages/layers/src/core/BaseLayer.ts
@@ -81,6 +81,11 @@ export default class BaseLayer
public layerType?: string | undefined;
public triangulation?: Triangulation | undefined;
+ public defaultSourceConfig: {
+ data: any[];
+ options: ISourceCFG | undefined;
+ };
+
public dataState: IDataState = {
dataSourceNeedUpdate: false,
dataMappingNeedUpdate: false,
diff --git a/packages/layers/src/index.ts b/packages/layers/src/index.ts
index 2007fd66ef..6fead23f06 100644
--- a/packages/layers/src/index.ts
+++ b/packages/layers/src/index.ts
@@ -16,6 +16,8 @@ import EarthLayer from './earth';
import MaskLayer from './mask';
import WindLayer from './wind';
+import TileDebugLayer from './tile/tileTest';
+
// import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
import DataMappingPlugin from './plugins/DataMappingPlugin';
import DataSourcePlugin from './plugins/DataSourcePlugin';
@@ -151,6 +153,7 @@ export {
EarthLayer,
WindLayer,
MaskLayer,
+ TileDebugLayer
};
export * from './core/interface';
diff --git a/packages/layers/src/line/index.ts b/packages/layers/src/line/index.ts
index ec2098619f..c77306789d 100644
--- a/packages/layers/src/line/index.ts
+++ b/packages/layers/src/line/index.ts
@@ -5,6 +5,25 @@ import { isVectorTile } from '../tile/utils';
export default class LineLayer extends BaseLayer {
public type: string = 'LineLayer';
+ public defaultSourceConfig = {
+ data: [
+ {
+ lng1: 100,
+ lat1: 30.0,
+ lng2: 130,
+ lat2: 30,
+ },
+ ],
+ options: {
+ parser: {
+ type: 'json',
+ x: 'lng1',
+ y: 'lat1',
+ x1: 'lng2',
+ y1: 'lat2',
+ },
+ },
+ };
public buildModels() {
const shape = this.getModelType();
diff --git a/packages/layers/src/mask/index.ts b/packages/layers/src/mask/index.ts
index f6955905b8..a8513d4fe9 100644
--- a/packages/layers/src/mask/index.ts
+++ b/packages/layers/src/mask/index.ts
@@ -4,6 +4,14 @@ import MaskModels, { MaskModelType } from './models';
export default class MaskLayer extends BaseLayer {
public type: string = 'MaskLayer';
+ public defaultSourceConfig: {
+ data: [];
+ options: {
+ parser: {
+ type: 'geojson';
+ };
+ };
+ };
public buildModels() {
const shape = this.getModelType();
this.layerModel = new MaskModels[shape](this);
diff --git a/packages/layers/src/plugins/DataSourcePlugin.ts b/packages/layers/src/plugins/DataSourcePlugin.ts
index 821b14104b..1b248f9e05 100644
--- a/packages/layers/src/plugins/DataSourcePlugin.ts
+++ b/packages/layers/src/plugins/DataSourcePlugin.ts
@@ -1,9 +1,5 @@
import { ILayer, ILayerPlugin, IMapService, TYPES } from '@antv/l7-core';
-import Source, {
- DEFAULT_DATA,
- DEFAULT_PARSER,
- DEFAULT_SOURCE,
-} from '@antv/l7-source';
+import Source from '@antv/l7-source';
import { injectable } from 'inversify';
import 'reflect-metadata';
@@ -15,14 +11,9 @@ export default class DataSourcePlugin implements ILayerPlugin {
layer.hooks.init.tap('DataSourcePlugin', () => {
let source = layer.getSource();
if (!source) {
- // TODO: 允许用户不使用 layer 的 source 方法,在这里传入一个默认的替换的默认数据
- const defaultSourceConfig = DEFAULT_SOURCE[
- layer.type as 'PointLayer' | 'LineLayer'
- ] || {
- data: DEFAULT_DATA,
- options: DEFAULT_PARSER,
- };
- const { data, options } = layer.sourceOption || defaultSourceConfig;
+ // Tip: 用户没有传入 source 的时候使用图层的默认数据
+ const { data, options } =
+ layer.sourceOption || layer.defaultSourceConfig;
source = new Source(data, options);
layer.setSource(source);
}
@@ -31,7 +22,6 @@ export default class DataSourcePlugin implements ILayerPlugin {
} else {
source.once('sourceUpdate', () => {
this.updateClusterData(layer);
- // TODO: layer.hooks.init.call();
});
}
// this.updateClusterData(layer);
diff --git a/packages/layers/src/point/index.ts b/packages/layers/src/point/index.ts
index 4e33ea0548..92236959b3 100644
--- a/packages/layers/src/point/index.ts
+++ b/packages/layers/src/point/index.ts
@@ -6,6 +6,17 @@ import { isVectorTile } from '../tile/utils';
export default class PointLayer extends BaseLayer {
public type: string = 'PointLayer';
+ public defaultSourceConfig = {
+ data: [],
+ options: {
+ parser: {
+ type: 'json',
+ x: 'lng',
+ y: 'lat',
+ },
+ },
+ };
+
public buildModels() {
const modelType = this.getModelType();
this.layerModel = new PointModels[modelType](this);
@@ -26,7 +37,7 @@ export default class PointLayer extends BaseLayer {
public getModelTypeWillEmptyData(): PointType {
if (this.shapeOption) {
const { field, values } = this.shapeOption;
- const { shape2d, shape3d } = this.getLayerConfig();
+ const { shape2d } = this.getLayerConfig();
const iconMap = this.iconService.getIconMap();
@@ -72,6 +83,7 @@ export default class PointLayer extends BaseLayer {
},
vectorpoint: {},
tile: {},
+ tileText: {},
earthFill: {},
earthExtrude: {},
};
@@ -79,20 +91,6 @@ export default class PointLayer extends BaseLayer {
}
protected getModelType(): PointType {
- const PointTypes = [
- 'fillImage',
- 'fill',
- 'radar',
- 'image',
- 'normal',
- 'simplePoint',
- 'extrude',
- 'text',
- 'vectorpoint',
- 'tile',
- 'earthFill',
- 'earthExtrude',
- ];
const parserType = this.layerSource.getParserType();
if (isVectorTile(parserType)) {
return 'vectorpoint';
diff --git a/packages/layers/src/point/models/index.ts b/packages/layers/src/point/models/index.ts
index 217a7fbe76..cf13432193 100644
--- a/packages/layers/src/point/models/index.ts
+++ b/packages/layers/src/point/models/index.ts
@@ -10,6 +10,7 @@ import NormalModel from './normal';
import Radar from './radar';
import SimplePopint from './simplePoint';
import TextModel from './text';
+import TileTextModel from './tileText';
import TileFillModel from './tile';
export type PointType =
@@ -23,6 +24,7 @@ export type PointType =
| 'text'
| 'vectorpoint'
| 'tile'
+ | 'tileText'
| 'earthFill'
| 'earthExtrude';
@@ -37,6 +39,7 @@ const PointModels: { [key in PointType]: any } = {
text: TextModel,
vectorpoint: PointTileModel,
tile: TileFillModel,
+ tileText: TileTextModel,
earthFill: EarthFillModel,
earthExtrude: EarthExtrudeModel,
};
diff --git a/packages/layers/src/point/models/tileText.ts b/packages/layers/src/point/models/tileText.ts
new file mode 100644
index 0000000000..dd4a75ad3e
--- /dev/null
+++ b/packages/layers/src/point/models/tileText.ts
@@ -0,0 +1,530 @@
+import {
+ AttributeType,
+ gl,
+ IEncodeFeature,
+ IModel,
+ IModelUniform,
+ ITexture2D,
+} from '@antv/l7-core';
+import {
+ calculateCentroid,
+ getMask,
+ padBounds,
+} from '@antv/l7-utils';
+import { isNumber } from 'lodash';
+import BaseModel from '../../core/BaseModel';
+import { IPointLayerStyleOptions } from '../../core/interface';
+import CollisionIndex from '../../utils/collision-index';
+import {
+ getGlyphQuads,
+ IGlyphQuad,
+ shapeText,
+} from '../../utils/symbol-layout';
+import textFrag from '../shaders/text_frag.glsl';
+import textVert from '../shaders/text_vert.glsl';
+
+export function TextTriangulation(feature: IEncodeFeature) {
+ // @ts-ignore
+ const that = this as TextModel;
+ const id = feature.id as number;
+ const vertices: number[] = [];
+ const indices: number[] = [];
+
+ if (!that.glyphInfoMap || !that.glyphInfoMap[id]) {
+ return {
+ vertices: [], // [ x, y, z, tex.x,tex.y, offset.x. offset.y]
+ indices: [],
+ size: 7,
+ };
+ }
+ const centroid = that.glyphInfoMap[id].centroid as number[]; // 计算中心点
+ const coord =
+ centroid.length === 2 ? [centroid[0], centroid[1], 0] : centroid;
+ that.glyphInfoMap[id].glyphQuads.forEach(
+ (quad: IGlyphQuad, index: number) => {
+ vertices.push(
+ ...coord,
+ quad.tex.x,
+ quad.tex.y + quad.tex.height,
+ quad.tl.x,
+ quad.tl.y,
+ ...coord,
+ quad.tex.x + quad.tex.width,
+ quad.tex.y + quad.tex.height,
+ quad.tr.x,
+ quad.tr.y,
+ ...coord,
+ quad.tex.x + quad.tex.width,
+ quad.tex.y,
+ quad.br.x,
+ quad.br.y,
+ ...coord,
+ quad.tex.x,
+ quad.tex.y,
+ quad.bl.x,
+ quad.bl.y,
+ );
+ indices.push(
+ 0 + index * 4,
+ 1 + index * 4,
+ 2 + index * 4,
+ 2 + index * 4,
+ 3 + index * 4,
+ 0 + index * 4,
+ );
+ },
+ );
+ return {
+ vertices, // [ x, y, z, tex.x,tex.y, offset.x. offset.y]
+ indices,
+ size: 7,
+ };
+}
+
+export default class TextModel extends BaseModel {
+ public glyphInfo: IEncodeFeature[];
+ public glyphInfoMap: {
+ [key: string]: {
+ shaping: any;
+ glyphQuads: IGlyphQuad[];
+ centroid: number[];
+ };
+ } = {};
+ private texture: ITexture2D;
+ private currentZoom: number = -1;
+ private extent: [[number, number], [number, number]];
+ private textureHeight: number = 0;
+ private textCount: number = 0;
+ private preTextStyle: Partial = {};
+ public getUninforms(): IModelUniform {
+ const {
+ opacity = 1.0,
+ stroke = '#fff',
+ strokeWidth = 0,
+ textAnchor = 'center',
+ textAllowOverlap = false,
+ halo = 0.5,
+ gamma = 2.0,
+ raisingHeight = 0,
+ } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
+ const { canvas, mapping } = this.fontService;
+ if (Object.keys(mapping).length !== this.textCount) {
+ this.updateTexture();
+ this.textCount = Object.keys(mapping).length;
+ }
+ this.preTextStyle = {
+ textAnchor,
+ textAllowOverlap,
+ };
+
+ if (
+ this.dataTextureTest &&
+ this.dataTextureNeedUpdate({
+ opacity,
+ strokeWidth,
+ stroke,
+ })
+ ) {
+ this.judgeStyleAttributes({
+ opacity,
+ strokeWidth,
+ stroke,
+ });
+
+ const encodeData = this.layer.getEncodedData();
+ const { data, width, height } = this.calDataFrame(
+ this.cellLength,
+ encodeData,
+ this.cellProperties,
+ );
+ this.rowCount = height; // 当前数据纹理有多少行
+
+ this.dataTexture =
+ this.cellLength > 0 && data.length > 0
+ ? this.createTexture2D({
+ flipY: true,
+ data,
+ format: gl.LUMINANCE,
+ type: gl.FLOAT,
+ width,
+ height,
+ })
+ : this.createTexture2D({
+ flipY: true,
+ data: [1],
+ format: gl.LUMINANCE,
+ type: gl.FLOAT,
+ width: 1,
+ height: 1,
+ });
+ }
+
+ return {
+ u_dataTexture: this.dataTexture, // 数据纹理 - 有数据映射的时候纹理中带数据,若没有任何数据映射时纹理是 [1]
+ u_cellTypeLayout: this.getCellTypeLayout(),
+ u_raisingHeight: Number(raisingHeight),
+
+ u_opacity: isNumber(opacity) ? opacity : 1.0,
+ u_stroke_width: isNumber(strokeWidth) ? strokeWidth : 1.0,
+ u_stroke_color: this.getStrokeColor(stroke),
+
+ u_sdf_map: this.texture,
+ u_halo_blur: halo,
+ u_gamma_scale: gamma,
+ u_sdf_map_size: [canvas.width, canvas.height],
+ };
+ }
+
+ public initModels(callbackModel: (models: IModel[]) => void) {
+ this.layer.on('remapping', this.mapping);
+ this.extent = this.textExtent();
+ const {
+ textAnchor = 'center',
+ textAllowOverlap = true,
+ } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
+ this.preTextStyle = {
+ textAnchor,
+ textAllowOverlap,
+ };
+ this.buildModels(callbackModel);
+ }
+
+ public buildModels = async (callbackModel: (models: IModel[]) => void) => {
+ const {
+ mask = false,
+ maskInside = true,
+ } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
+ this.mapping();
+
+ this.layer
+ .buildLayerModel({
+ moduleName: 'pointText',
+ vertexShader: textVert,
+ fragmentShader: textFrag,
+ triangulation: TextTriangulation.bind(this),
+ depth: { enable: false },
+ blend: this.getBlend(),
+ stencil: getMask(mask, maskInside),
+ })
+ .then((model) => {
+ callbackModel([model]);
+ })
+ .catch((err) => {
+ console.warn(err);
+ callbackModel([]);
+ });
+ };
+
+ public clearModels() {
+ this.texture?.destroy();
+ this.dataTexture?.destroy();
+ this.layer.off('remapping', this.mapping);
+ }
+ protected registerBuiltinAttributes() {
+ this.styleAttributeService.registerStyleAttribute({
+ name: 'rotate',
+ type: AttributeType.Attribute,
+ descriptor: {
+ name: 'a_Rotate',
+ buffer: {
+ usage: gl.DYNAMIC_DRAW,
+ data: [],
+ type: gl.FLOAT,
+ },
+ size: 1,
+ update: (
+ feature: IEncodeFeature,
+ featureIdx: number,
+ vertex: number[],
+ attributeIdx: number,
+ ) => {
+ const { rotate = 0 } = feature;
+ return Array.isArray(rotate) ? [rotate[0]] : [rotate as number];
+ },
+ },
+ });
+ this.styleAttributeService.registerStyleAttribute({
+ name: 'textOffsets',
+ type: AttributeType.Attribute,
+ descriptor: {
+ name: 'a_textOffsets',
+ buffer: {
+ // give the WebGL driver a hint that this buffer may change
+ usage: gl.STATIC_DRAW,
+ data: [],
+ type: gl.FLOAT,
+ },
+ size: 2,
+ update: (
+ feature: IEncodeFeature,
+ featureIdx: number,
+ vertex: number[],
+ attributeIdx: number,
+ ) => {
+ return [vertex[5], vertex[6]];
+ },
+ },
+ });
+
+ // point layer size;
+ this.styleAttributeService.registerStyleAttribute({
+ name: 'size',
+ type: AttributeType.Attribute,
+ descriptor: {
+ name: 'a_Size',
+ buffer: {
+ // give the WebGL driver a hint that this buffer may change
+ usage: gl.DYNAMIC_DRAW,
+ data: [],
+ type: gl.FLOAT,
+ },
+ size: 1,
+ update: (
+ feature: IEncodeFeature,
+ featureIdx: number,
+ vertex: number[],
+ attributeIdx: number,
+ ) => {
+ const { size = 12 } = feature;
+ return Array.isArray(size) ? [size[0]] : [size as number];
+ },
+ },
+ });
+
+ // point layer size;
+ this.styleAttributeService.registerStyleAttribute({
+ name: 'textUv',
+ type: AttributeType.Attribute,
+ descriptor: {
+ name: 'a_tex',
+ buffer: {
+ // give the WebGL driver a hint that this buffer may change
+ usage: gl.DYNAMIC_DRAW,
+ data: [],
+ type: gl.FLOAT,
+ },
+ size: 2,
+ update: (
+ feature: IEncodeFeature,
+ featureIdx: number,
+ vertex: number[],
+ attributeIdx: number,
+ ) => {
+ return [vertex[3], vertex[4]];
+ },
+ },
+ });
+ }
+
+ private mapping = () => {
+ this.initGlyph();
+ this.updateTexture();
+ this.filterGlyphs();
+ this.reBuildModel();
+ };
+ private textExtent(): [[number, number], [number, number]] {
+ const bounds = this.mapService.getBounds();
+ return padBounds(bounds, 0.5);
+ }
+ /**
+ * 生成文字纹理(生成文字纹理字典)
+ */
+ private initTextFont() {
+ const {
+ fontWeight = '400',
+ fontFamily = 'sans-serif',
+ } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
+ const data = this.layer.getEncodedData();
+ const characterSet: string[] = [];
+ data.forEach((item: IEncodeFeature) => {
+ let { shape = '' } = item;
+ shape = shape.toString();
+ for (const char of shape) {
+ // 去重
+ if (characterSet.indexOf(char) === -1) {
+ characterSet.push(char);
+ }
+ }
+ });
+ this.fontService.setFontOptions({
+ characterSet,
+ fontWeight,
+ fontFamily,
+ iconfont: false,
+ });
+ }
+
+ /**
+ * 生成 iconfont 纹理字典
+ */
+ private initIconFontTex() {
+ const {
+ fontWeight = '400',
+ fontFamily = 'sans-serif',
+ } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
+ const data = this.layer.getEncodedData();
+ const characterSet: string[] = [];
+ data.forEach((item: IEncodeFeature) => {
+ let { shape = '' } = item;
+ shape = `${shape}`;
+ if (characterSet.indexOf(shape) === -1) {
+ characterSet.push(shape);
+ }
+ });
+ this.fontService.setFontOptions({
+ characterSet,
+ fontWeight,
+ fontFamily,
+ iconfont: true,
+ });
+ }
+
+ /**
+ * 生成文字布局(对照文字纹理字典提取对应文字的位置很好信息)
+ */
+ private generateGlyphLayout(iconfont: boolean) {
+ // TODO:更新文字布局
+ const { mapping } = this.fontService;
+ const {
+ spacing = 2,
+ textAnchor = 'center',
+ } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
+ const data = this.layer.getEncodedData();
+
+ this.glyphInfo = data.map((feature: IEncodeFeature) => {
+ const { shape = '', id, size = 1, textOffset = [0, 0] } = feature;
+
+ const shaping = shapeText(
+ shape.toString(),
+ mapping,
+ // @ts-ignore
+ size,
+ textAnchor,
+ 'left',
+ spacing,
+ textOffset,
+ iconfont,
+ );
+ const glyphQuads = getGlyphQuads(shaping, textOffset, false);
+ feature.shaping = shaping;
+ feature.glyphQuads = glyphQuads;
+
+ feature.centroid = calculateCentroid(feature.coordinates);
+
+ // 此时地图高德2.0 originCentroid == centroid
+ feature.originCentroid =
+ feature.version === 'GAODE2.x'
+ ? calculateCentroid(feature.originCoordinates)
+ : (feature.originCentroid = feature.centroid);
+
+ this.glyphInfoMap[id as number] = {
+ shaping,
+ glyphQuads,
+ centroid: calculateCentroid(feature.coordinates),
+ };
+ return feature;
+ });
+ }
+ /**
+ * 文字避让 depend on originCentorid
+ */
+ private filterGlyphs() {
+ const {
+ padding = [4, 4],
+ textAllowOverlap = false,
+ } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
+ if (textAllowOverlap) {
+ // 如果允许文本覆盖
+ return;
+ }
+ this.glyphInfoMap = {};
+ this.currentZoom = this.mapService.getZoom();
+ this.extent = this.textExtent();
+ const { width, height } = this.rendererService.getViewportSize();
+ const collisionIndex = new CollisionIndex(width, height);
+ const filterData = this.glyphInfo.filter((feature: IEncodeFeature) => {
+ const { shaping, id = 0 } = feature;
+ const centroid = (feature.version === 'GAODE2.x'
+ ? feature.originCentroid
+ : feature.centroid) as [number, number];
+ const size = feature.size as number;
+ const fontScale: number = size / 24;
+ const pixels = this.mapService.lngLatToContainer(centroid);
+ const { box } = collisionIndex.placeCollisionBox({
+ x1: shaping.left * fontScale - padding[0],
+ x2: shaping.right * fontScale + padding[0],
+ y1: shaping.top * fontScale - padding[1],
+ y2: shaping.bottom * fontScale + padding[1],
+ anchorPointX: pixels.x,
+ anchorPointY: pixels.y,
+ });
+ if (box && box.length) {
+ // TODO:featureIndex
+ collisionIndex.insertCollisionBox(box, id);
+ return true;
+ } else {
+ return false;
+ }
+ });
+ filterData.forEach((item) => {
+ // @ts-ignore
+ this.glyphInfoMap[item.id as number] = item;
+ });
+ }
+ /**
+ * 初始化文字布局
+ */
+ private initGlyph() {
+ const { iconfont = false } = this.layer.getLayerConfig();
+ // 1.生成文字纹理(或是生成 iconfont)
+ iconfont ? this.initIconFontTex() : this.initTextFont();
+
+ // 2.生成文字布局
+ this.generateGlyphLayout(iconfont);
+ }
+ /**
+ * 更新文字纹理
+ */
+ private updateTexture() {
+ const { createTexture2D } = this.rendererService;
+ const { canvas } = this.fontService;
+ this.textureHeight = canvas.height;
+ if (this.texture) {
+ this.texture.destroy();
+ }
+
+ this.texture = createTexture2D({
+ data: canvas,
+ mag: gl.LINEAR,
+ min: gl.LINEAR,
+ width: canvas.width,
+ height: canvas.height,
+ });
+ }
+
+ private reBuildModel() {
+ const {
+ mask = false,
+ maskInside = true,
+ } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
+ this.filterGlyphs();
+ this.layer
+ .buildLayerModel({
+ moduleName: 'pointTileText',
+ vertexShader: textVert,
+ fragmentShader: textFrag,
+ triangulation: TextTriangulation.bind(this),
+ depth: { enable: false },
+ blend: this.getBlend(),
+ stencil: getMask(mask, maskInside),
+ })
+ .then((model) => {
+ this.layer.models = [model];
+ this.layer.renderLayers();
+ })
+ .catch((err) => {
+ console.warn(err);
+ this.layer.models = [];
+ });
+ }
+}
diff --git a/packages/layers/src/polygon/index.ts b/packages/layers/src/polygon/index.ts
index 3afdb4eed0..5bb4fbde47 100644
--- a/packages/layers/src/polygon/index.ts
+++ b/packages/layers/src/polygon/index.ts
@@ -6,6 +6,14 @@ import { isVectorTile } from '../tile/utils';
export default class PolygonLayer extends BaseLayer {
public type: string = 'PolygonLayer';
+ public defaultSourceConfig: {
+ data: [];
+ options: {
+ parser: {
+ type: 'geojson';
+ };
+ };
+ };
public buildModels() {
const shape = this.getModelType();
this.layerModel = new PolygonModels[shape](this);
diff --git a/packages/layers/src/tile/manager/tileLayerManager.ts b/packages/layers/src/tile/manager/tileLayerManager.ts
index 89f5a68130..922d88b10b 100644
--- a/packages/layers/src/tile/manager/tileLayerManager.ts
+++ b/packages/layers/src/tile/manager/tileLayerManager.ts
@@ -184,13 +184,14 @@ export class TileLayerManager implements ITileLayerManager {
this.rampColorsData = generateColorRamp(rampColors as IColorRamp);
}
+
this.initOptions = {
layerType: this.parent.type,
transforms: this.transforms,
shape: layerShape,
zIndex,
opacity,
- sourceLayer: parentParserType === 'geojsonvt' ? 'geojsonvt' : sourceLayer,
+ sourceLayer: this.getSourceLayer(parentParserType, sourceLayer),
coords,
featureId,
color: colorValue,
@@ -216,6 +217,16 @@ export class TileLayerManager implements ITileLayerManager {
};
}
+ private getSourceLayer(parentParserType: string, sourceLayer: string|undefined) {
+ if(parentParserType === 'geojsonvt') {
+ return 'geojsonvt';
+ } else if(parentParserType === 'testTile') {
+ return 'testTile';
+ } else {
+ return sourceLayer;
+ }
+ }
+
private setConfigListener() {
// RasterLayer PolygonLayer LineLayer PointLayer
// All Tile Layer Need Listen
diff --git a/packages/layers/src/tile/models/tileModel.ts b/packages/layers/src/tile/models/tileModel.ts
index ae82665ef4..4d02e86366 100644
--- a/packages/layers/src/tile/models/tileModel.ts
+++ b/packages/layers/src/tile/models/tileModel.ts
@@ -1,7 +1,7 @@
import { IModelUniform } from '@antv/l7-core';
import BaseModel from '../../core/BaseModel';
import { TMSTileLayer } from '../tmsTileLayer';
-export default class RasterTileModel extends BaseModel {
+export default class TileModel extends BaseModel {
public getUninforms(): IModelUniform {
return {};
}
diff --git a/packages/layers/src/tile/tileFactory/index.ts b/packages/layers/src/tile/tileFactory/index.ts
index cd383826a8..2ee234f2f5 100644
--- a/packages/layers/src/tile/tileFactory/index.ts
+++ b/packages/layers/src/tile/tileFactory/index.ts
@@ -4,12 +4,14 @@ import VectorPointLayer from './point';
import VectorPolygonTile from './polygon';
import RasterTileFactory from './raster';
import RasterDataFactory from './rasterData';
+import TestTile from './test';
export type TileType =
| 'PolygonLayer'
| 'PointLayer'
| 'LineLayer'
- | 'RasterLayer';
+ | 'RasterLayer'
+ | 'TileDebugLayer';
export function getTileFactory(tileType: TileType, parser: IParserCfg) {
switch (tileType) {
@@ -19,6 +21,8 @@ export function getTileFactory(tileType: TileType, parser: IParserCfg) {
return VectorLineTile;
case 'PointLayer':
return VectorPointLayer;
+ case 'TileDebugLayer':
+ return TestTile;
case 'RasterLayer':
if (parser.dataType === 'arraybuffer') {
return RasterDataFactory;
diff --git a/packages/layers/src/tile/tileFactory/test.ts b/packages/layers/src/tile/tileFactory/test.ts
new file mode 100644
index 0000000000..b94c4de25f
--- /dev/null
+++ b/packages/layers/src/tile/tileFactory/test.ts
@@ -0,0 +1,69 @@
+import { ILayer, ISubLayerInitOptions } from '@antv/l7-core';
+import { Tile } from '@antv/l7-utils';
+import { ITileFactoryOptions } from '../interface';
+import TileFactory from './base';
+import VectorLayer from './vectorLayer';
+import {
+ registerLayers,
+} from '../utils';
+
+export default class TestTile extends TileFactory {
+ public parentLayer: ILayer;
+
+ constructor(option: ITileFactoryOptions) {
+ super(option);
+ this.parentLayer = option.parent;
+ }
+
+ public createTile(tile: Tile, initOptions: ISubLayerInitOptions) {
+ const { sourceLayer } = initOptions;
+ if (!sourceLayer) {
+ return {
+ layers: [],
+ layerIDList: [],
+ };
+ }
+ const vectorTileLayer = tile.data.layers[sourceLayer];
+ const features = vectorTileLayer?.features;
+
+ if (features.length === 0) {
+ return {
+ layers: [],
+ layerIDList: [],
+ };
+ }
+
+ const properties = features[0].properties;
+
+ const text = new VectorLayer({ layerType: 'PointLayer' })
+ .source([properties], {
+ parser: {
+ type: 'json',
+ x: 'textLng',
+ y: 'textLat'
+ }
+ })
+ .shape('key', 'text')
+ .size(20)
+ .color('#000')
+ .style({
+ stroke: '#fff',
+ strokeWidth: 2
+ })
+
+ const line = new VectorLayer({ layerType: 'LineLayer' })
+ .source({
+ type: 'FeatureCollection',
+ features: features,
+ })
+ .shape('simple')
+ .color('#000')
+
+ registerLayers(this.parentLayer, [line, text]);
+
+ return {
+ layers: [line, text],
+ layerIDList: [line.id, text.id],
+ };
+ }
+}
diff --git a/packages/layers/src/tile/tileFactory/vectorLayer.ts b/packages/layers/src/tile/tileFactory/vectorLayer.ts
index 3ddc2d5a02..d01d1bb694 100644
--- a/packages/layers/src/tile/tileFactory/vectorLayer.ts
+++ b/packages/layers/src/tile/tileFactory/vectorLayer.ts
@@ -8,7 +8,7 @@ import {
import lineFillModel from '../../line/models/tile';
import lineSimpleModel from '../../line/models/simpleLine';
-import pointTextModel from '../../point/models/text';
+import pointTextModel from '../../point/models/tileText';
import pointFillModel from '../../point/models/tile';
import polygonFillModel from '../../polygon/models/tile';
diff --git a/packages/layers/src/tile/tileTest.ts b/packages/layers/src/tile/tileTest.ts
new file mode 100644
index 0000000000..bc51b6f933
--- /dev/null
+++ b/packages/layers/src/tile/tileTest.ts
@@ -0,0 +1,22 @@
+import BaseLayer from '../core/BaseLayer';
+import { IBaseLayerStyleOptions } from '../core/interface';
+import TileModel from './models/tileModel';
+
+export default class TileDebugLayer extends BaseLayer {
+ public type: string = 'TileDebugLayer';
+ public defaultSourceConfig = {
+ data: [],
+ options: {
+ parser: {
+ type: 'testTile',
+ },
+ },
+ };
+ public buildModels() {
+ this.layerModel = new TileModel(this);
+ this.layerModel.initModels((models) => {
+ this.models = models;
+ this.renderLayers();
+ });
+ }
+}
diff --git a/packages/layers/src/tile/utils.ts b/packages/layers/src/tile/utils.ts
index 91b0ff17f9..ab7c8e5fb6 100644
--- a/packages/layers/src/tile/utils.ts
+++ b/packages/layers/src/tile/utils.ts
@@ -7,7 +7,7 @@ import {
import { DOM, Tile } from '@antv/l7-utils';
import { Container } from 'inversify';
-export const tileVectorParser = ['mvt', 'geojsonvt'];
+export const tileVectorParser = ['mvt', 'geojsonvt', 'testTile'];
export function isVectorTile(parserType: string) {
return tileVectorParser.indexOf(parserType) >= 0;
diff --git a/packages/source/src/index.ts b/packages/source/src/index.ts
index 2ddaf700a8..579aceac1f 100644
--- a/packages/source/src/index.ts
+++ b/packages/source/src/index.ts
@@ -2,11 +2,12 @@ import { registerParser, registerTransform } from './factory';
import csv from './parser/csv';
import geojson from './parser/geojson';
import image from './parser/image';
-import json, { defaultData, defaultParser, defaultSource } from './parser/json';
+import json from './parser/json';
import mapboxVectorTile from './parser/mvt';
import geojsonVTTile from './parser/geojsonvt';
import raster from './parser/raster';
import rasterTile from './parser/raster-tile';
+import testTile from './parser/testTile';
import Source from './source';
import { cluster } from './transform/cluster';
import { filter } from './transform/filter';
@@ -18,6 +19,7 @@ import { map } from './transform/map';
registerParser('rasterTile', rasterTile);
registerParser('mvt', mapboxVectorTile);
registerParser('geojsonvt', geojsonVTTile);
+registerParser('testTile', testTile);
registerParser('geojson', geojson);
registerParser('image', image);
registerParser('csv', csv);
@@ -39,8 +41,4 @@ export {
export * from './interface';
-export const DEFAULT_SOURCE = defaultSource;
-export const DEFAULT_DATA = defaultData;
-export const DEFAULT_PARSER = defaultParser;
-
export default Source;
diff --git a/packages/source/src/parser/json.ts b/packages/source/src/parser/json.ts
index 1f316e5d2b..3a71f434c5 100644
--- a/packages/source/src/parser/json.ts
+++ b/packages/source/src/parser/json.ts
@@ -84,55 +84,3 @@ export default function json(data: IJsonData, cfg: IParserCfg): IParserData {
dataArray: resultData,
};
}
-
-export const defaultSource = {
- PointLayer: {
- data: [],
- options: {
- parser: {
- type: 'json',
- x: 'lng',
- y: 'lat',
- },
- },
- },
- LineLayer: {
- data: [
- {
- lng1: 100,
- lat1: 30.0,
- lng2: 130,
- lat2: 30,
- },
- ],
- options: {
- parser: {
- type: 'json',
- x: 'lng1',
- y: 'lat1',
- x1: 'lng2',
- y1: 'lat2',
- },
- },
- },
-};
-
-// TODO: 提供默认数据和解析器
-export const defaultData = [
- {
- lng1: 100,
- lat1: 30.0,
- lng2: 130,
- lat2: 30,
- },
-];
-
-export const defaultParser = {
- parser: {
- type: 'json',
- x: 'lng1',
- y: 'lat1',
- x1: 'lng2',
- y1: 'lat2',
- },
-};
diff --git a/packages/source/src/parser/testTile.ts b/packages/source/src/parser/testTile.ts
new file mode 100644
index 0000000000..eb9b10f38a
--- /dev/null
+++ b/packages/source/src/parser/testTile.ts
@@ -0,0 +1,76 @@
+import { Tile, TilesetManagerOptions } from '@antv/l7-utils';
+import { VectorTileLayer } from '@mapbox/vector-tile';
+import { Feature } from '@turf/helpers';
+import { IParserData, ITileParserCFG } from '../interface';
+
+const DEFAULT_CONFIG: Partial = {
+ tileSize: 256,
+ minZoom: 0,
+ maxZoom: Infinity,
+ zoomOffset: 0,
+};
+
+export type MapboxVectorTile = {
+ layers: { [_: string]: VectorTileLayer & { features: Feature[] } };
+};
+
+const getVectorTile = async (tile: Tile): Promise => {
+ return new Promise((resolve) => {
+ const [minLng, minLat, maxLng, maxLat] = tile.bounds;
+ // minLng/maxLat ---- maxLng/maxLat
+ // | |
+ // | |
+ // | |
+ // minLng/minLat --- maxLng/minLat
+
+ const vectorTile = {
+ layers: {
+ // Tip: fixed SourceLayer Name
+ testTile: ({
+ features: [
+ {
+ type: 'Feature',
+ properties: {
+ key: tile.x + '/' + tile.y + '/' + tile.z,
+ textLng: (minLng + maxLng) / 2,
+ textLat: (minLat + maxLat) / 2,
+ },
+ geometry: {
+ type: 'LineString',
+ coordinates: [
+ [maxLng, maxLat],
+ [maxLng, minLat],
+ [minLng, minLat],
+ [minLng, minLat],
+ ],
+ },
+ },
+ ],
+ } as unknown) as VectorTileLayer & {
+ features: Feature[];
+ },
+ },
+ } as MapboxVectorTile;
+
+ resolve(vectorTile);
+ });
+};
+
+export default function mapboxVectorTile(
+ data: string | string[],
+ cfg?: ITileParserCFG,
+): IParserData {
+ const getTileData = (tile: Tile) => getVectorTile(tile);
+ const tilesetOptions = {
+ ...DEFAULT_CONFIG,
+ ...cfg,
+ getTileData,
+ };
+
+ return {
+ data,
+ dataArray: [],
+ tilesetOptions,
+ isTile: true,
+ };
+}