前端开发必须了解的 - svg

525 阅读6分钟

什么是svg?

SVG 意为 可缩放矢量图形 (Scalable Vector Graphics)。

SVG 是一种 用于描述二维图形的 XML 标记语言 ,与位图图像不同,SVG 图像以文本形式存储,并且可以缩放到任意大小而不会失真,因为它们 基于数学描述而不是像素

SVG 图形是可伸缩的,无需分辨率依赖,这意味着它们可以在不失真的情况下被放大或缩小。

SVG 广泛应用于网页设计、图标制作、数据可视化和其他图形相关的领域。

特点

  • 矢量图形: SVG 使用基于路径的矢量图形,这意味着图形可以无限放大而不失真。
  • 可伸缩性: SVG 文件可以在不同的分辨率下保持清晰,适合用于响应式设计。
  • 互动性: SVG 可以与 JavaScript 结合,实现动画和交云效果。
  • 集成性: SVG 可以直接嵌入 HTML5 中,无需使用外部文件。
  • 兼容性: 大多数现代浏览器都支持 SVG。

应用场景

  • 网页图标: 由于 SVG 的可伸缩性,它非常适合用来制作网页图标。
  • 数据可视化: SVG 常用于图表和图形的创建,如条形图、饼图等。
  • 动画: SVG 可以与 CSS 和 JavaScript 结合,创建复杂的动画效果。
  • 游戏开发: 在某些情况下,SVG 也被用于创建简单的游戏图形。
  • 设计原型: 设计师可以使用 SVG 来创建可交互的设计原型。

基本语法

SVG 文档由一个或多个 SVG 元素组成,它们定义了图形的内容和属性。

<svg
	width="200"     <!-- 指定SVG画布的宽度 -->
	height="200"    <!-- 指定SVG画布的高度 -->
	xmlns="http://www.w3.org/2000/svg">   <!-- 指定SVG命名空间 -->
	<!-- SVG图形内容 -->
</svg>

绘制的基本图形

  • <rect>:绘制矩形
  • <circle>:绘制圆形
  • <ellipse>:绘制椭圆
  • <line>:绘制直线
  • <polyline>:绘制折线
  • <polygon>:绘制多边形
  • <path>:绘制路径

矩形(Rectangles): 使用 <rect> 元素绘制矩形,可以指定矩形的位置、大小、圆角等属性。

<rect x="50" y="50" width="100" height="50" rx="10" ry="10" fill="blue" />

圆形(Circles) :使用 <circle> 元素绘制圆形,可以指定圆心坐标和半径。

<circle cx="100" cy="100" r="50" fill="red" />

椭圆(Ellipses): 使用 <ellipse> 元素绘制椭圆,可以指定椭圆的中心坐标和长短轴的半径。

<ellipse cx="100" cy="100" rx="80" ry="50" fill="green" />

直线(Lines): 使用 <line> 元素绘制直线,需要指定起点和终点坐标。

<line x1="50" y1="50" x2="150" y2="150" stroke="black" stroke-width="2" />

多边形(Polygons): 使用 <polygon> 元素绘制多边形,需要指定多个顶点的坐标。

<polygon points="100,50 150,150 50,150" fill="orange" />

折线(Polylines): 使用 <polyline> 元素绘制折线,需要指定多个点的坐标。

<polyline points="100,50 150,150 50,150" fill="none" stroke="blue" stroke-width="2" />

路径(Paths): 使用 <path> 元素绘制路径,可以通过指定一系列的路径命令来绘制各种形状。

<path d="M10 10 L90 10 L90 90 Z" fill="none" stroke="black" stroke-width="2" />

渐变和填充:

  • 使用 <linearGradient><radialGradient> 定义渐变。
  • 使用 fillstroke 属性指定填充和描边样式。

文本和字体:

  • 使用 <text> 元素插入文本。
  • 使用 font-familyfont-size 等属性控制文本样式。

动画和交互:

  • 使用CSSJavaScript创建动画效果。
  • 添加事件处理器实现交互功能,如鼠标点击、悬停等。

SVG 元素属性:

<circle
  cx="100"       <!-- 圆心的x坐标 -->
  cy="100"       <!-- 圆心的y坐标 -->
  r="50"         <!-- 圆的半径 -->
  fill="red"     <!-- 填充颜色 -->
  stroke="black" <!-- 描边颜色 -->
  stroke-width="2" <!-- 描边宽度 -->
/>

嵌套和分组:

SVG 元素可以嵌套和分组,以便更好地组织和管理图形元素。

<g id="group1">   <!-- 定义一个分组 -->
  <!-- 分组内的图形元素 -->
  <rect x="10" y="10" width="50" height="50" />
  <circle cx="100" cy="100" r="30" />
</g>
  • <g> 元素用于创建一个分组。
  • id 属性用于为分组指定一个唯一的标识符。

html中使用svg

SVG 文件可通过以下标签嵌入 HTML 文档:<img><object> 或者 <iframe>

SVG 的代码可以直接嵌入到 HTML 页面中,或您可以直接链接到 SVG 文件。

<!-- src 属性指定 SVG 文件的路径 -->
<img src="example.svg" alt="SVG Image" width="200" height="200">

<!-- data 属性指定 SVG 文件的路径,type 属性指定资源的 MIME 类型 -->
<object data="example.svg" type="image/svg+xml" width="200" height="200">
  Your browser does not support SVG
</object>

<!-- src 属性指定 SVG 文件的路径 -->
<iframe src="example.svg" width="200" height="200"></iframe>
使用 CSS 背景图

通过 CSSbackground-image 属性,可以将 SVG 图像作为背景图嵌入到 HTML 元素中。这种方法适用于需要在 CSS 中控制背景图样式的情况。

.svg-bg {
	width: 200px;
	height: 200px;
	background-image: url('circle1.svg');
	background-size: cover;
}

基本图形

  • <rect>:绘制矩形
  • <circle>:绘制圆形
  • <ellipse>:绘制椭圆
  • <line>:绘制直线
  • <polyline>:绘制折线
  • <polygon>:绘制多边形
  • <path>:绘制路径

path 讲解

SVG 中的 <path> 元素用于创建路径,它是 SVG 中最强大和最灵活的基本形状之一。

使用 <path> 元素可以绘制直线、曲线、弧线等各种复杂的图形,并且可以通过设置路径命令来控制路径的形状和样式。

<path
  d="path-data"            <!-- 定义路径的路径数据 -->
  fill="fill-color"        <!-- 路径的填充颜色 -->
  stroke="stroke-color"    <!-- 路径的描边颜色 -->
  stroke-width="width"     <!-- 路径的描边宽度 -->
/>

重点就是这个属性 d

  • d 属性定义了路径的路径数据,即路径命令序列。路径数据由一系列的路径命令组成,每个路径命令以字母开头,后面跟随一组数字参数。常用的路径命令包括:M (移动到)、 L (直线到)、 H (水平线到)、 V (垂直线到)、 C (三次贝塞尔曲线)、 S (光滑曲线)、 Q (二次贝塞尔曲线)、 T (光滑二次贝塞尔曲线)、 A (圆弧)、 Z (闭合路径) 等。

另外 svg 支持 滤镜、模糊、阴影、渐变-线性、渐变-放射 等。

拓展

我们如何实现将DOM节点转化为图片。这里我们参考了包括 html2canvas等在内的库之后发现,原理也是基于svg的实现。

  • 利用SVGforeignObject元素能嵌入html元素的特性,将要导出的DOM节点嵌入到SVG中;
  • 通过img元素渲染svg
  • 通过canvas绘制img,调用导出方法导出为blobdata:url数据;
  • 通过a标签下载到本地;

首先来一段简单的DOM结构作为要导出的节点:

<div
  id="el"
  style="border: 1px solid lightcoral;
  padding: 10px;
  width: 250px;
  height: 250px;
  background-color: #fff;">
  <h1>foreignObject</h1>
  <p>
    SVG中的<span style="font-weight: bold; color: lightblue">foreignObject</span>
      元素允许包含来自不同的 XML 命名空间的元素。在浏览器的上下文中,很可能是
    <span style="background-color: lightseagreen; color: #fff">
        XHTML / HTML
    </span></p>
</div>

然后我们将这个节点克隆一下,并拼接成SVG字符串:

const el = document.getElementById('el')
// 获取节点大小
const rect = el.getBoundingClientRect()
// 克隆一份
const clone = el.cloneNode(true)
// 添加xhtml命名空间
clone.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
// 拼接svg字符串
const svgStr = `<svg xmlns="http://www.w3.org/2000/svg" width="${rect.width}" height="${rect.height}">
<foreignObject width="${rect.width}" height="${rect.height}">${clone.outerHTML}</foreignObject>
</svg>`

首先获取了一下要导出节点的大小,然后设置到svg节点上,接下来我们还给克隆的节点添加了命名空间的属性,这个是必要的,否则最后导出将是空白的,最后我们将被导出的DOM节点的html字符串拼接到foreignObject标签中即可。

接下来使用Blob对象将svg字符串转换为blob数据,然后我们通过FileReader对象读取。因为img标签并不能直接渲染blob数据,所以我们还要把blob转换为data:url数据:

const blob = new Blob([svgStr], {
    type: 'image/svg+xml'
})
const reader = new FileReader()
reader.onload = evt => {
    // evt.target.result
}
reader.readAsDataURL(blob)
const img = new Image()
img.onload = () => {
    ctx.drawImage(img, 0, 0)
}
img.src = svgUrl