Layer
# 概述
Layer
类是Leaflet中所有图层的基类,提供了一些通用的方法和属性。所有的图层类都应该继承自Layer
类。
# 源码分析
# 源码实现
源码中主要包括Layer
基类的实现以及图层Layer
类与Map
类之间交互混入的方法。
# Layer
基类实现
Layer
基类实现如下:
export var Layer = Evented.extend({
// 默认配置项
options: {
pane: "overlayPane", // 图层默认挂载
attribution: null, // 图层默认属性
bubblingMouseEvents: true, // 鼠标事件是否冒泡
},
addTo: function (map) {
map.addLayer(this);
return this;
},
remove: function () {
return this.removeFrom(this._map || this._mapToAdd);
},
removeFrom: function (obj) {
if (obj) {
obj.removeLayer(this);
}
return this;
},
getPane: function (name) {
return this._map.getPane(
name ? this.options[name] || name : this.options.pane
);
},
addInteractiveTarget: function (targetEl) {
this._map._targets[Util.stamp(targetEl)] = this;
return this;
},
removeInteractiveTarget: function (targetEl) {
delete this._map._targets[Util.stamp(targetEl)];
return this;
},
getAttribution: function () {
return this.options.attribution;
},
_layerAdd: function (e) {
var map = e.target;
if (!map.hasLayer(this)) {
return;
}
this._map = map; // 设置关联的地图实例
this._zoomAnimated = map._zoomAnimated; // 是否支持缩放动画
if (this.getEvents) { // 绑定事件
var events = this.getEvents();
map.on(events, this);
this.once(
"remove",
function () {
map.off(events, this); // 移除时解绑事件
},
this
);
}
this.onAdd(map);
this.fire("add"); //触发add事件
map.fire("layeradd", { layer: this }); //地图触发layeradd事件
},
});
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
# Layer
类详解
Layer
基类继承于Evented
类,因此所有图层类支持事件如on
、off
、fire
等。
# 核心方法
addTo(map)
:将图层添加到指定的地图对象map
中,并返回当前图层对象允许链式调用。remove()
:从当前地图对象中移除图层。removeFrom(obj)
:从指定的对象obj
(如Map
或LayerGroup
)中移除图层。getPane(name)
:获取指定名称的图层容器,默认获取overlayPane
DOM容器。addInteractiveTarget(targetEl)
和removeInteractiveTarget
:
- 用途:将DOM元素注册为交互目标,比如
Marker
的图标元素 - 实现:使用
Util.stamp
生成唯一ID,绑定到当前图层实例的_map._targets
对象中 - 作用:
- 当鼠标事件发生在该DOM元素上时,会触发地图的
mousemove
、click
等事件,并且事件对象的target
属性指向该DOM元素。 - 可以通过
map._targets
获取所有的交互目标元素及其对应的图层实例。 - 这对于处理复杂的交互场景非常有用,比如在地图上显示多个
Marker
,并且希望在点击其中一个Marker
时触发相应的事件。
- 当鼠标事件发生在该DOM元素上时,会触发地图的
getAttribution()
:获取图层的属性信息。_layerAdd(e)
:图层添加到地图时的回调函数,主要用于处理事件绑定、图层添加到地图的逻辑。其中主要涉及到两个方法getEvents
和onAdd
,分别用于获取图层相关的事件和图层添加到地图后的逻辑,它们都是在Layer
基类的子类中实现。
# Layer
类深入
流程
- 挂载到地图实例,检查缩放动画状态
- 通过
getEvents
获取子类的事件监听配置(如zoomend
、move
) - 绑定事件到地图实例,图层移除时自动解绑
- 调用子类实现的
onAdd
方法,执行图层添加到地图的逻辑 - 触发
add
事件和地图实例的layeradd
事件 - 图层添加到地图后,触发
add
事件和地图实例的layeradd
事件
事件管理
add
事件:当图层添加到地图时触发remove
事件:当图层从地图移除时触发layeradd
事件:当图层添加到地图时触发,传递图层实例作为参数layerremove
事件:当图层从地图移除时触发,传递图层实例作为参数
设计模式
- 模板方法模式:
onAdd
和getEvents
由子类实现,父类Layer
定义流程 - 发布-订阅模式:通过事件系统实现图层与地图间通信
- 模板方法模式:
# Map
类与Layer
类交互方法
Map
类混入如下:
Map.include({
addLayer: function (layer) {
if (!layer._layerAdd) {
throw new Error("The provided object is not a Layer.");
}
var id = Util.stamp(layer);
if (this._layers[id]) {
return this; // 避免重复添加
}
this._layers[id] = layer; // 存储图层
layer._mapToAdd = this; // 标记图层待添加到此地图
if (layer.beforeAdd) {
layer.beforeAdd(this); // 钩子:图层添加前的预处理
}
this.whenReady(layer._layerAdd, layer); // 地图就绪后触发图层初始化
return this;
},
removeLayer: function (layer) {
var id = Util.stamp(layer);
if (!this._layers[id]) {
return this;
}
if (this._loaded) {
layer.onRemove(this); // 调用图层清理逻辑
}
delete this._layers[id]; // 移除图层引用
if (this._loaded) {
this.fire("layerremove", { layer: layer }); // 触发地图layerremove事件
layer.fire("remove"); // 触发图层remove事件
}
layer._map = layer._mapToAdd = null; // 清除关联
return this;
},
hasLayer: function (layer) {
return Util.stamp(layer) in this._layers; // 检查图层是否存在
},
eachLayer: function (method, context) {
for (var i in this._layers) {
method.call(context, this._layers[i]); // 遍历所有图层执行method方法
}
return this;
},
_addLayers: function (layers) {
layers = layers ? (Util.isArray(layers) ? layers : [layers]) : []; // 统一转为数组
for (var i = 0, len = layers.length; i < len; i++) {
this.addLayers(layers[i]); // 批量添加图层
}
},
_addZoomLimit: function (layer) {
if (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
this._zoomBoundLayers[Util.stamp(layer)] = layer; // 记录有限制的图层
this._updateZoomLevels(); // 更新地图缩放范围
}
},
_removeZoomLimit: function (layer) {
var id = Util.stamp(layer);
if (this._zoomBoundLayers[id]) {
delete this._zoomBoundLayers[id]; // 移除记录
this._updateZoomLevels(); // 更新地图范围
}
},
_updateZoomLevels: function () {
var minZoom = Infinity,
maxZoom = -Infinity,
oldZoomSpan = this._getZoomSpan();
// 遍历所有有限制的图层,计算全局最小/最大缩放
for (var i in this._zoomBoundLayers) {
var options = this._zoomBoundLayers[i].options;
minZoom =
options.minZoom === undefined
? minZoom
: Math.min(minZoom, options.minZoom);
maxZoom =
options.maxZoom == undefined
? maxZoom
: Math.max(maxZoom, options.maxZoom);
}
this._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;
this._layersMinZoom = minZoom === Infinity ? undefined : minZoom;
// 触发事件通知缩放范围变化
if (oldZoomSpan !== this._getZoomSpan()) {
this.fire("zoomlevelschange");
}
// 自动调整当前缩放级别到有效范围
if (
this.options.maxZoom === undefined &&
this._layersMaxZoom &&
this.getZoom() > this._layersMaxZoom
) {
this.setZoom(this._layersMaxZoom);
}
if (
this.options.minZoom == undefined &&
this._layersMinZoom &&
this.getZoom() < this._layersMinZoom
) {
this.setZoom(this._layersMinZoom);
}
},
});
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# Map
类扩展详解
上述代码主要实现地图对图层的管理,比如图层的添加、移除、遍历管理,以及处理图层缩放级别限制的逻辑
# 方法介绍
addLayer(layer)
- 作用:将图层添加到地图
- 关键步骤
- 检查图层合法性,即参数
layer
需要存在_layerAdd
方法 - 通过
Util.stamp
生成唯一ID避免重复 - 调用
beforeAdd
钩子(如TileLayer
预加载) - 地图就绪后调用
_layerAdd
(触发图层渲染)
- 检查图层合法性,即参数
removeLayer(layer)
- 作用:从地图移除图层
- 关键步骤:
- 调用
onRemove
清理DOM或事件 - 触发
layerremove
事件和remove
事件 - 清除图层关联
- 调用
hasLayer(layer)
和eachLayer(fn)
- 用途
hasLayer
:检查图层是否存在eachLayer
:遍历所有图层执行回调函数
- 用途
_addLayers(layers)
- 场景:处理单个或多个图层参数,简化调用
_addZoomLimit(layer)
和_removeZoomLimit(layer)
- 用途:
_addZoomLimit
:记录有限制的图层_removeZoomLimit
:移除记录的图层
- 用途:
_updateZoomLevels()
- 作用:更新地图的缩放级别范围
- 关键步骤:
- 遍历所有有限制的图层,计算全局最小/最大缩放
- 更新
_layersMaxZoom
和_layersMinZoom
- 触发
zoomlevelschange
事件通知缩放范围变化 - 自动调整当前缩放级别到有效范围
# 总结
# Layer
基类
Leaflet中Layer
基类为所有图层提供了基础功能:
- 生命周期管理:添加到地图、移除、事件绑定。
- DOM 和交互管理:通过窗格挂载内容,注册交互目标。
- 版权信息收集:统一处理版权显示。
- 事件系统集成:支持自定义事件响应。
子类只需专注于具体的渲染逻辑(如 onAdd
)和交互实现,复用基础能力。例如,TileLayer
负责加载瓦片,Marker
负责显示图标,均继承自 Layer
。
# Map
类扩展
Leaflet 的 Map
类提供了核心的图层管理能力:
- 生命周期管理:添加、移除、遍历图层。
- 事件驱动:通过事件通知图层状态变化。
- 缩放限制协调:动态调整地图缩放范围,确保所有图层的可见性约束被满足。
- 扩展性:通过钩子方法(
beforeAdd
、onRemove
)支持自定义图层行为