源码分析之Leaflet中的Renderer渲染器基类

概述

Renderer 是一个抽象类,作为所有矢量渲染器(如SVGCanvas)的基类,用于定义渲染器的基本行为。它继承自 Layer 类,提供了一些通用的方法和属性,如处理渲染器的DOM容器管理、坐标变换和地图事件响应。

源码分析

源码实现

Renderer渲染器的源码实现如下:

export var Renderer = Layer.extend({
  options: {
    padding: 0.1, //控制渲染区域比地图视口多出的比例,避免边缘图形被裁剪。例如地图视口为100px,地图默认渲染区域为120px=100px *(1+0.1*2)
  },
  initialize: function (options) {
    Util.setOptions(this, options); // 合并选项
    Util.stamp(this); // 添加唯一标识符
    this._layers = this._layers || {}; // 存储所有子图层
  },
  onAdd: function () {
    if (!this._container) {
      this._initContainer(); // 子类实现,创建SVG/Canvas元素
      DomUtil.addClass(this._container, "leaflet-zoom-animated");
    }

    this.getPane().appendChild(this._container);
    this._update(); // 初始化边界和变换
    this.on("update", this._updatePaths, this);
  },
  onRemove: function () {
    this.off("update", this._updatePaths, this);
  },
  getEvents: function () {
    var events = {
      viewreset: this._reset,
      zoom: this._onZoom,
      moveend: this._update,
      zoomend: this._onZoomEnd,
    };
    if (this._zoomAnimated) {
      events.zoomanim = this._onAnimZoom; // 处理动画缩放
    }
    return events;
  },
  _onAnimZoom: function (ev) {
    this._updateTransform(ev.center, ev.zoom);
  },
  _onZoom: function () {
    this._updateTransform(this._map.getCenter(), this._map.getZoom());
  },
  _updateTransform: function (center, zoom) {
    // 计算缩放比例
    var scale = this._map.getZoomScale(zoom, this._zoom),
     // 计算视口半长,含(padding)
      viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),
      // 当前中心点在地图坐标系中的像素坐标
      currentCenterPoint = this._map.project(this._center, zoom),
      // 计算容器偏移量
      topLeftOffset = viewHalf
        .multiplyBy(-scale) // 反向偏移
        .add(currentCenterPoint) // 加上当前中心点
        .subtract(this._map._getNewPixelOrigin(center, zoom));
    
    // 应用变换,更新容器的位置和缩放
    if (Browser.any3d) {
      DomUtil.setTransform(this._container, topLeftOffset, scale);
    } else {
      DomUtil.setPosition(this._container, topLeftOffset);
    }
  },
  _reset: function () {
    this._update(); // 更新边界
    this._updateTransform(this._center, this._zoom); // 重新定位
    // 重置所有子图层
    for (var id in this._layers) {
      this._layers[id]._reset();
    }
  },
  _onZoomEnd: function () {
    for (var id in this._layers) {
      this._layers[id]._project();
    }
  },
  _updatePath: function () {
    for (var id in this._layers) {
      this._layers[id]._update(); // 重绘路径
    }
  },
  _update: function () {
    var p = this.options.padding,
      size = this._map.getSize(),
      min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();

    this._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());

    this._center = this._map.getCenter();
    this._zoom = this._map.getZoom();
  },
});

源码解析

类结构与继承
  • 继承自Layer

Renderer 继承自 Layer 类,这表明它是一个图层类的子类,可被添加到地图中。所有矢量图形(如PolylinePolygon)默认使用渲染器绘制。

  • 抽象基类
    Renderer类不能被实例化使用,通常是作为具体渲染器(如SVGCanvas)的基类,提供了通用的渲染方法和属性,而具体的渲染逻辑由子类实现。
构造函数

initialize 方法用于初始化渲染器,合并传入的选项,并添加唯一标识符。

DOM容器生命周期

1.onAdd():添加到地图时

  • 容器创建

    • 子类实现的_initContainer()方法:创建渲染器的DOM容器,如SVGCanvas元素。
  • CSS 类leaflet-zoom-animated

    • 容器添加了leaflet-zoom-animated类,用于启用缩放动画效果。
  • 事件绑定

    • 绑定了update事件,当渲染器需要更新时触发_updatePaths方法。

2.onRemove():移除时销毁

事件绑定与处理

1.getEvents():监听地图事件

  • 关键事件
    • viewreset:地图视图重置时(如地图投影或范围变化)触发_reset方法,重置渲染器
    • zoom/moveend:地图缩放或移动结束时触发_update方法,更新渲染器状态(位置和缩放)
    • zoomanim:动画缩放时触发_onAnimZoom方法,处理缩放动画效果
坐标变换与动画

_updateTransform(center,zoom):核心变换逻辑

    1. 计算缩放比例scale:根据当前缩放级别和目标缩放级别,计算出缩放比例scale
    1. 计算视口半长viewHalf:根据当前地图视口大小和padding选项,计算出视口的一半长度viewHalf
    1. 计算中心点像素坐标currentCenterPoint:将地图中心点转换为像素坐标currentCenterPoint
    1. 计算容器偏移量topLeftOffset
    • 反向偏移:根据缩放比例和视口半长,计算出容器需要反向偏移的距离。
    • 加上当前中心点:加上当前中心点的像素坐标。
    • 减去新的像素原点:减去新的像素原点,以确保容器的位置正确。
    1. 应用变换兼容性处理:
    • 对于支持 3D 变换的浏览器,使用DomUtil.setTransform方法应用变换,包括平移和缩放。
    • 对于不支持 3D 变换的浏览器,使用DomUtil.setPosition方法应用平移。
边界更新与重绘

_update:更新渲染器的边界和状态

    1. 计算边界bounds:根据当前地图视口大小和padding选项,计算出渲染器的边界bounds
    1. 更新中心点和缩放级别:更新渲染器的中心点和缩放级别。

_reset:重置渲染器

  • 子图层重置:调用每个路径的_reset(),例如重新计算投影

_updatePaths():更新所有路径

  • 触发时机:在update事件触发时调用(如地图移动或缩放后),用于重绘所有路径。
子类实现关键点

子类必须实现的方法:

  • _initContainer()
    创建DOM元素(SVGCanvas’),设置其样式和尺寸

  • _updatePath(layer)
    具体如何绘制或更新单个路径

设计思想总结
  • 分层抽象

    • Renderer处理通用逻辑(事件、变换、容器管理)
    • 子类专注具体渲染技术(SVGCanvas
  • 性能优化

    • 批量更新:通过_updatePaths方法,一次性更新所有路径,减少重绘次数
    • CSS 变换:利用硬件加速实现平滑缩放动画
    • 离屏渲染:通过padding扩展渲染区域,减少频繁重绘
  • 浏览器兼容

    • 通过Browser模块检测特性,降级处理不支持3D变换的浏览器
渲染流程

1. 地图初始化​​
添加 Renderer 实例到地图,触发 onAdd,创建容器并绑定事件。
2. 用户拖拽地图​​
触发 moveend,调用 _update() 更新 _bounds 和中心点。
3. 缩放动画进行中​​
触发 zoomanim,调用 _onAnimZoom,实时更新容器变换。
4. 缩放结束​​
触发 zoomend,调用 _onZoomEnd,重新投影所有路径。
5. 路径更新​​
某个 Polyline 修改坐标,触发 _update(),重绘对应路径

总结

Renderer是Leaflet 矢量渲染的核心基类,通过统一管理容器变换和地图事件,为不同渲染技术(SVG/Canvas)提供通用逻辑,确保矢量图形在地图交互中正确渲染和更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jinuss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值