OpenLayers

OpenLayers中切片图层TileLayer的渲染解析

2019-11-04  本文已影响0人  jadefan

切片图层是最常用也是最基础的图层,通常底图或者影像图层都采用TileLayer加载
TileLayer由Tile组成,Tile一般是图片切片
我们来看TileLayer渲染过程

TileLayer的创建

从最初的地方开始,也就是初始化地图时,会实例化一个切片图层

const map = new Map({
  layers: [
    new TileLayer({
      source: new OSM()
    })
  ],
  target: 'map',
  view: new View({
    center: [0, 0],
    zoom: 2
  })
});

TileLayer里也比较简洁,初始化调用父类的构造函数,自己只负责创建渲染器

class TileLayer extends BaseTileLayer {
  constructor(opt_options) {
    super(opt_options);
  }
  createRenderer() {
    return new CanvasTileLayerRenderer(this);
  }
}

那在何处执行createRenderer,构建layer.render以备Map调用呢?
TileLayer属于Layer的子类,看Layer的实现:

class Layer extends BaseLayer {
  constructor(options) {
    ...
  }
  render(frameState, target) {
    const layerRenderer = this.getRenderer(); 
    if (layerRenderer.prepareFrame(frameState)) {
      return layerRenderer.renderFrame(frameState, target);
    }
  }
  getRenderer() {
    if (!this.renderer_) {
      this.renderer_ = this.createRenderer();
    }
    return this.renderer_;
  }
}

可以看到Layer定义了render()方法,并调用了createRenderer(),并执行渲染器的renderFrame()方法
这里就引出了ol的一个图层渲染机制

ol的图层类型很多,但大部分属性和方法通用,不同的图层类型自己创建渲染器,用Layer统筹初始化图层,再调用各自实现的渲染器

TileLayer的继承链条为:
TileLayer->BaseTileLayer->Layer->BaseLayer->BaseObject->Observable->EventTarget->Disposable
TileLayer的渲染器CanvasTileLayerRenderer的继承链条为:
CanvasTileLayerRenderer->CanvasLayerRenderer->LayerRenderer->Observable->EventTarget->Disposable
接下来看ol是如何渲染切片图层的

TileLayer的渲染器CanvasTileLayerRenderer的实现逻辑

通过上面的解析可以看出渲染的核心方法是renderFrame(),代码很长,来看主要逻辑

首先看下切片图层的数据源Source

TileLayer的一个重要属性就是source,定义了切片的网络地址、规则、大小、分辨率、比例尺、生产商等等信息。要正确渲染就必须先正确解析并请求到切片图片。

OSM看下source的继承关系
OSM->XYZ->TileImage->UrlTile->TileSource->Source->BaseObject->Observable->EventTarget->Disposable

OpenStreetMap(简称OSM,中文是公开地图)是一个网上地图协作计划,目标是创造一个内容自由且能让所有人编辑的世界地图。它是利用公众集体的力量和无偿的贡献来改善地图相关的地理数据。OSM是非营利性 的,它将数据回馈给社区重新用于其它的产品与服务。

可以看到OSM继承自XYZ,XYZ是切片地图很常用的一套切片规则,在new OSM()时已经将对应投影和切片规则读取出来

在调用渲染器时,根据设置好的中心点和级别,通过切片规则和投影定义计算出需要的切片Z\X\Y的值,从而请求到切片的图片,再绘制到canvas中。

canvas / TileLayer.js

class CanvasTileLayerRenderer extends CanvasLayerRenderer {
...
  renderFrame(frameState, target) {
    ...
    for (const tileCoordKey in tilesToDraw) {
      //调用绘制切片
      this.drawTileImage(tile, frameState, x, y, w, h, tileGutter, transition, layerState.opacity);
    } 
    ...
  }

  drawTileImage(tile, frameState, x, y, w, h, gutter, transition, opacity) {
    ...
    //画布绘制
    this.context.drawImage(image, gutter, gutter, image.width - 2 * gutter, image.height - 2 * gutter, x, y, w, h);
    ...
  }
  ...
}
上一篇下一篇

猜你喜欢

热点阅读