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
        • 概述
        • 源码分析
          • 源码实现
          • 关键方法解析
          • 与SVG渲染器的对比
          • 设计思想总结​​
          • 最终效果​​
      • CircleMarker
      • Circle
    • Layer
    • LayerGroup
    • FeatureGroup
    • DivOverlay
    • Popup
    • Tooltip
    • ImageOverlay
    • SVGOverlay
    • VideoOverlay
    • GeoJSON
  • Map

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

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

# 关键方法解析

_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
SVG.Util
CircleMarker

← SVG.Util CircleMarker→

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