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)
  • 框架

  • core模块

  • dom模块

  • control

  • geometry

  • geo

  • layer

    • marker

    • tile

    • vector

      • Renderer
      • Canvas
      • Path
      • Polyline
      • Polygon
      • Rectangle
      • Render.getRenderer
      • SVG
      • SVG.Util
      • SVG.VML
      • CircleMarker
        • 概述
        • 源码分析
          • 源码实现
          • 源码详解
          • 类继承与定位
          • 核心方法
          • 投影与渲染逻辑
          • 交互检测
          • 性能优化
          • 设计亮点
          • 与其他模块的关系
        • 总结
      • Circle
    • Layer
    • LayerGroup
    • FeatureGroup
    • DivOverlay
    • Popup
    • Tooltip
    • ImageOverlay
    • SVGOverlay
    • VideoOverlay
    • GeoJSON
  • Map

  • 《Leaflet源码》笔记
  • layer
  • vector
东流
2025-04-15
目录

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);
}
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
61
62
63
64
65
66
67
68

# 源码详解

# 类继承与定位

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

# 核心方法

CircleMarker的核心方法包括:

1.位置操作:setLatLng和getLatLng 2.半径操作:setRadius和getRadius 3.样式覆盖:setStyle

# 投影与渲染逻辑

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

2.边界计算

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

3.路径更新

  • 渲染器委托:实际绘制由SVGRenderer或CanvasRenderer实现:
    • SVG:更新<circle>元素的cx、cy、r属性
    • Canvas:调用arc()方法绘制圆形

# 交互检测

  • 容差计算:_clickTolerance继承自Path,包含线宽和渲染器容差
  • 作用:支持Canvas渲染器的鼠标事件检测

# 性能优化

  • 空检查:当圆形的包围盒与渲染器视口无交集时,标记为【空】,跳过绘制

# 设计亮点

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

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

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

  • 通过 fire('move') 实现坐标变化的事件通知。
  • 继承自 Interactive layer 支持 click、mouseover 等交互事件。 ​ 3.​渲染器抽象​​
  • 通过 _updateCircle 方法委托具体渲染逻辑,实现 SVG/Canvas 的无缝切换。 ​​ 4.性能优化​​
  • 包围盒快速检测(_pxBounds)
  • 空元素跳过绘制(_empty)

# 与其他模块的关系

  • 依赖Path:复用样式管理、渲染生命周期、点击检测等基础能力
  • 依赖Renderer:通过_updateCircle实现具体绘制
  • 与Circle类的对比:
特性 CircleMarker Circle
半径单位 像素 地理单位(米)
缩放行为 大小固定 随地图缩放变化
适用场景 标记固定大小的点 表示地理区域(如5km范围)

# 总结

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

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

编辑 (opens new window)
上次更新: 2025/05/08, 10:32:25
SVG.VML
Circle

← SVG.VML Circle→

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