访问Openlayers网站(https://jinuss.github.io/Openlayers_map_pages/,网站是基于
Vue3
+Openlayers
,里面有大量的实践和案例。觉得还不错,可以给个小星星Star,鼓励一波 https://github.com/Jinuss/OpenlayersMap哦~
概述
在前面提到了 Openlayers 中的矢量几何图形的渲染指令集部分,关于这些构建绘制指令集的类CanvasBuilderGroup
类,可以参考这篇文章源码分析之Openlayers中BuilderGroup类。顾名思义,CanvasBuilderGroup
类就是一组管理各种几何图形指令集的构造器的集合,该类会在矢量图层VectorLayer.js
(src\ol\renderer\canvas\VectorLayer.js
)和矢量瓦片图层VectorTileLayer.js
(src\ol\renderer\canvas\VectorTileLayer.js
)中被实例化,然后依据feature
去构建指令集。
本文将以VetorLayer.js
为例,讲解一个feature
时如何生成指令集的过程。
源码分析
CanvasVectorLayerRenderer
类
CanvasVectorLayerRenderer
类即VectorLayer.js
,用于构建矢量图层的渲染器,它继承于CanvasLayerRenderer
类,关于CanvasLayerRenderer
类,可以参考这篇文章源码分析之Openlayers渲染篇CanvasLayerRenderer类。
CanvasVectorLayerRenderer
类的中的prepareFrame
方法会在Layer
类中的render
方法被调用,而Layer
类是BaseVectorLayer
类的父类,关于它们的介绍,分别可以参考这两篇文章源码分析之Openlayers图层基类BaseLayer介绍和源码分析之Openlayers中的核心基类Layer类介绍.而render
方法会在Map
的渲染器CompositeMapRenderer
类里的renderFrame
方法中被调用。总结一下就是prepareFrame
方法会在地图渲染时被调用,
prepareFrame
方法
prepareFrame
方法中关于feature
部分的代码如下:
class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
prepareFrame(frameState) {
const replayGroup = new CanvasBuilderGroup(
getRenderTolerance(resolution, pixelRatio),
extent,
resolution,
pixelRatio
);
const render = (feature, index) => {
let styles;
const styleFunction =
feature.getStyleFunction() || vectorLayer.getStyleFunction();
if (styleFunction) {
styles = styleFunction(feature, resolution);
}
if (styles) {
const dirty = this.renderFeature(
feature,
squaredTolerance,
styles,
replayGroup,
userTransform,
this.getLayer().getDeclutter(),
index
);
ready = ready && !dirty;
}
};
const features = vectorSource.getFeaturesInExtent(userExtent);
for (let i = 0, ii = features.length; i < ii; ++i) {
render(features[i], i);
}
const replayGroupInstructions = replayGroup.finish();
}
}
prepareFrame
方法会实例化CanvasBuilderGroup
类,实例对象relayGroup
表示一组待渲染的绘制命令集合,是图形绘制命令的载体。它用于管理和优化图形的渲染过程,将多个渲染步骤组合在一起,避免重复计算,可以提高渲染效率。然后定义了一个局部函数render
,
render
函数
render
函数接受两个参数feature
和index
,这里的feature
就是Feature
类的一个实例,关于Feature
类,可以参考这篇文章源码分析之Openlayers中Feature特征。render
方法内部会先判断feature
是否定义了样式函数styleFunction
,若没有定义,则使用矢量图层vectorLayer
的默认样式函数,然后执行styleFunction(feature,resolution)
语句,返回结果作为styles
,这一步也就是每当地图更新时,feature
或者layer
的styleFunction
会被调用,可以获取地图实时的分辨率resolution
;然后判断,若styles
存在,则调用内部方法this.renderFeature
方法。
prepareFrame
方法通过图层源获取用户可见范围内的features
,然后遍历features
,去调用上面定义的局部函数render
最后调用replayGroup.finish
方法获取需要绘制features
的绘制指令集和碰撞检测指令集等。
下面介绍下this.renderFeature
方法,该方法也是在CanvasVectorLayerRenderer
类中定义的一个内部方法。
其实现如下:
renderFeature
方法
class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
renderFeature(
feature,
squaredTolerance,
styles,
builderGroup,
transform,
declutter,
index
) {
if (!styles) {
return false;
}
let loading = false;
if (Array.isArray(styles)) {
for (let i = 0, ii = styles.length; i < ii; ++i) {
loading =
renderFeature(
builderGroup,
feature,
styles[i],
squaredTolerance,
this.boundHandleStyleImageChange_,
transform,
declutter,
index
) || loading;
}
} else {
loading = renderFeature(
builderGroup,
feature,
styles,
squaredTolerance,
this.boundHandleStyleImageChange_,
transform,
declutter,
index
);
}
return loading;
}
}
renderFeature
方法内部会先判断,若styles
样式不存在,则返回;然后判断样式styles
是否是数组,若是数组,则循环遍历样式styles
调用外部方法renderFeature
,所以这里如果定义多个样式,后面的样式会覆盖前面样式的相同属性;否则只需要调用一次外部方法renderFeature
,该外部方法renderFeature
接受参数builderGroup
、feature
和style
等等。builderGroup
就是在prepareFrame
方法中的实例对象replayGroup
.
vector.js
上面提到的外部方法renderFeature
是在src\ol\renderer\vector.js
中定义的,