访问Openlayers网站(https://jinuss.github.io/Openlayers_map_pages/,网站是基于
Vue3
+Openlayers
,里面有大量的实践和案例。觉得还不错,可以给个小星星Star,鼓励一波 https://github.com/Jinuss/OpenlayersMap哦~
概述
本文将介绍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();
}
}
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;
}
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();
}
}
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);
}
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();
}
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))
);
}
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;
}
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
的逻辑处理。