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
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()
方法绘制圆形
- SVG:更新
# 交互检测
- 容差计算:
_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