源码分析之Leaflet中CircleMarker

概述

在Leaflet中,CircleMarker继承于Path类,用于创建固定像素大小的圆形标记。

源码分析

源码实现

CircleMarker的源码实现如下:

export var CircleMarker = Path.extend({
  options: {
    fill: true, // 默认启用填充
    radius: 10, // 圆形半径(像素单位)
  },
  initialize: function (latlng, options) {
    Util.setOptions(this, options); // 合并配置项
    this._latlng = toLatLng(latlng); // 确保经纬度对象合法化
    this._radius = this.options.radius; // 存储半径(像素值)
  },
  // 设置新位置并触发事件
  setLatLng: function (latlng) {
    var oldLatLng = this._latlng;
    this._latlng = toLatLng(latlng);
    this.redraw(); // 强制重绘
    return this.fire("move", { oldLatLng: oldLatLng, latlng: this._latlng }); // 触发 move事件
  },
  // 获取当前坐标
  getLatLng: function () {
    return this._latlng;
  },
  // 更新半径并重绘
  setRadius: function (radius) {
    this.options.radius = this._radius = radius;
    return this.redraw();
  },
  // 获取当前半径
  getRadius: function () {
    return this._radius;
  },
  setStyle: function (options) {
    var radius = (options && options.radius) || this._radius;
    Path.prototype.setStyle.call(this, options);
    this.setRadius(radius);
    return this;
  },
  _project: function () {
    // 地理坐标 → 图层像素坐标
    this._point = this._map.latLngToLayerPoint(this._latlng);
    this._updateBounds(); // 更新碰撞边界
  },
  _updateBounds: function () {
    var r = this._radius,
      r2 = this._radiusY || r,
      w = this._clickTolerance(),
      p = [r + w, r2 + w];
    this._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p));
  },
  _update: function () {
    if (this._map) {
      this._updatePath();
    }
  },
  _updatePath: function () {
    this._renderer._updateCircle(this); // 委托渲染器绘制
  },
  _empty: function () {
    return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
  },
  // 判断点是否在圆形内
  _containsPoint: function (p) {
    return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
  },
});

export function circleMarker(latlng, options) {
  return new CircleMarker(latlng, options);
}

源码详解

类继承与定位
  • 继承自Path:复用矢量图形的样式管理、渲染生命周期等基础能力。
  • 功能定位:创建半径固定为像素值的圆形(与地理半径的Circle类不同)
核心方法

CircleMarker的核心方法包括:

1.位置操作setLatLnggetLatLng
2.半径操作setRadiusgetRadius
3.样式覆盖setStyle

投影与渲染逻辑

1.坐标转换_project()将地理坐标转为图层像素坐标

2.边界计算

  • 作用_updateBounds()方法用于更新边界,可以确定圆形在屏幕空间的包围盒,用于:
    • 快速判断是否在视口外(_empty方法)
    • 优化渲染(跳过不可见元素的绘制)

3.路径更新

  • 渲染器委托:实际绘制由SVGRendererCanvasRenderer实现:
    • SVG:更新<circle>元素的cxcyr属性
    • Canvas:调用arc()方法绘制圆形
交互检测
  • 容差计算_clickTolerance继承自Path,包含线宽和渲染器容差
  • 作用:支持Canvas渲染器的鼠标事件检测
性能优化
  • 空检查:当圆形的包围盒与渲染器视口无交集时,标记为【空】,跳过绘制
设计亮点

​1.​像素半径固定​​

  • 区别于 Circle 类的地理单位半径,CircleMarker 在缩放时大小不变。
  • 实现方式:直接存储像素值 _radius,无需随缩放重新计算。

2.​​事件系统集成​​

  • 通过 fire('move') 实现坐标变化的事件通知。
  • 继承自 Interactive layer 支持 clickmouseover 等交互事件。

    3.​渲染器抽象​​
  • 通过 _updateCircle 方法委托具体渲染逻辑,实现 SVG/Canvas 的无缝切换。
    ​​
    4.性能优化​​
  • 包围盒快速检测(_pxBounds
  • 空元素跳过绘制(_empty
与其他模块的关系
  • 依赖Path:复用样式管理、渲染生命周期、点击检测等基础能力
  • 依赖Renderer:通过_updateCircle实现具体绘制
  • Circle类的对比
特性CircleMarkerCircle
半径单位像素地理单位(米)
缩放行为大小固定随地图缩放变化
适用场景标记固定大小的点表示地理区域(如5km范围)

总结

Leaflet 的 CircleMarker 通过以下设计实现高效的点标记:

1.​轻量继承​​:复用 Path 的 90% 基础能力,仅扩展半径相关逻辑。
2.​像素级控制​​:直接操作屏幕坐标,避免地理投影计算。
​​3.跨渲染器兼容​​:通过抽象方法 _updateCircle 适配不同渲染技术。
​​4.交互友好​​:精确的点击检测与事件冒泡机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jinuss

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

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

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

打赏作者

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

抵扣说明:

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

余额充值