SVG 从零开始绘图(一)

364 阅读3分钟

概要

本文主要将 SVG 的基础和折线图的绘制,如果对此不感兴趣的,就可以不用阅读后续了。

SVG 简介

SVG 的全称是 (Scalable Vector Graphics), 它是使用 XML 来描述二维图形和绘图程序的语言;它是一个可缩放的矢量图形。

对于前端工程师来说,使用 SVG 的门槛还是相对很低的。因为开发方式和 html 类似,并且 css 和 JavaScript 都能作用于 SVG 上面。甚至,我们可以认为,SVG 就是 HTML 的增强版

学习前必备知识

SVG 的优势

  • SVG 是可伸缩的。
  • SVG 是由点来存储,由于计算机是根据点信息绘图,不会失真,所以不用考虑适配问题。
  • SVG 可以转换 Path 路径,与 Path 动画相结合,可以形成更丰富的动画。
  • SVG 使用 XML 格式定义图形,,可被非常用的多的工具读取和修改。
  • ...

SVG 标签基础信息

<svg width='100px' height='100px' viewBox="0 0 50 50">
</svg>
  • xmlns - SVG 命名空间
  • version - 版本号
  • width - 宽度(和canvas中的属性类似)
  • height - 高度
  • viewBox - 表示视口;前两个是坐标(左上角为00, 这时从 0,0 点开始)后两个是长度和宽度,表示(0-50,0-50 的图形)。实际上获取的svg图形是界面中的右下角的一部分。

line 直线

属性如下:

  • x1 属性在 x 轴定义线条的开始
  • y1 属性在 y 轴定义线条的开始
  • x2 属性在 x 轴定义线条的结束
  • y2 属性在 y 轴定义线条的结束
<svg xmlns="" version="1.1">
  <line x1="0" y1="0" x2="200" y2="300" style="stroke:red;stroke-width:2" />
</svg>

polyline 曲线 - 元素是用于创建任何只有直线的形状

<svg xmlns="test2" version="1.1">
  <polyline points="20,20 40,25 60,40 80,120 120,140 200,180"
  style="fill:none;stroke:black;stroke-width:3" />
</svg>

path 路径 - 元素用于定义一个路径。

  • M = moveto(M x, y) - 将画笔移动到指定的地方
  • L = lineto(L x, y) - 画直线到指定的坐标位置
  • H = horizontal lineto(H x) - 画水平线到指定的 X 坐标位置
  • V = vertical lineto(V, y) - 画垂直线到指定的 Y 坐标位置
  • C = curveto(C x1,y1,x2,y2,endX,endY) - 三阶贝济埃曲线
  • S = smooth curveto(S x2,y2,endX,endY) - 三阶贝济埃曲线
  • Q = quadratic Bézier curve(Q x,y,endX,endY) - 二阶贝济埃曲线
  • T = smooth quadratic Bézier curveto(T endX,endY) - 映射前面路径后的终点
  • A = elliptical Arc(A RX,RY,XROTATION,FLAYG1,FLAY2,X,Y) - 弧线
  • Z = closepath - 关闭路径 我们可以绘制一个开始位置0 0,到达 200,200 位置,然后再到220 300,最后关闭
<svg xmlns="test3" version="1.1">
  <path d="M0 0 L200 200 L220 300 Z" fill="red"/>
</svg>

看了前面绘制的一些简单图形,那我们怎样才能学 echarts 那样绘制折线图,曲线图呢?请继续往下看

DEMO1 - 绘制折线图

我们可以先来看下效果图

image.png

要实现上面的图形,我们可以进行以下的步骤拆分

第一步,画坐标轴

x轴

image.png

<svg width="400" height="200">
	<g class="x axis" transform="translate(0, 140)">
                <!-- X轴-->
		<line x1="0" y1="0" x2="270" y2="0" style="stroke:gray;stroke-width:1"/> 
		<!-- x轴刻度 -->
		<line x1="30" y1="0" x2="30" y2="10" style="stroke:gray;stroke-width:1"/>
		<line x1="250" y1="0" x2="250" y2="10" style="stroke:gray;stroke-width:1"/>
		<!-- X轴头部箭头-->
		<line x1="270" y1="0" x2="265" y2="-5" style="stroke:gray;stroke-width:1"/>
		<line x1="270" y1="0" x2="265" y2="5" style="stroke:gray;stroke-width:1"/>
		<!-- x轴刻度值 -->
		<text x="30" y="20" style="font-size: 10px;">30</text>
		<text x="240" y="20"  style="font-size: 10px;">250</text>
	</g>
</svg> 

y 轴类似

image.png

 <g class="y axis" transform="translate(100,20)">
			<!-- y轴 -->
		   <line x1="0" y1="0" x2="0" y2="120" style="stroke:gray;stroke-width:1"/>
		   <!-- y轴刻度 -->
		   <line x1="-10" y1="105" x2="0" y2="105" style="stroke:gray;stroke-width:1"/>
		   <line x1="-10" y1="90" x2="0" y2="90" style="stroke:gray;stroke-width:1"/>
		   <line x1="-10" y1="60" x2="0" y2="60" style="stroke:gray;stroke-width:1"/>
		   <line x1="-10" y1="30" x2="0" y2="30" style="stroke:gray;stroke-width:1"/>
		   <line x1="-10" y1="0" x2="0" y2="0" style="stroke:gray;stroke-width:1"/>
		   <!-- y轴头部箭头-->
		   <g class="ytop">
			   <line x1="0" y1="0" x2="0" y2="-10" style="stroke:red;stroke-width:1"/>
			   <line x1="0" y1="-10" x2="5" y2="-5" style="stroke:red;stroke-width:1"/>
			   <line x1="0" y1="-10" x2="-5" y2="-5" style="stroke:red;stroke-width:1"/>
		   </g>
		   <!-- y轴刻度值 -->
		   <text x="-30" y="105" dy="5" style="font-size: 10px;">10</text>
		   <text x="-30" y="0"   dy="5" style="font-size: 10px;">80</text>
	</g>

第二步 画线

画线这步单独拆分出来其实也很简单,只需要先绘制几个点,然后 使用polyline 把这些点给串起来就行了。

image.png

<svg width="400" height="200">
   <g class="data" transform="translate(40,10)">
       <circle r="5" cx="0"   cy="105" fill="red"/>
       <circle r="5" cx="180" cy="60"  fill="red"/>
       <circle r="5" cx="250" cy="0"   fill="red"/>
       <!-- 数据连接成线 -->
       <polyline points="0,105, 180,60 250,0" fill="none" stroke="black" />
    </g>
</svg> 

第三步 合成

最后一步,将上述的绘制进行合成就可以组成我们想要的折线图了。

<svg width="400" height="200">
          <g class="layer" transform="translate(40,10)">
            <!-- 数据点 -->
            <g class="data">
                <circle r="5" cx="0"   cy="105" fill="red"/>
                <circle r="5" cx="180" cy="60"  fill="red"/>
                <circle r="5" cx="250" cy="0"   fill="red"/>
                <!-- 数据连接成线 -->
                <polyline points="0,105, 180,60 250,0" fill="none" stroke="black" />
            </g>
            <g class="y axis">
			  <!-- y轴 -->
              <line x1="0" y1="0" x2="0" y2="120" style="stroke:gray;stroke-width:1"/>  
              <!-- y轴刻度 -->
              <line x1="-10" y1="105" x2="0" y2="105" style="stroke:gray;stroke-width:1"/>
              <line x1="-10" y1="90" x2="0" y2="90" style="stroke:gray;stroke-width:1"/>
              <line x1="-10" y1="60" x2="0" y2="60" style="stroke:gray;stroke-width:1"/>
              <line x1="-10" y1="30" x2="0" y2="30" style="stroke:gray;stroke-width:1"/>
              <line x1="-10" y1="0" x2="0" y2="0" style="stroke:gray;stroke-width:1"/>
              <!-- y轴头部箭头-->
              <g class="ytop">
                 <line x1="0" y1="0" x2="0" y2="-10" style="stroke:red;stroke-width:1"/>
                 <line x1="0" y1="-10" x2="5" y2="-5" style="stroke:red;stroke-width:1"/>
                 <line x1="0" y1="-10" x2="-5" y2="-5" style="stroke:red;stroke-width:1"/>
              </g>
              <!-- y轴刻度值 -->
              <text x="-30" y="105" dy="5" style="font-size: 10px;">10</text>
              <text x="-30" y="0"   dy="5" style="font-size: 10px;">80</text>
            </g>
            
            <g class="x axis" transform="translate(0, 120)">
               <!-- X轴-->
              <line x1="0" y1="0" x2="290" y2="0" style="stroke:gray;stroke-width:1"/>
              <!-- x轴刻度 -->
              <line x1="30" y1="0" x2="30" y2="10" style="stroke:gray;stroke-width:1"/>
              <line x1="250" y1="0" x2="250" y2="10" style="stroke:gray;stroke-width:1"/>
              <!-- X轴头部箭头-->
              <line x1="290" y1="0" x2="284" y2="-5" style="stroke:gray;stroke-width:1"/>
              <line x1="290" y1="0" x2="284" y2="5" style="stroke:gray;stroke-width:1"/>
              <!-- x轴刻度值 -->
              <text x="30" y="20" style="font-size: 10px;">30</text>
              <text x="240" y="20"  style="font-size: 10px;">250</text>
            </g>
          </g>
        </svg>

思考,我们看echarts 里面有很多的自定义配置,比如还有一些线条的渐变,这怎么实现呢?

渐变 -

渐变有两种方式,线性渐变 和 放射性渐变,感兴趣的可以进行测试

  • - 元素用于定义线性渐变
  • - 元素用于定义放射性渐变

本次文章就到这里,后面会写一写关于 js 来结合 SVG 的demo,加入浮层hover效果。