• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

antvis / L7Plot / 3763448570

pending completion
3763448570

Pull #262

github

GitHub
Merge 3128c703f into da129e8ec
Pull Request #262: refactor: 图层属性更新逻辑性能优化

723 of 1953 branches covered (37.02%)

Branch coverage included in aggregate %.

8 of 8 new or added lines in 1 file covered. (100.0%)

3049 of 4601 relevant lines covered (66.27%)

177.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

38.12
/packages/composite-layers/src/core/composite-layer.ts
1
import { isUndefined, uniqueId } from '@antv/util';
2
import EventEmitter from '@antv/event-emitter';
42✔
3
import { ILegend, Source } from '@antv/l7';
42✔
4
import { deepMergeLayerOptions, isSourceChanged } from '../utils';
42✔
5
import { Scene, SourceOptions, ICompositeLayer, CompositeLayerType, LayerBlend, ICoreLayer, ISource } from '../types';
42✔
6
import { CompositeLayerEvent, LayerGroupEvent, OriginLayerEventList } from './constants';
42✔
7
import { LayerGroup } from './layer-group';
42✔
8

42✔
9
/**
42✔
10
 * 复合图层的基础配置
42✔
11
 */
42✔
12
export interface CompositeLayerOptions {
42✔
13
  /** 图层名称 */
42✔
14
  name?: string;
15
  /** 图层 ID */
41✔
16
  id?: string;
17
  /** 图层 zIndex */
18
  zIndex?: number;
19
  /**
41✔
20
   * 图层是否可见
41✔
21
   * @default true
41!
22
   */
41!
23
  visible?: boolean;
41✔
24
  /** 图层最小可见层级 */
41✔
25
  minZoom?: number;
41✔
26
  /** 图层最大可见层级 */
41✔
27
  maxZoom?: number;
41✔
28
  /**
41✔
29
   * 图层拾取缓存配置,
41✔
30
   * 如 1px 宽度的线鼠标很难拾取到, 通过设置该参数可扩大拾取的范围
31
   * @default 0
32
   * */
33
  pickingBuffer?: number;
34
  /**
42✔
35
   * 图层加载成功后是否自动定位到图层数据可见范围,注意开启后图层数据发生更新时,地图也会自动缩放到图层的数据边界范围
×
36
   * @default false
37
   */
38
  autoFit?: boolean;
39
  /**
40
   * 图层元素混合效果
42✔
41
   * @default 'normal'
41✔
42
   * */
41✔
43
  blend?: LayerBlend;
41!
44
  /** 数据配置 */
41✔
45
  source: {
46
    /** 数据 */
47
    data: any;
48
  };
49
}
42✔
50

41!
51
export abstract class CompositeLayer<O extends CompositeLayerOptions> extends EventEmitter implements ICompositeLayer {
×
52
  /**
53
   * 复合图层类型
41✔
54
   */
55
  static LayerType = CompositeLayerType;
56
  /**
57
   * 默认的 options 配置项
58
   */
59
  static DefaultOptions: Partial<CompositeLayerOptions> = {};
42✔
60
  /**
×
61
   * 是否是复合图层
62
   */
63
  public readonly isComposite = true;
64
  /**
65
   * 复合图层名称
42✔
66
   */
67
  public readonly name: string;
68
  /**
69
   * 图层 ID
70
   */
71
  public readonly id: string;
42✔
72
  /**
×
73
   * 复合图层类型
×
74
   */
×
75
  public abstract readonly type: CompositeLayerType | string;
×
76
  /**
×
77
   * 复合图层的 schema 配置
78
   */
×
79
  public options: O;
80
  /**
81
   * 复合图层上一次的 schema 配置
82
   */
83
  public lastOptions: O;
42✔
84
  /**
×
85
   * Scene 实例
×
86
   */
×
87
  protected scene: Scene | undefined;
×
88
  /**
89
   * 主子图层实例
90
   */
91
  protected abstract readonly layer: ICoreLayer;
92
  /**
42✔
93
   * 图层间共享 source 实例
94
   */
×
95
  public source!: ISource;
×
96
  /**
97
   * 子图层组
×
98
   */
×
99
  public subLayers: LayerGroup;
100

101
  constructor(options: O) {
×
102
    super();
×
103
    const { id, name } = options;
104
    this.id = id ? id : uniqueId('composite-layer');
105
    this.name = name ? name : this.id;
×
106
    this.options = deepMergeLayerOptions<O>(this.getDefaultOptions() as O, options);
×
107
    this.lastOptions = this.options;
×
108
    this.source = this.createSource();
×
109
    const layers = this.createSubLayers();
110
    this.subLayers = new LayerGroup(layers);
111

112
    this.emit(CompositeLayerEvent.CREATED, this);
113
  }
114

42✔
115
  /**
×
116
   * 获取默认配置
×
117
   */
118
  public getDefaultOptions(): Partial<CompositeLayerOptions> {
42✔
119
    return CompositeLayer.DefaultOptions;
×
120
  }
×
121

122
  /**
123
   * 创建图层间共享 source 方法
124
   */
125
  protected createSource() {
126
    const sourceOptions = this.options.source;
42✔
127

×
128
    const { data, ...sourceCFG } = sourceOptions;
129
    const source = this.isSourceInstance(sourceOptions) ? sourceOptions : new Source(data, sourceCFG);
130
    return source;
131
  }
132

42✔
133
  /**
×
134
   * 判断 source 是否是实例工具方法
135
   */
136
  protected isSourceInstance(source: SourceOptions | ISource): source is ISource {
137
    if (source instanceof Source) {
138
      return true;
42✔
139
    }
×
140
    return false;
141
  }
142

143
  /**
144
   * 创建子图层
42✔
145
   */
×
146
  protected abstract createSubLayers(): ICoreLayer[];
×
147

148
  /**
149
   * 设置子图层数据
150
   *支持 source 配置项与 source 实例更新
151
   */
152
  protected setSubLayersSource(source: SourceOptions | ISource) {
42✔
153
    this.layer.changeData(source);
×
154
  }
×
155

156
  /**
157
   * 初始化子图层相关事件绑定
158
   */
159
  protected initSubLayersEvent(): void {
160
    //
42✔
161
  }
×
162

×
163
  /**
164
   * 添加到场景
165
   */
×
166
  public addTo(scene: Scene) {
167
    this.scene = scene;
168
    this.subLayers.once(LayerGroupEvent.INITED_LAYERS, () => {
169
      this.emit(CompositeLayerEvent.INITED, this);
170
      this.emit(CompositeLayerEvent.ADD, this);
42✔
171
    });
×
172
    this.subLayers.addTo(scene);
×
173
  }
174

175
  /**
×
176
   * 从场景移除
177
   */
178
  public remove() {
179
    if (!this.scene) return;
180
    this.subLayers.remove();
42✔
181
    this.emit(CompositeLayerEvent.REMOVE);
×
182
  }
183

184
  /**
185
   * 更新
186
   */
42✔
187
  public update(options: Partial<O>, autoRender = true) {
×
188
    this.updateOption(options);
189

190
    // 停止渲染,避免属性更新与数据更新造成多次内部调用 scene render => renderLayers
191
    if (autoRender) {
192
      this.scene?.setEnableRender(false);
42✔
193
    }
×
194

195
    // 数据更新
196
    if (options.source && isSourceChanged(options.source, this.lastOptions.source)) {
197
      this.changeData(options.source);
198
    }
42✔
199

×
200
    // 图层更新
201
    this.updateSubLayers(options);
202

203
    if (autoRender) {
204
      this.scene?.setEnableRender(true);
42✔
205
      this.render();
×
206
    }
207
  }
208

209
  /**
210
   * 更新: 更新配置
42✔
211
   */
×
212
  public updateOption(options: Partial<O>) {
213
    this.lastOptions = this.options;
214

215
    this.options = deepMergeLayerOptions<O>(this.options, options);
216
  }
42✔
217

×
218
  /**
×
219
   * 更新子图层
×
220
   */
×
221
  protected abstract updateSubLayers(options: Partial<O>): void;
222

×
223
  public render() {
224
    if (this.scene) {
225
      this.scene.render();
226
    }
227
  }
228

42✔
229
  /**
×
230
   * 更新数据
×
231
   */
232
  public changeData(source: SourceOptions) {
233
    this.setSubLayersSource(source);
234
  }
235

42✔
236
  /**
×
237
   * 设置图层 zIndex
238
   */
239
  public setIndex(zIndex: number) {
240
    this.subLayers.setZIndex(zIndex);
241
  }
42✔
242

×
243
  /**
×
244
   * 设置图层 blend
245
   */
246
  public setBlend(blend: LayerBlend) {
×
247
    this.layer.setBlend(blend);
248
  }
×
249

250
  /**
251
   * 设置图层 minZoom
252
   */
253
  public setMinZoom(minZoom: number) {
42✔
254
    this.subLayers.getLayers().forEach((layer) => {
×
255
      layer.setMinZoom(minZoom);
×
256
    });
257
  }
258

×
259
  /**
260
   * 设置图层 maxZoom
×
261
   */
262
  public setMaxZoom(maxZoom: number) {
263
    this.subLayers.getLayers().forEach((layer) => {
264
      layer.setMaxZoom(maxZoom);
265
    });
42✔
266
  }
×
267

×
268
  /**
269
   * 显示图层
270
   */
×
271
  public show() {
272
    if (!this.layer.inited) return;
×
273
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
274
    //@ts-ignore
275
    this.update({ visible: true });
276
  }
277

42✔
278
  /**
279
   * 隐藏图层
280
   */
281
  public hide() {
42✔
282
    if (!this.layer.inited) return;
42✔
283
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
284
    //@ts-ignore
42✔
285
    this.update({ visible: false });
286
  }
287

288
  /**
289
   * 切换图层显隐状态
290
   */
291
  public toggleVisible() {
292
    this.isVisible() ? this.hide() : this.show();
293
  }
294

295
  /**
296
   * 图层是否可见
297
   */
298
  public isVisible() {
299
    return this.layer.inited ? this.layer.isVisible() : isUndefined(this.options.visible) ? true : this.options.visible;
300
  }
301

302
  /**
303
   * 图层框选数据
304
   */
305
  public boxSelect(bounds: [number, number, number, number], callback: (...args: any[]) => void) {
306
    this.layer.boxSelect(bounds, callback);
307
  }
308

309
  /**
310
   * 定位到当前图层数据范围
311
   */
312
  public fitBounds(fitBoundsOptions?: unknown) {
313
    this.layer.fitBounds(fitBoundsOptions);
314
  }
315

316
  /**
317
   * 获取图例
318
   */
319
  public getLegend(name: string): ILegend {
320
    return this.layer.getLegend(name);
321
  }
322

323
  /**
324
   * 获取图例数据
325
   */
326
  public getLegendItems(type: string): Record<string, any>[] {
327
    return this.layer.getLegendItems(type);
328
  }
329

330
  /**
331
   * 获取颜色图例数据
332
   */
333
  public getColorLegendItems(): Record<string, any>[] {
334
    const colorLegendItems = this.layer.getLegendItems('color');
335
    if (Array.isArray(colorLegendItems) && colorLegendItems.length !== 0) {
336
      const items = colorLegendItems;
337
      return items;
338
    }
339

340
    return [];
341
  }
342

343
  /**
344
   * 获取带有交互的子图层
345
   * 一般用于是否启用 tooltip,图层事件绑定
346
   */
347
  public getInteractionSubLayers(): ICoreLayer[] {
348
    const layers = this.subLayers.getLayers().filter((layer) => layer.interaction === true);
349

350
    return layers;
351
  }
352

353
  /**
354
   * 摧毁
355
   */
356
  public destroy() {
357
    this.subLayers.destroy();
358
  }
359

360
  /**
361
   * 事件代理: 绑定事件
362
   */
363
  public on(name: string, callback: (...args: any[]) => void, once?: boolean) {
364
    if (OriginLayerEventList.indexOf(name) !== -1) {
365
      this.layer.on(name, callback);
366
    } else {
367
      super.on(name, callback, once);
368
    }
369
    return this;
370
  }
371

372
  /**
373
   * 事件代理: 绑定一次事件
374
   */
375
  public once(name: string, callback: (...args: any[]) => void) {
376
    if (OriginLayerEventList.indexOf(name) !== -1) {
377
      this.layer.once(name, callback);
378
    } else {
379
      super.once(name, callback);
380
    }
381
    return this;
382
  }
383

384
  /**
385
   * 事件代理: 解绑事件
386
   */
387
  public off(name: string, callback: (...args: any[]) => void) {
388
    if (OriginLayerEventList.indexOf(name) !== -1) {
389
      this.layer.off(name, callback);
390
    } else {
391
      super.off(name, callback);
392
    }
393
    return this;
394
  }
395
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc