本篇作为技术分享系列的第一篇,详细讲一下 SVG 的解析和绘制,这部分功能的研究和最终实现由团队的 @黄超超 同学负责,感谢提供技术文档和支持。
首先我们来看一下 SVG 的文件结构和组成
SVG (Scalable Vector Graphics) 是一种可缩放矢量图形,使用 XML 格式来定义,是一种 W3C 标准,图像在放大或改变尺寸的情况下其图形质量不会有所损失。
下面是一个简单的 SVG 的文件结构例子:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>
从文件结构来看,SVG 确实是一种标准的 XML 格式,而里面的元素,从字面上来看,是一个坐标为(100,50),半径为40,填充色为红色,线条为黑色,线宽为2的圆形。下面我们来看看 SVG 文件里面的基本元素和属性:
1. 结构元素
<defs>, <g>, <svg>, <symbol>, <use>
2. 图形元素
<line>, <circle>, <ellipse>, <polygon>, <polyline>, <rect>, <path>
这些标签相信大家都不陌生,几乎每种界面语言都有类似的标记。在 SVG 里,最常用的还是<path>, 用它可以表示前面所有的标签。
3. 特殊元素
<image> :图片,源通常由 base64 string 或 url 表示。它通常出现在这种场景:通过 PhotoShop 编辑一张图片后,导出为 SVG 格式,这时文件里就存在 <image> 标签,之后再导入到 AI 中进行路径编辑,导出为 SVG 格式,就有了一张可以描绘路径,又包含 <image> 底图的 SVG 文件了。
<text> :文本,设置文字内容和字体字号等信息后,就可以在 SVG 中显示这些文字。 <text> 支持 transform 属性,可以旋转缩放文字,同时还支持 style, css 代码可以直接添加进来。
完整的元素列表参考这里:https://developer.mozilla.org/zh-CN/docs/Web/SVG/element
4. 元素的若干属性
opacity, fill, stroke, stroke-width, stroke-miterlimit, fill-opacity, stroke-opacity, fill-rule, stroke-dasharray, stroke-dashoffset, stroke-linecap, stroke-linejoin, transform
这些都不难理解,代表了元素的透明度,填充,线条,变换等,因为 SVG 是 W3C 标准,所以以上这些外观属性,在 CSS 中都有对应的属性。另外,SVG 还支持其他的属性类型,如动画事件/动画定时/关键帧动画/图形属性/过滤器等,十分强大。
完整的属性列表参考这里:https://developer.mozilla.org/zh-CN/docs/Web/SVG/attribute
来看一个例子:自上而下,分别包含了 两个矩形,一个圆形,一个椭圆,一条直线,一条折线,一个多边形和一条自定义 path。
<?xml version="1.0" standalone="no"?>
<svg width="200" height="250" version="1.1" viewBox="0 0 200 250" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
<rect x="60" y="10" rx="10" ry="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
<circle cx="25" cy="75" r="20" stroke="red" fill="transparent" stroke-width="5"/>
<ellipse cx="75" cy="75" rx="20" ry="5" stroke="red" fill="transparent" stroke-width="5"/>
<line x1="10" x2="50" y1="110" y2="150" stroke="orange" fill="transparent" stroke-width="5"/>
<polyline points="60,110 65,120 70,115 75,130 80,125 85,140 90,135 95,150 100,145"
stroke="orange" fill="transparent" stroke-width