openlayers源码阅读笔记(二)—— 地图渲染器ol.CompositeMapRenderer

openlayers源码阅读笔记(二)—— 地图渲染器ol.CompositeMapRenderer

上一节中讲到地图渲染是调用了渲染器的renderFrame方法,这一节我们来看地图渲染器CompositeMapRenderer类,直译过来就是复合地图渲染器。

1. 创建div.ol-layers元素

构造函数很简单,就是创建了div.ol-layers,并插入到viewport中。

/**
 * @classdesc
 * Canvas map renderer.
 * @api
 */
class CompositeMapRenderer extends MapRenderer {
  /**
   * @param {import("../PluggableMap.js").default} map Map.
   */
  constructor(map) {
    super(map);

    /**
     * @type {import("../events.js").EventsKey}
     */
    this.fontChangeListenerKey_ = listen(
      checkedFonts,
      ObjectEventType.PROPERTYCHANGE,
      map.redrawText.bind(map)
    );

    /**
     * @private
     * @type {HTMLDivElement}
     */
    this.element_ = document.createElement('div');
    const style = this.element_.style;
    style.position = 'absolute';
    style.width = '100%';
    style.height = '100%';
    style.zIndex = '0';

    this.element_.className = CLASS_UNSELECTABLE + ' ol-layers';

    const container = map.getViewport();
    container.insertBefore(this.element_, container.firstChild || null);

    /**
     * @private
     * @type {Array<HTMLElement>}
     */
    this.children_ = [];

    /**
     * @private
     * @type {boolean}
     */
    this.renderedVisible_ = true;
  }
  ......
}
2. CompositeMapRenderer.renderFrame方法
  renderFrame(frameState) {
    if (!frameState) {
      if (this.renderedVisible_) {
        this.element_.style.display = 'none';
        this.renderedVisible_ = false;
      }
      return;
    }

    this.calculateMatrices2D(frameState);
    this.dispatchRenderEvent(RenderEventType.PRECOMPOSE, frameState);
    .......
  }

renderFrame接收一个framestate参数,他会先检测framestate是否为真值,如果不是,则取消渲染。渲染之前他会先调用调用this.calculateMatrices2D方法和派发一个PRECOMPOSES事件。this.calculateMatrices2D方法是根据地图的尺寸、view的分辨率、旋转角、中心纵坐标来计算framestate中的坐标和像素单位相互转换的矩阵coordinateToPixelTransform和pixelToCoordinateTransform。

  renderFrame(frameState) {
    .......
    const layerStatesArray = frameState.layerStatesArray.sort(function (a, b) {
      return a.zIndex - b.zIndex;
    });
    const viewState = frameState.viewState;
    ......
  }

通过layer的zIndex给图层排序,这决定了图层的渲染顺序和我们看到的屏幕上的图层的上下层级,最后渲染的图层会出现在地图最顶层。

  renderFrame(frameState) {
    .......
    this.children_.length = 0;
    ......
  }

this.children_是div.ol-layers的子元素,也就是显示图层的canvas元素,这一句将div.ol-layers的子元素清空。

  renderFrame(frameState) {
    .......
    let previousElement = null;
    for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
      const layerState = layerStatesArray[i];
      frameState.layerIndex = i;
      if (
        !inView(layerState, viewState) ||
        (layerState.sourceState != SourceState.READY &&
          layerState.sourceState != SourceState.UNDEFINED)
      ) {
        continue;
      }

      const layer = layerState.layer;
      const element = layer.render(frameState, previousElement);
      if (!element) {
        continue;
      }
      if (element !== previousElement) {
        this.children_.push(element);
        previousElement = element;
      }
	......
  }

遍历图层状态数组,若数据源状态sourceState不为READY或UNDEFINED则不渲染此图层。
调用layer.render方法,该方法接收两个参数framestate和一个HTML元素,并且返回一个HTML元素。该HTML元素就是将呈现在页面上的地图canvas元素,每一个layer将本图层需要呈现的像素渲染到上一个layer(若有)渲染之后的canvas上,最终会得到一个我们想要呈现到页面上的canvas。如果我们在new Layer()的时候给图层设置了className属性,则该图层会新建一个canvas,而不是在previousElement上继续渲染。最后this.children_储存的就是所有需要添加到页面呈现的canvas元素。

  renderFrame(frameState) {
    .......
    replaceChildren(this.element_, this.children_);

    this.dispatchRenderEvent(RenderEventType.POSTCOMPOSE, frameState);

    if (!this.renderedVisible_) {
      this.element_.style.display = '';
      this.renderedVisible_ = true;
    }

    this.scheduleExpireIconCache(frameState);
  }

最后调用window.replaceChildren将this.element_也就是div.ol-layers的子元素替换成this.children_中的canvas元素。

3. 总结

ol.CompositeMapRenderer类在构造函数中创建了存放图层canvas的节点div.ol-layers;在地图渲染时会按顺序调用图层的render方法;最后将所有需要呈现图层渲染好的canvas元素插入到div.ol-layers中。
下一节分享ol.layer及其render函数。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值