Jinuss's blog Jinuss's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

前端可视化
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 核心基类

  • Control控件篇

  • Geom几何图形篇

  • Layer图层篇

    • 概览
    • BaseLayer类介绍
    • Layer类介绍
      • 概述
      • 源码剖析
        • Layer类的构造函数
        • Layer类的其它函数
      • 总结
    • BaseVectorLayer类
    • VectorLayer类
  • Renderer篇

  • Feature篇

  • style样式篇

  • 《Openlayers源码》笔记
  • Layer图层篇
东流
2024-12-04
目录

Layer类介绍

# 概述

本文将介绍Layer类,该类是所有图层类型都会继承的基类,一般情况下,在添加自定义图层,并使用自定义的render函数时,该类才应该被实例化。

# 源码剖析

Layer类继承于BaseLayer类,在前面提过BaseLayer类主要是设置对象的一些属性值,以及提供GET和SET两类方法。Layer类的实现如下:

class Layer extends BaseLayer {
  constructor(options) {
    const baseOptions = Object.assign({}, options);
    delete baseOptions.source;

    super(baseOptions);
    this.on;
    this.once;
    this.un;
    this.mapPrecomposeKey_ = null;
    this.mapRenderKey_ = null;
    this.sourceChangeKey_ = null;
    this.renderer_ = null;
    this.sourceReady_ = false;
    this.rendered = false;
    if (options.render) {
      this.render = options.render;
    }

    if (options.map) {
      this.setMap(options.map);
    }

    this.addChangeListener(
      LayerProperty.SOURCE,
      this.handleSourcePropertyChange_
    );

    const source = options.source ? options.source : null;
    this.setSource(source);
  }

  getLayersArray(array) {
    array = array ? array : [];
    array.push(this);
    return array;
  }
  getLayerStatesArray(states) {
    states = states ? states : [];
    states.push(this.getLayerState());
    return states;
  }
  getSource() {
    return this.get(LayerProperty.SOURCE) || null;
  }
  getRenderSource() {
    return this.getSource();
  }
  getSourceState() {
    const source = this.getSource();
    return !source ? "undefined" : source.getState();
  }

  handleSourceChange_() {
    this.changed();
    if (this.sourceReady_ || this.getSource().getState() !== "ready") {
      return;
    }
    this.sourceReady_ = true;
    this.dispatchEvent("sourceready");
  }

  handleSourcePropertyChange_() {
    if (this.sourceChangeKey_) {
      unlistenByKey(this.sourceChangeKey_);
      this.sourceChangeKey_ = null;
    }
    this.sourceReady_ = false;
    const source = this.getSource();
    if (source) {
      this.sourceChangeKey_ = listen(
        source,
        EventType.CHANGE,
        this.handleSourceChange_,
        this
      );
      if (source.getState() === "ready") {
        this.sourceReady_ = true;
        setTimeout(() => {
          this.dispatchEvent("sourceready");
        }, 0);
      }
    }
    this.changed();
  }

  getFeatures(pixel) {
    if (!this.renderer_) {
      return Promise.resolve([]);
    }
    return this.renderer_.getFeatures(pixel);
  }

  getData(pixel) {
    if (!this.renderer_ || !this.rendered) {
      return null;
    }
    return this.renderer_.getData(pixel);
  }
  isVisible(view) {
    let frameState;
    const map = this.getMapInternal();
    if (!view && map) {
      view = map.getView();
    }
    if (view instanceof View) {
      frameState = {
        viewState: view.getState(),
        extent: view.calculateExtent(),
      };
    } else {
      frameState = view;
    }
    if (!frameState.layerStatesArray && map) {
      frameState.layerStatesArray = map.getLayerGroup().getLayerStatesArray();
    }
    let layerState;
    if (frameState.layerStatesArray) {
      layerState = frameState.layerStatesArray.find(
        (layerState) => layerState.layer === this
      );
    } else {
      layerState = this.getLayerState();
    }

    const layerExtent = this.getExtent();

    return (
      inView(layerState, frameState.viewState) &&
      (!layerExtent || intersects(layerExtent, frameState.extent))
    );
  }

  getAttributions(view) {
    if (!this.isVisible(view)) {
      return [];
    }
    const getAttributions = this.getSource()?.getAttributions();
    if (!getAttributions) {
      return [];
    }
    const frameState =
      view instanceof View ? view.getViewStateAndExtent() : view;
    let attributions = getAttributions(frameState);
    if (!Array.isArray(attributions)) {
      attributions = [attributions];
    }
    return attributions;
  }

  render(frameState, target) {
    const layerRenderer = this.getRenderer();

    if (layerRenderer.prepareFrame(frameState)) {
      this.rendered = true;
      return layerRenderer.renderFrame(frameState, target);
    }
    return null;
  }

  unrender() {
    this.rendered = false;
  }
  getDeclutter() {
    return undefined;
  }
  renderDeclutter(frameState, layerState) {}

  renderDeferred(frameState) {
    const layerRenderer = this.getRenderer();
    if (!layerRenderer) {
      return;
    }
    layerRenderer.renderDeferred(frameState);
  }
  setMapInternal(map) {
    if (!map) {
      this.unrender();
    }
    this.set(LayerProperty.MAP, map);
  }

  getMapInternal() {
    return this.get(LayerProperty.MAP);
  }

  setMap(map) {
    if (this.mapPrecomposeKey_) {
      unlistenByKey(this.mapPrecomposeKey_);
      this.mapPrecomposeKey_ = null;
    }
    if (!map) {
      this.changed();
    }
    if (this.mapRenderKey_) {
      unlistenByKey(this.mapRenderKey_);
      this.mapRenderKey_ = null;
    }
    if (map) {
      this.mapPrecomposeKey_ = listen(
        map,
        RenderEventType.PRECOMPOSE,
        this.handlePrecompose_,
        this
      );
      this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
      this.changed();
    }
  }

  handlePrecompose_(renderEvent) {
    const layerStatesArray = renderEvent.frameState.layerStatesArray;
    const layerState = this.getLayerState(false);
    assert(
      !layerStatesArray.some(
        (arrayLayerState) => arrayLayerState.layer === layerState.layer
      ),
      "A layer can only be added to the map once. Use either `layer.setMap()` or `map.addLayer()`, not both."
    );
    layerStatesArray.push(layerState);
  }

  setSource(source) {
    this.set(LayerProperty.SOURCE, source);
  }

  getRenderer() {
    if (!this.renderer_) {
      this.renderer_ = this.createRenderer();
    }
    return this.renderer_;
  }

  hasRenderer() {
    return !!this.renderer_;
  }

  createRenderer() {
    return null;
  }
  disposeInternal() {
    if (this.renderer_) {
      this.renderer_.dispose();
      delete this.renderer_;
    }

    this.setSource(null);
    super.disposeInternal();
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

# Layer类的构造函数

Layer类构造函数接受一个参数Options对象将其赋值给变量baseOptions,并删除baseOptions的source属性,通过super(baseOptions)初始化父类;然后初始化了几个变量;

然后判断options.render是否存在,若存在则赋值给this.render,覆盖Layer类中的render方法;判断options.map是否存在,若存在,则调用this.setMap方法,如下:

  • render方法
  render(frameState, target) {
    const layerRenderer = this.getRenderer();

    if (layerRenderer.prepareFrame(frameState)) {
      this.rendered = true;
      return layerRenderer.renderFrame(frameState, target);
    }
    return null;
  }
1
2
3
4
5
6
7
8
9

render方法的作用就是负责渲染图层,每种类型的图层都有之与其对应的图层渲染器。它接受两个参数帧状态frameState和目标容器target。render方法内部就是获取调用getRenderer获取图层渲染器,然后判断layerRenderer.prepareFrame(frameState)是否准备渲染帧,若返回true,则修改this.rendered值为true,调用layerRenderer.renderFrame(frameState, target)将帧渲染到target即网页容器中;若返回false,则render方法返回null

  • setMap方法
  setMap(map) {
    if (this.mapPrecomposeKey_) {
      unlistenByKey(this.mapPrecomposeKey_);
      this.mapPrecomposeKey_ = null;
    }
    if (!map) {
      this.changed();
    }
    if (this.mapRenderKey_) {
      unlistenByKey(this.mapRenderKey_);
      this.mapRenderKey_ = null;
    }
    if (map) {
      this.mapPrecomposeKey_ = listen(
        map,
        RenderEventType.PRECOMPOSE,
        this.handlePrecompose_,
        this,
      );
      this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
      this.changed();
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

setMap方法在Layer类中调用时,参数map肯定存在,因此现阶段只讨论map存在的情况;map存在时,会调用listen方法注册postcompose类型的this.handlePrecompose_事件和change类型的map.render事件,最后调用this.changed方法。 listen方法,listen方法在中提过,本质上还是调用EventTarget类中的addEventListener方法,而最后调用的this.changed方法会调用Observable类中的changed方法,继而调用dispatchEvent派发change类型的注册事件,前面注册的map.render事件,即参数map的render方法。

最后调用this.addeventListener方法注册source类型的this.handleSourcePropertyChange_事件;然后调用setSource方法。

  • setSource方法
  setSource(source) {
    this.set(LayerProperty.SOURCE, source);
  }
1
2
3

setSource方法就是调用BaseObject类中的set方法,第一次调用时(新旧值不一样时)会触发source的注册事件,即handleSourcePropertyChange_方法

  • handleSourcePropertyChange_
handleSourcePropertyChange_() {
    if (this.sourceChangeKey_) {
      unlistenByKey(this.sourceChangeKey_);
      this.sourceChangeKey_ = null;
    }
    this.sourceReady_ = false;
    const source = this.getSource();
    if (source) {
      this.sourceChangeKey_ = listen(
        source,
        EventType.CHANGE,
        this.handleSourceChange_,
        this,
      );
      if (source.getState() === 'ready') {
        this.sourceReady_ = true;
        setTimeout(() => {
          this.dispatchEvent('sourceready');
        }, 0);
      }
    }
    this.changed();
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

handleSourcePropertyChange_方法首先会判断this.sourceChangeKey_是否存在,若存在则解除EventKey键为this.sourceChangeKey_的监听,然后将其置为null;然后设置this.sourceReady_为false。调用this.getSource()方法,它内部就是调用BaseObject类的get方法获取source的值并返回,若source存在,则注册change类型的handleSourceChange_事件; 判断图层源source的状态是否为ready,若是,则设置this.sourceReady_为true,然后设置一个定时器调用dispatcheEvent('sourceready')方法。 最后调用changed事件,派发事件,执行类型为change的注册事件,调用handleSourceChange_方法。而handleSourceChange_内部还是会在this.sourceReady_为false或者source为ready的前提下去调用dispatcheEvent('sourceready')方法。

# Layer类的其它函数

  • getLayersArray方法:获取图层数组
  • getLayerStatesArray方法:获取图层状态数组
  • getRenderSource方法:获取渲染的图层源
  • getSourceState方法:获取图层源状态
  • getFeatures方法:接受一个参数pixel,若this.renderer渲染器不存在,则返回一个空数组;否则调用渲染器的getFeatures方法
  • getData方法:同上,若渲染器不存在则返回null,否则调用渲染器上的getData方法
  • isVisible方法:
  isVisible(view) {
    let frameState;
    const map = this.getMapInternal();
    if (!view && map) {
      view = map.getView();
    }
    if (view instanceof View) {
      frameState = {
        viewState: view.getState(),
        extent: view.calculateExtent(),
      };
    } else {
      frameState = view;
    }
    if (!frameState.layerStatesArray && map) {
      frameState.layerStatesArray = map.getLayerGroup().getLayerStatesArray();
    }
    let layerState;
    if (frameState.layerStatesArray) {
      layerState = frameState.layerStatesArray.find(
        (layerState) => layerState.layer === this,
      );
    } else {
      layerState = this.getLayerState();
    }

    const layerExtent = this.getExtent();

    return (
      inView(layerState, frameState.viewState) &&
      (!layerExtent || intersects(layerExtent, frameState.extent))
    );
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

isVisible方法用于判断图层在当前地图中是否可见,主要判断图层的状态和地图视图view的帧状态,涉及到范围和分辨率以及visiable

  • getAttributions方法:
  getAttributions(view) {
    if (!this.isVisible(view)) {
      return [];
    }
    const getAttributions = this.getSource()?.getAttributions();
    if (!getAttributions) {
      return [];
    }
    const frameState =
      view instanceof View ? view.getViewStateAndExtent() : view;
    let attributions = getAttributions(frameState);
    if (!Array.isArray(attributions)) {
      attributions = [attributions];
    }
    return attributions;
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

getAttributions方法用于获取图层源的各种属性,参数是一个view,首先判断视图的可见性,若不可见,则返回一个空数组,否则调用图层源的getAttributions()方法,返回值保存在变量getAttributions中,若变量getAttributions不存在,则返回一个空数组;否则调用getAttributions(frameState)。

  • setMapInternal和getMapInternal方法就是用于设置和获取对象的map
  • getRenderer方法:获取渲染器
  • hasRenderer方法:判断是否存在渲染器
  • createRender方法:创建一个渲染器,在Layer类中,返回一个null,该方法应该会在Layer的子类被重写
  • disposeInternal方法:Layer类的清理方法,判断渲染器是否存在,若存在则调用渲染器的dispose方法,然后删除渲染器;然后调用this.setSource(null),设置空的图层源,重置一些状态,最后调用父类的disposeInternal方法,执行父类的清除函数。

# 总结

本文主要介绍Layer类中重要的方法,如render方法和setSource的逻辑处理。

编辑 (opens new window)
上次更新: 2024/12/11, 10:30:03
BaseLayer类介绍
BaseVectorLayer类

← BaseLayer类介绍 BaseVectorLayer类→

最近更新
01
GeoJSON
05-08
02
Circle
04-15
03
CircleMarker
04-15
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式