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类介绍
    • BaseVectorLayer类
    • VectorLayer类
      • 概述
      • 源码剖析
        • VectorLayer类
        • CanvasVectorLayerRenderer 渲染器
        • CanvasVectorLayerRenderer方法解释
  • Renderer篇

  • Feature篇

  • style样式篇

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

VectorLayer类

# 概述

本文主要介绍VectorLayer类和CanvasVectorLayerRenderer图层渲染器

# 源码剖析

# VectorLayer类

VectorLayer就是继承了BaseVectorLayer类,重写了createRender方法,返回CanvasVectorLayerRenderer的实例对象。

class VectorLayer extends BaseVectorLayer {
  constructor(options) {
    super(options);
  }
  createRenderer() {
    return new CanvasVectorLayerRenderer(this);
  }
}
1
2
3
4
5
6
7
8

# CanvasVectorLayerRenderer 渲染器

VectorLayer类中createRenderer方法实际是重写Layer类(即BaseVectorLayer的父类)中定义的同名方法,返回一个CanvasVectorLayerRenderer类的实例对象,该类继承了CanvasLayerRenderer类。

CanvasVectorLayerRenderer类的构造函数各变量含义如下面代码片段所示

CanvasVectorLayerRenderer类的实现如下:

class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
  constructor(vectorLayer) {
    // 绑定样式图像变化后的处理方法,确保函数的上下文始终指向当前渲染器的实例对象
    this.boundHandleStyleImageChange_ = this.handleStyleImageChange_.bind(this);
    // 是否正在进行动画或者交互状态
    this.animatingOrInteracting_;
    // 记录击中检测的图像数据,在进行对象碰撞检测时会用到,初始化为null
    this.hitDetectionImageData_ = null;
    // 是否已裁剪,初始化为false
    this.clipped_ = false;
    // 记录已渲染的Features,初始化为null
    this.renderedFeatures_ = null;
    // 记录已渲染的修订版本号,初始化为-1
    this.renderedRevision_ = -1;
    // 记录已渲染的分辨率,初始化为NaN
    this.renderedResolution_ = NaN;
    // 记录已渲染的视图范围,初始化为[Infinity, Infinity, -Infinity, -Infinity]
    this.renderedExtent_ = createEmpty();
    // 记录包裹的已渲染范围,初始化为[Infinity, Infinity, -Infinity, -Infinity]
    this.wrappedRenderedExtent_ = createEmpty();
    // 记录已渲染的旋转角度
    this.renderedRotation_;
    // 记录已渲染的中心,初始值为null
    this.renderedCenter_ = null;
    // 记录已渲染的像素比率,初始值为1
    this.renderedPixelRatio_ = 1;
    // 记录已渲染的渲染顺序,初始值为null
    this.renderedRenderOrder_ = null;
    // 记录已渲染的去重操作
    this.renderedFrameDeclutter_;
    // 重播组,初始值为null
    this.replayGroup_ = null;
    // 记录重播组已更改,初始值为true
    this.replayGroupChanged = true;
    // 是否启用裁剪,初始值为true
    this.clipping = true;
    // 目标上下文,即canvas 绘图的上下文
    this.targetContext_ = null;
    // 透明度,初始值为1
    this.opacity_ = 1; //
  }
  renderWorlds(executorGroup, frameState, declutterable) {}
  setDrawContext_() {}
  resetDrawContext_() {}
  renderDeclutter(frameState) {}
  renderDeferredInternal() {}
  renderFrame(frameState, target) {}
  getFeatures(pixel) {}
  forEachFeatureAtCoordinate(
    coordinate,
    frameState,
    hitTolerance,
    callback,
    matches
  ) {}
  handleFontsChanged() {}
  handleStyleImageChange_() {}
  prepareFrame() {}
  renderFeature() {}
}
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

# CanvasVectorLayerRenderer方法解释

  • renderWorlds方法

renderWorlds方法用于在多个世界上渲染矢量数据,即地图在水平轴上可以循环延申。它接受三个参数executorGroup(负责渲染执行的对象,进行实际渲染的操作),frameState(帧状态信息),declutterable(表示是否参与去重,true需要去重,false不进行去重处理)

renderWorlds方法内部就是先获取帧状态的各种信息中心、分辨率、像素比等等,然后调用this.getLayer获取图层源以及投影坐标系是否支持在水平方向延申,从而确定渲染的起始位置,最后执行一个循环,根据当前视图的世界范围,逐个渲染每个世界.

renderWorlds方法中的核心部分在循环体,该循环体先是调用LayerRenderer类(即CanvasLayerRenderer类的父类)中的getRenderTransform方法获取渲染转换矩阵,它会根据当前视图的中心、分辨率、旋转角度等信息,计算出当前世界的变换矩阵。然后根据frameState.declutter)确定变换矩阵,再通过executorGroup.execute触发实际的渲染操作,这是一个很复杂的过程,在以后会分析到。

renderWorlds(executorGroup, frameState, declutterable) {
    const extent = frameState.extent;
    const viewState = frameState.viewState;
    const center = viewState.center;
    const resolution = viewState.resolution;
    const projection = viewState.projection;
    const rotation = viewState.rotation;
    const projectionExtent = projection.getExtent();
    const vectorSource = this.getLayer().getSource();
    const declutter = this.getLayer().getDeclutter();
    const pixelRatio = frameState.pixelRatio;
    const viewHints = frameState.viewHints;
    const snapToPixel = !(
      viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]
    );
    const context = this.context;
    const width = Math.round((getWidth(extent) / resolution) * pixelRatio);//渲染区域宽度
    const height = Math.round((getHeight(extent) / resolution) * pixelRatio);//渲染区域高度

    const multiWorld = vectorSource.getWrapX() && projection.canWrapX();//是否水平方向延申
    const worldWidth = multiWorld ? getWidth(projectionExtent) : null; //世界的宽度
    const endWorld = multiWorld
      ? Math.ceil((extent[2] - projectionExtent[2]) / worldWidth) + 1
      : 1; //计算需要渲染世界的数量
    let world = multiWorld
      ? Math.floor((extent[0] - projectionExtent[0]) / worldWidth)
      : 0;//当前视图所在的世界的起始位置(即开始渲染的世界编号)
    do {
      let transform = this.getRenderTransform(
        center,
        resolution,
        0,
        pixelRatio,
        width,
        height,
        world * worldWidth
      );
      if (frameState.declutter) {
        transform = transform.slice(0);
      }
      executorGroup.execute(
        context,
        [context.canvas.width, context.canvas.height],
        transform,
        rotation,
        snapToPixel,
        declutterable === undefined
          ? ALL
          : declutterable
          ? DECLUTTER
          : NON_DECLUTTER,
        declutterable ? declutter && frameState.declutter[declutter] : undefined
      );
    } while (++world < endWorld);
  }
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
  • setDrawContext_

setDrawContext_方法目的就是用于设置canvas的上下文环境,该上下文环境就是调用createCanvasContext2D方法创建了一个canvas element,然后返回一个2d context。

setDrawContext_() {
    if (this.opacity_ !== 1) {
      this.targetContext_ = this.context;
      this.context = createCanvasContext2D(
        this.context.canvas.width,
        this.context.canvas.height,
        canvasPool,
      );
    }
  }
1
2
3
4
5
6
7
8
9
10
  • 和resetDrawContext_方法

resetDrawContext_方法就是重置canvas的上下文环境或状态,releaseCanvas就是释放画布资源,清空canvas上的数据,以便以后复用或回收。

  resetDrawContext_() {
    if (this.opacity_ !== 1) {
      const alpha = this.targetContext_.globalAlpha;
      this.targetContext_.globalAlpha = this.opacity_;
      this.targetContext_.drawImage(this.context.canvas, 0, 0);
      this.targetContext_.globalAlpha = alpha;
      releaseCanvas(this.context);
      canvasPool.push(this.context.canvas);
      this.context = this.targetContext_;
      this.targetContext_ = null;
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
  • renderDeclutter方法

renderDeclutter方法就是接受一个参数frameState帧状态,如果this.replayGroup_或者图层不需要去重,则返回;否则调用renderWorlds方法进行帧状态的渲染。

  renderDeclutter(frameState) {
    if (!this.replayGroup_ || !this.getLayer().getDeclutter()) {
      return;
    }
    this.renderWorlds(this.replayGroup_, frameState, true);
  }
1
2
3
4
5
6
  • renderDeferredInternal方法

renderDeferredInternal方法是内部由 Openlayers 内部调用延迟渲染的方法,其实现如下

  renderDeferredInternal(frameState) {
    if (!this.replayGroup_) {
      return;
    }
    this.replayGroup_.renderDeferred();
    if (this.clipped_) {
      this.context.restore();
    }
    this.resetDrawContext_();
  }
1
2
3
4
5
6
7
8
9
10

若this.replayGroup_不存在,则返回;否则执行this.replayGroup_.renderDeferred()方法,然后判断是否已裁剪,若已裁剪,则保存canvas的上下文;最后调用了resetDrawContext_重置画布绘制的上下文。

  • renderFrame方法

renderFrame方法是核心方法,用于渲染图层,接受两个参数frameState帧状态和目标元素target。 renderFrame方法先是通过layerIndex获取layerState图层状态,以及图层的透明度,然后调用prepareContainer方法设置this.context.canvas的transform属性,然后判断this.replayGroup_是否存在,若不存在则判断图层是否存在prerender和postrender类型的监听事件,若不存在,则返回;若存在,则设置画布的上下文,然后调用this.preRender进行预渲染

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

← BaseVectorLayer类 VectorContext类→

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