SVG.VML
# 概述
SVG.VML
在Leaflet中用于旧版IE浏览器(IE5-IE8)的向后兼容支持,通过VML(Vector Markup Language)渲染矢量图形的兼容性实现。
# 源码分析
# 源码实现
SVG.VML
的源码实现如下:
export var vmlCreate = (function () {
try {
// IE中注册VML命名空间
document.namespaces.add("lvml", "urn:schemas-microsoft-com:vml");
return function (name) {
return document.createElement("<lvml:" + name + ' class="lvml">');
};
} catch (e) {}
// 非IE浏览器直接创建元素
return function (name) {
return document.createElement(
"<" + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">'
);
};
})();
// VML 渲染器混入
export var vmlMixin = {
_initContainer: function () {
this._container = DomUtil.create("div", "leaflet-vml-container"); // 创建根容器
},
_update: function () {
if (this._map._animatingZoom) {
return;
}
Renderer.prototype._update.call(this);
this.fire("update");
},
_initPath: function (layer) {
var container = (layer._container = vmlCreate("shape"));
DomUtil.addClass(
container,
"leaflet-vml-shape " + (this.options.className || "")
);
container.coordsize = "1 1";// 定义坐标系比例
layer._path = vmlCreate("path");
container.appendChild(layer._path);
this._updateStyle(layer);
this._layers[Util.stamp(layer)] = layer;
},
_addPath: function (layer) {
var container = layer._container;
this._container.appendChild(container);
if (layer.options.interactive) {
layer.addInteractiveTarget(container);
}
},
_removePath: function (layer) {
var container = layer._container;
DomUtil.remove(container);
layer.removeInteractiveTarget(container);
delete this._layers[Util.stamp(layer)];
},
_updateStyle: function (layer) {
var stroke = layer._stroke,
fill = layer._fill,
options = layer.options,
container = layer._container;
container.stroked = !!options.stroke; //是否描边
container.filled = !!options.fill; // 是否填充
if (options.stroke) {
if (!stroke) {
stroke = layer._stroke = vmlCreate("stroke"); // 创建描边子元素
}
container.appendChild(stroke);
stroke.weight = options.weight + "px"; // 描边宽度
stroke.color = options.color; // 描边颜色
stroke.opacity = options.opacity; // 透明度
// 虚线样式
if (options.dashArray) {
stroke.dashStyle = Util.isArray(options.dashArray)
? options.dashArray.join(" ")
: options.dashArray.replace(/( *, *)/g, " ");
} else {
stroke.dashStyle = "";
}
stroke.endcap = options.lineCap.replace("butt", "flat");
stroke.joinstyle = options.lineJoin;
} else if (stroke) {
container.removeChild(stroke);
layer._stroke = null;
}
// 填充样式
if (options.fill) {
if (!fill) {
fill = layer._fill = vmlCreate("fill");
}
container.appendChild(fill);
fill.color = options.fillColor || options.color;
fill.opacity = options.fillOpacity;
} else if (fill) {
container.removeChild(fill);
layer._fill = null;
}
},
_updateCircle: function (layer) {
var p = layer._point.round(),
r = Math.round(layer._radius),
r2 = Math.round(layer._radiusY || r);
this._setPath(
layer,
layer._empty()
? "M0 0"
: "AL " + p.x + "," + p.y + " " + r + "," + r2 + " 0," + 65535 * 360
);
// 65535 * 360 是 VML 中表示 360 度的特殊值(角度单位为 1/65535 度
},
_setPath: function (layer, path) {
layer._path.v = path;
},
_bringToFront: function (layer) {
DomUtil.toFront(layer._container);
},
_bringToBack: function (layer) {
DomUtil.toBack(layer._container);
},
};
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
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# 关键方法解析
_initPath(layer)
初始化路径
- VML元素结构
<shape>
:VML的图像容器,类比SVG的<g>
<path>
:VML的路径元素,存储路径数据coordsize
:属性定义坐标系缩放比例
路径更新_setPath
- VML路径存储
VML的
<path>
元素的路径数据存储在v
属性中,而非SVG的d
属性
# 与SVG渲染器的对比
特性 | SVG渲染器 | VML渲染器 |
---|---|---|
DOM结构 | 使用<svg> 和<path> | 使用<div> 包裹<shape> 和<path> |
样式设置 | 通过元素属性(如stroke 、fill ) | 通过子元素(如<stroke> 、fill ) |
路径语法 | 标准SVG路径(M 、L 、A 等) | VML特有语法 |
浏览器支持 | 现代浏览器 | IE6-8 |
性能 | 较高(硬件加速) | 较低(纯软件) |
# 设计思想总结
- 兼容性优先
Leaflet 通过动态检测浏览器支持(
Browser.vml
),自动选择 SVG 或 VML 渲染器。 - 代码复用
VML 渲染器通过混入(
vmlMixin
)覆盖 SVG 的部分方法,避免重复代码。 - 历史包袱 由于 VML 已被废弃,这段代码仅用于支持旧版 IE,现代浏览器无需加载。
# 最终效果
在 IE6-IE8 中,矢量图形(如折线、多边形)通过 VML 渲染。
无需关心底层实现,Leaflet 统一 API(如
L.polyline
)自动适配渲染器。
SVG.VML
体现了 Leaflet 在兼容性上的细致考量,确保了在老旧浏览器中仍能提供基本功能。
编辑 (opens new window)
上次更新: 2025/05/12, 07:40:30