@antv/l7-layers 2.24.0 → 2.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -80,6 +80,7 @@ export interface IPointLayerStyleOptions extends IBaseLayerStyleOptions {
80
80
  fontWeight?: string;
81
81
  fontFamily?: string;
82
82
  textAllowOverlap?: boolean;
83
+ allowOverlap?: boolean;
83
84
  pickLight?: boolean;
84
85
  sourceColor?: string;
85
86
  targetColor?: string;
@@ -112,6 +112,17 @@ export function PointExtrudeTriangulation(feature) {
112
112
  * @param feature 映射feature
113
113
  */
114
114
  export function PointImageTriangulation(feature) {
115
+ // @ts-ignore
116
+ const that = this;
117
+ const id = feature.id;
118
+ // 当 imageFilterMap 存在且该 feature 未通过碰撞检测时,返回空几何(等效隐藏)
119
+ if (that !== null && that !== void 0 && that.imageFilterMap && !that.imageFilterMap[id]) {
120
+ return {
121
+ vertices: [],
122
+ indices: [],
123
+ size: 3
124
+ };
125
+ }
115
126
  const coordinates = calculateCentroid(feature.coordinates);
116
127
  return {
117
128
  vertices: [...coordinates],
@@ -12,4 +12,4 @@ import RegisterStyleAttributePlugin from './RegisterStyleAttributePlugin';
12
12
  import ShaderUniformPlugin from './ShaderUniformPlugin';
13
13
  import UpdateModelPlugin from './UpdateModelPlugin';
14
14
  import UpdateStyleAttributePlugin from './UpdateStyleAttributePlugin';
15
- export declare function createPlugins(): (DataSourcePlugin | RegisterStyleAttributePlugin | FeatureScalePlugin | DataMappingPlugin | LayerStylePlugin | LayerMaskPlugin | UpdateStyleAttributePlugin | UpdateModelPlugin | MultiPassRendererPlugin | ShaderUniformPlugin | LayerAnimateStylePlugin | LightingPlugin | PixelPickingPlugin | LayerModelPlugin)[];
15
+ export declare function createPlugins(): (DataMappingPlugin | DataSourcePlugin | FeatureScalePlugin | LayerAnimateStylePlugin | LayerMaskPlugin | LayerModelPlugin | LayerStylePlugin | LightingPlugin | MultiPassRendererPlugin | PixelPickingPlugin | RegisterStyleAttributePlugin | ShaderUniformPlugin | UpdateModelPlugin | UpdateStyleAttributePlugin)[];
@@ -1,3 +1,4 @@
1
+ import type { ILayer, ILayerConfig } from '@antv/l7-core';
1
2
  import BaseLayer from '../core/BaseLayer';
2
3
  import type { IPointLayerStyleOptions } from '../core/interface';
3
4
  import type { PointType } from './models/index';
@@ -17,6 +18,7 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
17
18
  };
18
19
  buildModels(): Promise<void>;
19
20
  rebuildModels(): Promise<void>;
21
+ style(options: Partial<IPointLayerStyleOptions> & Partial<ILayerConfig>): ILayer;
20
22
  /**
21
23
  * 在未传入数据的时候判断点图层的 shape 类型
22
24
  * @returns
package/es/point/index.js CHANGED
@@ -37,6 +37,16 @@ export default class PointLayer extends BaseLayer {
37
37
  yield _this2.buildModels();
38
38
  })();
39
39
  }
40
+ style(options) {
41
+ super.style(options);
42
+ // allowOverlap 依赖 needUpdate() 感知变化并重建 model,而 needUpdate() 仅在渲染帧的
43
+ // beforeRender 钩子中被调用。style() 本身不触发渲染,因此在 allowOverlap 出现时
44
+ // 主动触发一次 reRender,确保静止地图下也能即时生效。
45
+ if ('allowOverlap' in options) {
46
+ this.reRender();
47
+ }
48
+ return this;
49
+ }
40
50
 
41
51
  /**
42
52
  * 在未传入数据的时候判断点图层的 shape 类型
@@ -50,7 +50,7 @@ export default class FillModel extends BaseModel {
50
50
  } = this.layer.getLayerConfig();
51
51
  return {
52
52
  u_animate: this.animateOption2Array(animateOption),
53
- u_time: this.layer.getLayerAnimateTime()
53
+ u_time: animateOption.enable ? this.layer.getLayerAnimateTime() : -1.0
54
54
  };
55
55
  }
56
56
  getAttribute() {
@@ -17,6 +17,12 @@ export default class ImageModel extends BaseModel {
17
17
  UV: number;
18
18
  };
19
19
  private texture;
20
+ imageFilterMap: {
21
+ [key: number]: boolean;
22
+ } | null;
23
+ private currentZoom;
24
+ private extent;
25
+ private preAllowOverlap;
20
26
  getUninforms(): IModelUniform;
21
27
  protected getCommonUniformsInfo(): {
22
28
  uniformsArray: number[];
@@ -26,8 +32,17 @@ export default class ImageModel extends BaseModel {
26
32
  };
27
33
  };
28
34
  initModels(): Promise<IModel[]>;
29
- clearModels(): void;
30
35
  buildModels(): Promise<IModel[]>;
36
+ needUpdate(): Promise<boolean>;
37
+ clearModels(): void;
31
38
  protected registerBuiltinAttributes(): void;
39
+ /**
40
+ * 图标碰撞避让:遍历所有 feature,在屏幕空间做 AABB 碰撞检测,
41
+ * 将通过检测的 feature id 写入 imageFilterMap。
42
+ * PointImageTriangulation 绑定 this 后,会跳过不在 map 中的 feature。
43
+ */
44
+ private filterImages;
45
+ private imageExtent;
46
+ private reBuildModel;
32
47
  private updateTexture;
33
48
  }
@@ -2,8 +2,10 @@ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
2
2
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
3
3
  import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
4
4
  import { AttributeType, gl } from '@antv/l7-core';
5
+ import { boundsContains, calculateCentroid, padBounds } from '@antv/l7-utils';
5
6
  import BaseModel from "../../core/BaseModel";
6
7
  import { PointImageTriangulation } from "../../core/triangulation";
8
+ import CollisionIndex from "../../utils/collision-index";
7
9
  /* babel-plugin-inline-import '../shaders/image/image_frag.glsl' */
8
10
  const pointImageFrag = "layout(std140) uniform commonUniforms {\n vec2 u_textSize;\n float u_raisingHeight;\n float u_heightfixed;\n};\n\nuniform sampler2D u_texture;\n\nin vec4 v_color;\nin vec2 v_uv;\nin float v_opacity;\n\n#pragma include \"picking\"\n\nout vec4 outputColor;\n\nvoid main() {\n vec2 pos = v_uv / u_textSize + gl_PointCoord / u_textSize * 64.0;\n vec4 textureColor;\n\n // Y = 0.299R + 0.587G + 0.114B // \u4EAE\u5EA6\u63D0\u53D6\n\n textureColor = texture(SAMPLER_2D(u_texture), pos);\n\n // Tip: \u53BB\u9664\u8FB9\u7F18\u90E8\u5206 mipmap \u5BFC\u81F4\u7684\u6DF7\u5408\u53D8\u6697\n float fragmengTocenter = distance(vec2(0.5), gl_PointCoord);\n if (fragmengTocenter >= 0.5) {\n float luma = 0.299 * textureColor.r + 0.587 * textureColor.g + 0.114 * textureColor.b;\n textureColor.a *= luma;\n }\n\n if (\n all(lessThan(v_color, vec4(1.0 + 0.00001))) && all(greaterThan(v_color, vec4(1.0 - 0.00001))) ||\n v_color == vec4(1.0)\n ) {\n outputColor = textureColor;\n } else {\n outputColor = step(0.01, textureColor.z) * v_color;\n }\n outputColor.a *= v_opacity;\n if (outputColor.a < 0.01) {\n discard;\n }\n outputColor = filterColor(outputColor);\n}\n";
9
11
  /* babel-plugin-inline-import '../shaders/image/image_vert.glsl' */
@@ -12,6 +14,11 @@ export default class ImageModel extends BaseModel {
12
14
  constructor(...args) {
13
15
  super(...args);
14
16
  _defineProperty(this, "texture", void 0);
17
+ // 通过碰撞检测的 feature id 集合,由 filterImages() 填充;null 表示不启用过滤(allowOverlap: true)
18
+ _defineProperty(this, "imageFilterMap", null);
19
+ _defineProperty(this, "currentZoom", -1);
20
+ _defineProperty(this, "extent", void 0);
21
+ _defineProperty(this, "preAllowOverlap", true);
15
22
  _defineProperty(this, "updateTexture", () => {
16
23
  const {
17
24
  createTexture2D
@@ -78,25 +85,35 @@ export default class ImageModel extends BaseModel {
78
85
  initModels() {
79
86
  var _this = this;
80
87
  return _asyncToGenerator(function* () {
88
+ const {
89
+ allowOverlap = true
90
+ } = _this.layer.getLayerConfig();
91
+ _this.extent = _this.imageExtent();
92
+ _this.preAllowOverlap = allowOverlap;
81
93
  _this.iconService.on('imageUpdate', _this.updateTexture);
82
94
  _this.updateTexture();
83
95
  return _this.buildModels();
84
96
  })();
85
97
  }
86
- clearModels() {
87
- var _this$texture2;
88
- (_this$texture2 = this.texture) === null || _this$texture2 === void 0 || _this$texture2.destroy();
89
- this.iconService.off('imageUpdate', this.updateTexture);
90
- }
91
98
  buildModels() {
92
99
  var _this2 = this;
93
100
  return _asyncToGenerator(function* () {
101
+ const {
102
+ allowOverlap = true
103
+ } = _this2.layer.getLayerConfig();
94
104
  _this2.initUniformsBuffer();
105
+ if (!allowOverlap) {
106
+ _this2.filterImages();
107
+ } else {
108
+ // 允许压盖时置 null,PointImageTriangulation 检测到 null 则跳过过滤
109
+ _this2.imageFilterMap = null;
110
+ }
95
111
  const model = yield _this2.layer.buildLayerModel({
96
112
  moduleName: 'pointImage',
97
113
  vertexShader: pointImageVert,
98
114
  fragmentShader: pointImageFrag,
99
- triangulation: PointImageTriangulation,
115
+ // 绑定 this,让 PointImageTriangulation 能读取 imageFilterMap
116
+ triangulation: PointImageTriangulation.bind(_this2),
100
117
  defines: _this2.getDefines(),
101
118
  inject: _this2.getInject(),
102
119
  depth: {
@@ -107,6 +124,41 @@ export default class ImageModel extends BaseModel {
107
124
  return [model];
108
125
  })();
109
126
  }
127
+ needUpdate() {
128
+ var _this3 = this;
129
+ return _asyncToGenerator(function* () {
130
+ const {
131
+ allowOverlap = true
132
+ } = _this3.layer.getLayerConfig();
133
+
134
+ // allowOverlap 开关发生变化时,强制重建
135
+ if (allowOverlap !== _this3.preAllowOverlap) {
136
+ _this3.preAllowOverlap = allowOverlap;
137
+ yield _this3.reBuildModel();
138
+ return true;
139
+ }
140
+
141
+ // 允许压盖时无需每帧检测
142
+ if (allowOverlap) {
143
+ return false;
144
+ }
145
+
146
+ // 不允许压盖时,zoom 变化 >0.5 或视野超出上次范围则重算碰撞
147
+ const zoom = _this3.mapService.getZoom();
148
+ const extent = _this3.mapService.getBounds();
149
+ const flag = boundsContains(_this3.extent, extent);
150
+ if (Math.abs(_this3.currentZoom - zoom) > 0.5 || !flag) {
151
+ yield _this3.reBuildModel();
152
+ return true;
153
+ }
154
+ return false;
155
+ })();
156
+ }
157
+ clearModels() {
158
+ var _this$texture2;
159
+ (_this$texture2 = this.texture) === null || _this$texture2 === void 0 || _this$texture2.destroy();
160
+ this.iconService.off('imageUpdate', this.updateTexture);
161
+ }
110
162
  registerBuiltinAttributes() {
111
163
  // 注册 Position 属性 64 位地位部分,经纬度数据开启双精度,避免大于 20层级以上出现数据偏移
112
164
  this.registerPosition64LowAttribute();
@@ -165,4 +217,77 @@ export default class ImageModel extends BaseModel {
165
217
  }
166
218
  });
167
219
  }
220
+
221
+ /**
222
+ * 图标碰撞避让:遍历所有 feature,在屏幕空间做 AABB 碰撞检测,
223
+ * 将通过检测的 feature id 写入 imageFilterMap。
224
+ * PointImageTriangulation 绑定 this 后,会跳过不在 map 中的 feature。
225
+ */
226
+ filterImages() {
227
+ const {
228
+ padding = [0, 0]
229
+ } = this.layer.getLayerConfig();
230
+ this.imageFilterMap = {};
231
+ this.currentZoom = this.mapService.getZoom();
232
+ this.extent = this.imageExtent();
233
+ const {
234
+ width,
235
+ height
236
+ } = this.rendererService.getViewportSize();
237
+ const collisionIndex = new CollisionIndex(width, height);
238
+ const data = this.layer.getEncodedData();
239
+ data.forEach(feature => {
240
+ const {
241
+ id = 0,
242
+ size = 5
243
+ } = feature;
244
+ const iconSize = Array.isArray(size) ? size[0] : size;
245
+ const centroid = calculateCentroid(feature.coordinates);
246
+ const pixels = this.mapService.lngLatToContainer(centroid);
247
+ const {
248
+ box
249
+ } = collisionIndex.placeCollisionBox({
250
+ x1: -iconSize - padding[0],
251
+ x2: iconSize + padding[0],
252
+ y1: -iconSize - padding[1],
253
+ y2: iconSize + padding[1],
254
+ anchorPointX: pixels.x,
255
+ anchorPointY: pixels.y
256
+ });
257
+ if (box && box.length) {
258
+ collisionIndex.insertCollisionBox(box, id);
259
+ this.imageFilterMap[id] = true;
260
+ }
261
+ });
262
+ }
263
+ imageExtent() {
264
+ const bounds = this.mapService.getBounds();
265
+ return padBounds(bounds, 0.5);
266
+ }
267
+ reBuildModel() {
268
+ var _this4 = this;
269
+ return _asyncToGenerator(function* () {
270
+ const {
271
+ allowOverlap = true
272
+ } = _this4.layer.getLayerConfig();
273
+ if (!allowOverlap) {
274
+ _this4.filterImages();
275
+ } else {
276
+ _this4.imageFilterMap = null; // 允许压盖:清空过滤表,全量渲染
277
+ }
278
+ const model = yield _this4.layer.buildLayerModel({
279
+ moduleName: 'pointImage',
280
+ vertexShader: pointImageVert,
281
+ fragmentShader: pointImageFrag,
282
+ triangulation: PointImageTriangulation.bind(_this4),
283
+ defines: _this4.getDefines(),
284
+ inject: _this4.getInject(),
285
+ depth: {
286
+ enable: false
287
+ },
288
+ primitive: gl.POINTS
289
+ });
290
+ _this4.layer.models = [model];
291
+ })();
292
+ }
168
293
  }
@@ -47,7 +47,7 @@ export default abstract class Tile extends EventEmitter implements ITile {
47
47
  enablePropagation?: boolean | undefined;
48
48
  fitBoundsOptions?: unknown;
49
49
  name?: string | undefined;
50
- blend?: "normal" | "additive" | "subtractive" | "min" | "max" | "none" | undefined;
50
+ blend?: "min" | "max" | "normal" | "additive" | "subtractive" | "none" | undefined;
51
51
  depth?: boolean | undefined;
52
52
  pickedFeatureID?: number | undefined;
53
53
  enableMultiPassRenderer?: boolean | undefined;
@@ -7,6 +7,6 @@ import RasterTerrainRGBTile from './RasterTerrainRGBTile';
7
7
  import RasterTile from './RasterTile';
8
8
  import VectorTile from './VectorTile';
9
9
  export type TileType = 'VectorTile' | 'DebugTile' | 'PolygonLayer' | 'PointLayer' | 'LineLayer' | 'RasterLayer' | 'image' | 'MaskLayer' | 'TileDebugLayer';
10
- export declare function getTileFactory(layer: ILayer): typeof DebugTile | typeof ImageTile | typeof VectorTile | typeof MaskLayer | typeof RasterRGBTile | typeof RasterTile | typeof RasterTerrainRGBTile;
10
+ export declare function getTileFactory(layer: ILayer): typeof DebugTile | typeof ImageTile | typeof MaskLayer | typeof RasterRGBTile | typeof RasterTerrainRGBTile | typeof RasterTile | typeof VectorTile;
11
11
  export * from '../interface';
12
12
  export * from './Tile';
@@ -80,6 +80,7 @@ export interface IPointLayerStyleOptions extends IBaseLayerStyleOptions {
80
80
  fontWeight?: string;
81
81
  fontFamily?: string;
82
82
  textAllowOverlap?: boolean;
83
+ allowOverlap?: boolean;
83
84
  pickLight?: boolean;
84
85
  sourceColor?: string;
85
86
  targetColor?: string;
@@ -139,6 +139,17 @@ function PointExtrudeTriangulation(feature) {
139
139
  * @param feature 映射feature
140
140
  */
141
141
  function PointImageTriangulation(feature) {
142
+ // @ts-ignore
143
+ const that = this;
144
+ const id = feature.id;
145
+ // 当 imageFilterMap 存在且该 feature 未通过碰撞检测时,返回空几何(等效隐藏)
146
+ if (that !== null && that !== void 0 && that.imageFilterMap && !that.imageFilterMap[id]) {
147
+ return {
148
+ vertices: [],
149
+ indices: [],
150
+ size: 3
151
+ };
152
+ }
142
153
  const coordinates = (0, _l7Utils.calculateCentroid)(feature.coordinates);
143
154
  return {
144
155
  vertices: [...coordinates],
@@ -12,4 +12,4 @@ import RegisterStyleAttributePlugin from './RegisterStyleAttributePlugin';
12
12
  import ShaderUniformPlugin from './ShaderUniformPlugin';
13
13
  import UpdateModelPlugin from './UpdateModelPlugin';
14
14
  import UpdateStyleAttributePlugin from './UpdateStyleAttributePlugin';
15
- export declare function createPlugins(): (DataSourcePlugin | RegisterStyleAttributePlugin | FeatureScalePlugin | DataMappingPlugin | LayerStylePlugin | LayerMaskPlugin | UpdateStyleAttributePlugin | UpdateModelPlugin | MultiPassRendererPlugin | ShaderUniformPlugin | LayerAnimateStylePlugin | LightingPlugin | PixelPickingPlugin | LayerModelPlugin)[];
15
+ export declare function createPlugins(): (DataMappingPlugin | DataSourcePlugin | FeatureScalePlugin | LayerAnimateStylePlugin | LayerMaskPlugin | LayerModelPlugin | LayerStylePlugin | LightingPlugin | MultiPassRendererPlugin | PixelPickingPlugin | RegisterStyleAttributePlugin | ShaderUniformPlugin | UpdateModelPlugin | UpdateStyleAttributePlugin)[];
@@ -1,3 +1,4 @@
1
+ import type { ILayer, ILayerConfig } from '@antv/l7-core';
1
2
  import BaseLayer from '../core/BaseLayer';
2
3
  import type { IPointLayerStyleOptions } from '../core/interface';
3
4
  import type { PointType } from './models/index';
@@ -17,6 +18,7 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
17
18
  };
18
19
  buildModels(): Promise<void>;
19
20
  rebuildModels(): Promise<void>;
21
+ style(options: Partial<IPointLayerStyleOptions> & Partial<ILayerConfig>): ILayer;
20
22
  /**
21
23
  * 在未传入数据的时候判断点图层的 shape 类型
22
24
  * @returns
@@ -44,6 +44,16 @@ class PointLayer extends _BaseLayer.default {
44
44
  yield _this2.buildModels();
45
45
  })();
46
46
  }
47
+ style(options) {
48
+ super.style(options);
49
+ // allowOverlap 依赖 needUpdate() 感知变化并重建 model,而 needUpdate() 仅在渲染帧的
50
+ // beforeRender 钩子中被调用。style() 本身不触发渲染,因此在 allowOverlap 出现时
51
+ // 主动触发一次 reRender,确保静止地图下也能即时生效。
52
+ if ('allowOverlap' in options) {
53
+ this.reRender();
54
+ }
55
+ return this;
56
+ }
47
57
 
48
58
  /**
49
59
  * 在未传入数据的时候判断点图层的 shape 类型
@@ -57,7 +57,7 @@ class FillModel extends _BaseModel.default {
57
57
  } = this.layer.getLayerConfig();
58
58
  return {
59
59
  u_animate: this.animateOption2Array(animateOption),
60
- u_time: this.layer.getLayerAnimateTime()
60
+ u_time: animateOption.enable ? this.layer.getLayerAnimateTime() : -1.0
61
61
  };
62
62
  }
63
63
  getAttribute() {
@@ -17,6 +17,12 @@ export default class ImageModel extends BaseModel {
17
17
  UV: number;
18
18
  };
19
19
  private texture;
20
+ imageFilterMap: {
21
+ [key: number]: boolean;
22
+ } | null;
23
+ private currentZoom;
24
+ private extent;
25
+ private preAllowOverlap;
20
26
  getUninforms(): IModelUniform;
21
27
  protected getCommonUniformsInfo(): {
22
28
  uniformsArray: number[];
@@ -26,8 +32,17 @@ export default class ImageModel extends BaseModel {
26
32
  };
27
33
  };
28
34
  initModels(): Promise<IModel[]>;
29
- clearModels(): void;
30
35
  buildModels(): Promise<IModel[]>;
36
+ needUpdate(): Promise<boolean>;
37
+ clearModels(): void;
31
38
  protected registerBuiltinAttributes(): void;
39
+ /**
40
+ * 图标碰撞避让:遍历所有 feature,在屏幕空间做 AABB 碰撞检测,
41
+ * 将通过检测的 feature id 写入 imageFilterMap。
42
+ * PointImageTriangulation 绑定 this 后,会跳过不在 map 中的 feature。
43
+ */
44
+ private filterImages;
45
+ private imageExtent;
46
+ private reBuildModel;
32
47
  private updateTexture;
33
48
  }
@@ -9,8 +9,10 @@ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/
9
9
  var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
11
  var _l7Core = require("@antv/l7-core");
12
+ var _l7Utils = require("@antv/l7-utils");
12
13
  var _BaseModel = _interopRequireDefault(require("../../core/BaseModel"));
13
14
  var _triangulation = require("../../core/triangulation");
15
+ var _collisionIndex = _interopRequireDefault(require("../../utils/collision-index"));
14
16
  /* babel-plugin-inline-import '../shaders/image/image_frag.glsl' */
15
17
  const pointImageFrag = "layout(std140) uniform commonUniforms {\n vec2 u_textSize;\n float u_raisingHeight;\n float u_heightfixed;\n};\n\nuniform sampler2D u_texture;\n\nin vec4 v_color;\nin vec2 v_uv;\nin float v_opacity;\n\n#pragma include \"picking\"\n\nout vec4 outputColor;\n\nvoid main() {\n vec2 pos = v_uv / u_textSize + gl_PointCoord / u_textSize * 64.0;\n vec4 textureColor;\n\n // Y = 0.299R + 0.587G + 0.114B // \u4EAE\u5EA6\u63D0\u53D6\n\n textureColor = texture(SAMPLER_2D(u_texture), pos);\n\n // Tip: \u53BB\u9664\u8FB9\u7F18\u90E8\u5206 mipmap \u5BFC\u81F4\u7684\u6DF7\u5408\u53D8\u6697\n float fragmengTocenter = distance(vec2(0.5), gl_PointCoord);\n if (fragmengTocenter >= 0.5) {\n float luma = 0.299 * textureColor.r + 0.587 * textureColor.g + 0.114 * textureColor.b;\n textureColor.a *= luma;\n }\n\n if (\n all(lessThan(v_color, vec4(1.0 + 0.00001))) && all(greaterThan(v_color, vec4(1.0 - 0.00001))) ||\n v_color == vec4(1.0)\n ) {\n outputColor = textureColor;\n } else {\n outputColor = step(0.01, textureColor.z) * v_color;\n }\n outputColor.a *= v_opacity;\n if (outputColor.a < 0.01) {\n discard;\n }\n outputColor = filterColor(outputColor);\n}\n";
16
18
  /* babel-plugin-inline-import '../shaders/image/image_vert.glsl' */
@@ -19,6 +21,11 @@ class ImageModel extends _BaseModel.default {
19
21
  constructor(...args) {
20
22
  super(...args);
21
23
  (0, _defineProperty2.default)(this, "texture", void 0);
24
+ // 通过碰撞检测的 feature id 集合,由 filterImages() 填充;null 表示不启用过滤(allowOverlap: true)
25
+ (0, _defineProperty2.default)(this, "imageFilterMap", null);
26
+ (0, _defineProperty2.default)(this, "currentZoom", -1);
27
+ (0, _defineProperty2.default)(this, "extent", void 0);
28
+ (0, _defineProperty2.default)(this, "preAllowOverlap", true);
22
29
  (0, _defineProperty2.default)(this, "updateTexture", () => {
23
30
  const {
24
31
  createTexture2D
@@ -85,25 +92,35 @@ class ImageModel extends _BaseModel.default {
85
92
  initModels() {
86
93
  var _this = this;
87
94
  return (0, _asyncToGenerator2.default)(function* () {
95
+ const {
96
+ allowOverlap = true
97
+ } = _this.layer.getLayerConfig();
98
+ _this.extent = _this.imageExtent();
99
+ _this.preAllowOverlap = allowOverlap;
88
100
  _this.iconService.on('imageUpdate', _this.updateTexture);
89
101
  _this.updateTexture();
90
102
  return _this.buildModels();
91
103
  })();
92
104
  }
93
- clearModels() {
94
- var _this$texture2;
95
- (_this$texture2 = this.texture) === null || _this$texture2 === void 0 || _this$texture2.destroy();
96
- this.iconService.off('imageUpdate', this.updateTexture);
97
- }
98
105
  buildModels() {
99
106
  var _this2 = this;
100
107
  return (0, _asyncToGenerator2.default)(function* () {
108
+ const {
109
+ allowOverlap = true
110
+ } = _this2.layer.getLayerConfig();
101
111
  _this2.initUniformsBuffer();
112
+ if (!allowOverlap) {
113
+ _this2.filterImages();
114
+ } else {
115
+ // 允许压盖时置 null,PointImageTriangulation 检测到 null 则跳过过滤
116
+ _this2.imageFilterMap = null;
117
+ }
102
118
  const model = yield _this2.layer.buildLayerModel({
103
119
  moduleName: 'pointImage',
104
120
  vertexShader: pointImageVert,
105
121
  fragmentShader: pointImageFrag,
106
- triangulation: _triangulation.PointImageTriangulation,
122
+ // 绑定 this,让 PointImageTriangulation 能读取 imageFilterMap
123
+ triangulation: _triangulation.PointImageTriangulation.bind(_this2),
107
124
  defines: _this2.getDefines(),
108
125
  inject: _this2.getInject(),
109
126
  depth: {
@@ -114,6 +131,41 @@ class ImageModel extends _BaseModel.default {
114
131
  return [model];
115
132
  })();
116
133
  }
134
+ needUpdate() {
135
+ var _this3 = this;
136
+ return (0, _asyncToGenerator2.default)(function* () {
137
+ const {
138
+ allowOverlap = true
139
+ } = _this3.layer.getLayerConfig();
140
+
141
+ // allowOverlap 开关发生变化时,强制重建
142
+ if (allowOverlap !== _this3.preAllowOverlap) {
143
+ _this3.preAllowOverlap = allowOverlap;
144
+ yield _this3.reBuildModel();
145
+ return true;
146
+ }
147
+
148
+ // 允许压盖时无需每帧检测
149
+ if (allowOverlap) {
150
+ return false;
151
+ }
152
+
153
+ // 不允许压盖时,zoom 变化 >0.5 或视野超出上次范围则重算碰撞
154
+ const zoom = _this3.mapService.getZoom();
155
+ const extent = _this3.mapService.getBounds();
156
+ const flag = (0, _l7Utils.boundsContains)(_this3.extent, extent);
157
+ if (Math.abs(_this3.currentZoom - zoom) > 0.5 || !flag) {
158
+ yield _this3.reBuildModel();
159
+ return true;
160
+ }
161
+ return false;
162
+ })();
163
+ }
164
+ clearModels() {
165
+ var _this$texture2;
166
+ (_this$texture2 = this.texture) === null || _this$texture2 === void 0 || _this$texture2.destroy();
167
+ this.iconService.off('imageUpdate', this.updateTexture);
168
+ }
117
169
  registerBuiltinAttributes() {
118
170
  // 注册 Position 属性 64 位地位部分,经纬度数据开启双精度,避免大于 20层级以上出现数据偏移
119
171
  this.registerPosition64LowAttribute();
@@ -172,5 +224,78 @@ class ImageModel extends _BaseModel.default {
172
224
  }
173
225
  });
174
226
  }
227
+
228
+ /**
229
+ * 图标碰撞避让:遍历所有 feature,在屏幕空间做 AABB 碰撞检测,
230
+ * 将通过检测的 feature id 写入 imageFilterMap。
231
+ * PointImageTriangulation 绑定 this 后,会跳过不在 map 中的 feature。
232
+ */
233
+ filterImages() {
234
+ const {
235
+ padding = [0, 0]
236
+ } = this.layer.getLayerConfig();
237
+ this.imageFilterMap = {};
238
+ this.currentZoom = this.mapService.getZoom();
239
+ this.extent = this.imageExtent();
240
+ const {
241
+ width,
242
+ height
243
+ } = this.rendererService.getViewportSize();
244
+ const collisionIndex = new _collisionIndex.default(width, height);
245
+ const data = this.layer.getEncodedData();
246
+ data.forEach(feature => {
247
+ const {
248
+ id = 0,
249
+ size = 5
250
+ } = feature;
251
+ const iconSize = Array.isArray(size) ? size[0] : size;
252
+ const centroid = (0, _l7Utils.calculateCentroid)(feature.coordinates);
253
+ const pixels = this.mapService.lngLatToContainer(centroid);
254
+ const {
255
+ box
256
+ } = collisionIndex.placeCollisionBox({
257
+ x1: -iconSize - padding[0],
258
+ x2: iconSize + padding[0],
259
+ y1: -iconSize - padding[1],
260
+ y2: iconSize + padding[1],
261
+ anchorPointX: pixels.x,
262
+ anchorPointY: pixels.y
263
+ });
264
+ if (box && box.length) {
265
+ collisionIndex.insertCollisionBox(box, id);
266
+ this.imageFilterMap[id] = true;
267
+ }
268
+ });
269
+ }
270
+ imageExtent() {
271
+ const bounds = this.mapService.getBounds();
272
+ return (0, _l7Utils.padBounds)(bounds, 0.5);
273
+ }
274
+ reBuildModel() {
275
+ var _this4 = this;
276
+ return (0, _asyncToGenerator2.default)(function* () {
277
+ const {
278
+ allowOverlap = true
279
+ } = _this4.layer.getLayerConfig();
280
+ if (!allowOverlap) {
281
+ _this4.filterImages();
282
+ } else {
283
+ _this4.imageFilterMap = null; // 允许压盖:清空过滤表,全量渲染
284
+ }
285
+ const model = yield _this4.layer.buildLayerModel({
286
+ moduleName: 'pointImage',
287
+ vertexShader: pointImageVert,
288
+ fragmentShader: pointImageFrag,
289
+ triangulation: _triangulation.PointImageTriangulation.bind(_this4),
290
+ defines: _this4.getDefines(),
291
+ inject: _this4.getInject(),
292
+ depth: {
293
+ enable: false
294
+ },
295
+ primitive: _l7Core.gl.POINTS
296
+ });
297
+ _this4.layer.models = [model];
298
+ })();
299
+ }
175
300
  }
176
301
  exports.default = ImageModel;
@@ -47,7 +47,7 @@ export default abstract class Tile extends EventEmitter implements ITile {
47
47
  enablePropagation?: boolean | undefined;
48
48
  fitBoundsOptions?: unknown;
49
49
  name?: string | undefined;
50
- blend?: "normal" | "additive" | "subtractive" | "min" | "max" | "none" | undefined;
50
+ blend?: "min" | "max" | "normal" | "additive" | "subtractive" | "none" | undefined;
51
51
  depth?: boolean | undefined;
52
52
  pickedFeatureID?: number | undefined;
53
53
  enableMultiPassRenderer?: boolean | undefined;
@@ -7,6 +7,6 @@ import RasterTerrainRGBTile from './RasterTerrainRGBTile';
7
7
  import RasterTile from './RasterTile';
8
8
  import VectorTile from './VectorTile';
9
9
  export type TileType = 'VectorTile' | 'DebugTile' | 'PolygonLayer' | 'PointLayer' | 'LineLayer' | 'RasterLayer' | 'image' | 'MaskLayer' | 'TileDebugLayer';
10
- export declare function getTileFactory(layer: ILayer): typeof DebugTile | typeof ImageTile | typeof VectorTile | typeof MaskLayer | typeof RasterRGBTile | typeof RasterTile | typeof RasterTerrainRGBTile;
10
+ export declare function getTileFactory(layer: ILayer): typeof DebugTile | typeof ImageTile | typeof MaskLayer | typeof RasterRGBTile | typeof RasterTerrainRGBTile | typeof RasterTile | typeof VectorTile;
11
11
  export * from '../interface';
12
12
  export * from './Tile';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antv/l7-layers",
3
- "version": "2.24.0",
3
+ "version": "2.24.2",
4
4
  "description": "L7's collection of built-in layers",
5
5
  "license": "MIT",
6
6
  "author": "https://github.com/orgs/antvis/people",
@@ -26,15 +26,15 @@
26
26
  "earcut": "^2.2.1",
27
27
  "eventemitter3": "^4.0.0",
28
28
  "gl-matrix": "^3.1.0",
29
- "@antv/l7-maps": "2.24.0",
30
- "@antv/l7-utils": "2.24.0",
31
- "@antv/l7-core": "2.24.0",
32
- "@antv/l7-source": "2.24.0"
29
+ "@antv/l7-maps": "2.24.2",
30
+ "@antv/l7-source": "2.24.2",
31
+ "@antv/l7-core": "2.24.2",
32
+ "@antv/l7-utils": "2.24.2"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/earcut": "^2.1.0",
36
36
  "@types/gl-matrix": "^2.4.5",
37
- "@antv/l7-test-utils": "^2.24.0"
37
+ "@antv/l7-test-utils": "^2.24.2"
38
38
  },
39
39
  "publishConfig": {
40
40
  "access": "public",