【笔记类】SVG

161 阅读3分钟

一、理解html、xhtml、xml

1734442-20190722194556639-2105004736.png

html是超文本标记语言,xml是可拓展的标记语言,两者均是从SGML(标准通用标记语言)中抽取发展而来,html的语法比较松散、扩充性也不太好,所以出现了xhtml(可拓展的超文本标记语言),它本质上属于xml的方言,不过这玩意随着html5的流行就被淘汰掉了。

二、xmlns、xmlns:xlink和version

xmlns是xml命名空间,用来告诉浏览器接下来的标签属于xml的哪种方言。内联svg可以不写,但是外部使用时必须写。

<html xmlns="http://www.w3.org/1999/xhtml">
  <body>
    <!-- 在这里放置一些 XHTML 标签 -->
    <svg xmlns="http://www.w3.org/2000/svg" width="300px" height="200px">
      <!-- 在这里放置一些 SVG 标签 -->
    </svg>
    <!-- 在这里放置一些 XHTML 标签 -->
  </body>
</html>

xmlns:xlink,声明了一个命名空间,该命名空间以xlink作为前缀。内联svg可以不写,但是外部使用时带有xlink:的必须写。

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <script xlink:href="cool-script.js" type="text/ecmascript"/>
</svg>

version用于指明svg文档遵循的规范,有1.0和1.1。该属性纯粹是一个说明,对渲染和处理无任何影响。

三、svg标签的宽高和viewBox之间的关系

注:与img标签一致,CSS宽高会覆盖掉svg标签上的宽高

计算关系如下:

<!-- 什么都不写,则 width:300, height:150, viewBox: 0 0 300 150 -->
<svg></svg>

<!-- 只写宽高,则 viewBox: 0 0 width height -->
<svg width="200" height="100"></svg>

<!-- 只写viewBox,则 width=父元素宽, height=父元素宽/200*100 -->
<svg viewBox="0 0 200 100"></svg>

<!-- 写宽高中的一个和viewBox,则这里的height=300/200*100=150 -->
<svg width="300" viewBox="0 0 200 100"></svg>

来个实际的例子:

<svg width="300" viewBox="0 0 200 100">
  <!-- 下面的百分比都是根据viewBox来计算的,width=200*100%=200, height=100*80%=80 -->
  <rect x="0" y="0" width="100%" height="80%"></rect>
  <!-- cx=200*50%=100, cy=100*70%=70, r=10 -->
  <circle cx="50%" cy="70%" r="10" fill="white"></circle>
</svg>

<!-- 若上面的r写成百分比形式如 10%,计算方式为:√(200^2+100^2) / √2 * 10% = 15.81 -->

⬆️ 算出来的是一个宽200、高80的矩形,和一个半径10的圆。

789CC1B3-DBF8-45F6-81F4-28A09A699FF1.png

实际上画出来的是一个宽300、高120的矩形,和一个半径15的圆。这是因为当 SVG 的 viewbox 属性与视图属性宽高比一致时,会自动缩放。

(1)改变viewBox的前两个值看一下

<svg width="300" viewBox="-100 -20 200 100">
  <!-- 下面的百分比都是根据viewBox来计算的,width=200*100%=200, height=100*80%=80 -->
  <rect x="0" y="0" width="100%" height="80%"></rect>
  <!-- cx=200*50%=100, cy=100*70%=70, r=10 -->
  <circle cx="50%" cy="70%" r="10" fill="white"></circle>
</svg>

意思是(-100, -20)这个点作为左上角,画一个宽200、高100的矩形,再自动缩放到300x150的大小。如下图:

D5F7DFA8-5577-4327-A89B-EA7125D83E06.png

(2)设置一下height,让SVG 的 viewbox 属性与视图属性宽高比不一致,此时可以设置preserveAspectRatio该属性来控制图形应该怎么被缩放。

<svg width="300" height="200" viewBox="0 0 200 100" preserveAspectRatio="xMidYMid meet">
  <!-- 下面的百分比都是根据viewBox来计算的,width=200*100%=200, height=100*80%=80 -->
  <rect x="0" y="0" width="100%" height="80%"></rect>
  <!-- cx=200*50%=100, cy=100*70%=70, r=10 -->
  <circle cx="50%" cy="70%" r="10" fill="white"></circle>
</svg>

preserveAspectRatio的默认值为xMidYMid meet,xMidYMid意思是将 viewbox 和视图在x轴和y轴上的中线都对齐,meet可以理解为css里的background-size被设置为contain,slice则可以类比为cover。

71B878FB-CEC7-420D-9CB6-115521707EFC.png

四、path标签

path是用来定义形状的通用元素,基本上所有的形状都可以用path来绘制。SVG 定义了六种路径命令类型,一共 20条命令(大写为绝对坐标,小写为相对坐标):

类型命令注意点
移动到M,m---
画线至L,l H,h V,v---
三次贝塞尔曲线C,c S.ss表示平滑的三次bezier曲线
二次贝塞尔曲线Q,q T,tt表示平滑的二次bezier曲线
椭圆曲线A,a半径不满足其余条件时,会等比放大
封闭路径Z,z大小写无区别
<svg width="400" height="200" stroke="black" stroke-width="3" fill="none">
  <path d="M 10,10 L 30,30 h 20 v 20 c 0,20 20,20 20,0 s 20,-20 20,0 q 20,20 0,40 t 0,40 a 40 20 0 1 1 -80,0 Z" />
</svg>

从(10, 10)开始画一条到(30, 30)的线,再水平画一条长20的线,再垂直画一条长20的线,再画两条三次bezier曲线,再画两条二次bezier曲线,再画一个椭圆曲线,最后闭合。如下:

62399DF9-9EDF-4074-BDE9-042A2470E4CD.png

可参考:svg中path标签的d属性bezier曲线原理

五、一些额外标签

1、use标签、g标签、defs标签。其中use用于复制一个形状;g用于将几个形状合成一个组;defs包裹的标签不会直接显示,仅用于引用。

<svg width="400" height="200">
  <defs>
    <g id="audi" stroke="black" stroke-width="3" fill="none">
      <circle cx="50" cy="50" r="15" />
      <circle cx="70" cy="50" r="15" />
      <circle cx="90" cy="50" r="15" />
      <circle cx="110" cy="50" r="15" />
    </g>
  </defs>
  <use xlink:href="#audi" />
</svg>

9DE25ABD-1471-48F1-A1C3-039CC9243D88.png

2、linearGradient标签、stop标签。其中linearGradient用于定义线性渐变,stop定义颜色坡度。

<svg width="400" height="200">
  <defs>
    <g id="audi" stroke-width="3" fill="none">
      <circle cx="50" cy="50" r="15" />
      <circle cx="70" cy="50" r="15" />
      <circle cx="90" cy="50" r="15" />
      <circle cx="110" cy="50" r="15" />
    </g>

    <linearGradient id="myGradient" gradientTransform="rotate(90)">
      <stop offset="5%"  stop-color="gold" />
      <stop offset="95%" stop-color="red" />
    </linearGradient>
  </defs>

  <use xlink:href="#audi" stroke="url(#myGradient)" />
</svg>

DB80ADFC-A354-4786-8A9D-8C6CF0B09C94.png

3、clipPath标签、pattern标签。其中clipPath用于裁剪,仅在clipPath的范围内显示;pattern用于填充。

<svg width="400" height="200">
  <defs>
    <clipPath id="myClip">
      <circle cx="200" cy="50" r="35" />
    </clipPath>

    <pattern id="star" viewBox="0,0,10,10" width="10%" height="10%">
      <polygon points="0,0 2,5 0,10 5,8 10,10 8,5 10,0 5,2" />
    </pattern>
  </defs>
  
  <!-- 用star填充这个rect -->
  <rect width="100" height="100" fill="url(#star)" />
  <!-- 用star填充这个rect后,再用myClip裁剪 -->
  <rect x="150" width="100" height="100" clip-path="url(#myClip)" fill="url(#star)" />
</svg>

40F4F436-76C8-4605-9024-B8B5F40BEA53.png

4、animate标签、animateTransform标签。除了transform动画需要用animateTransform外,其余动画均可以用animate。

<svg width="400" height="200">
  <image class="" href="./konglong.png">
    <!-- 宽度从0到100 -->
    <animate
      attributeName="width"
      from="0"
      to="100"
      dur="3"
      repeatCount="indefinite"
    ></animate>
    <!-- 旋转360度,基点从(0, 0)到(50, 50) -->
    <animateTransform
      attributeName="transform"
      type="rotate"
      from="0 0 0"
      to="360 50 50"
      dur="3"
      repeatCount="indefinite"
    />
  </image>
</svg>

291891492291361822023-03-08-14-22-26.gif