svg 学习系列-波浪背景

2,678 阅读7分钟

前言

最近想做一个波浪滚动的背景,查询资料后发现使用 svg 可以做。自己动手实践了下,效果如下:

实现

技术选择
首先看到这些波浪是由一些曲线来绘制成的,使用 css 可以通过 border-radius 设置各种角度来实现。但是想想也挺麻烦的,svg 中的 path 可以满足我们的需求。

path 使用

<path>元素是SVG基本形状中最强大的一个。 你可以用它创建线条, 曲线, 弧形等等。

也就是说可以通过 path 来画出你想要的图形,来看看如何通过 path 来画出一个简单的图形。

path元素的形状是通过属性d定义的,属性d的值是一个“命令+参数”的序列

例如

<svg width='300' height='300' version='1.1' xmlns='http://www.w3.org/2000/svg'>
    <path d="M0 0 L30 30" stroke="red"/>
    <circle cx="250" cy="180" r="5" fill="red"></circle>
    <circle cx="100" cy="100" r="5" fill="black"></circle>
</svg>

从上图可以得知

  1. 与我们场景的 X-Y 坐标轴不同的是,Y轴的方向相反。也就是你的y值越大,点的位置越下面。
  2. 先不管 M, L 这些代表什么意思(后续会说),我们需要知道的点是 M,L 这样大写的字母表示命令,后面跟着的是坐标。

常用命令

移动一个点
这里的xy是坐标的位置,关于大小写的差别M后面跟着的坐标是坐标轴中的绝对坐标位置,m跟着的是坐标轴中的相对位置,根上一个点有关

  1. M x y
  2. m dx dy (命令小写的写法)

划线
会在当前位置和新位置之间画一条线,这里的xy是坐标的位置

  1. L x y
  2. l dx dy 简写方式如下
  • H x 画水平线 horizontal
  • V y 画垂直线 vertical
  • Z 闭合曲线

练习:使用path画一个矩形

<svg class="move-wrap" height='300' version='1.1' xmlns='http://www.w3.org/2000/svg'>
        <path d="M0 0 H100 V100 H0 Z" stroke="red" fill="transparent"/>
</svg>

绘制曲线

绘制平滑曲线的命令有三个,其中两个用来绘制贝塞尔曲线(C,Q),另外一个用来绘制弧形或者说是圆的一部分(A)。

二次贝塞尔曲线

命令用Q来表示,当我们选择一个点作为控制点后,画的曲线会分别和两端与控制点连线相切。可以简单的理解为,控制点控制了曲线的凸的程度

x1 y1 表示控制点的位置,x y 表示曲线终点的坐标。

<path d="M100 100 Q x1 y1, x y" 
stroke-width="10" stroke="black" fill="transparent"/>

三次贝塞尔曲线
命令用C来表示,使用如下 前面两个值(120 120 ,160 120)表示两个控制点的位置。最后一个坐标180 100是曲线终点的坐标。

<path d="M100 100 C120 120,160 120,180 100" 
stroke-width="10" stroke="black" fill="transparent"/>

S命令可以用来创建与前面一样的贝塞尔曲线
适用于三次曲线,二次贝塞尔曲线有一个差不多的T命令。

<path d="M0 150 
                 C30 135,60 135, 90 150
                 S150 165,180 150 
                 S240 135,270 150
                 V300 H0 Z" fill="rgba(0, 0, 50, .1)"  stroke-width="1"/>

S240 135 S指令后面需要指定一个控制点,S命令自动补出一个对称的控制点,270 150 表示曲线最终点。

补全
得到两个正弦曲线,想法就是绘制多个这样波浪,每个波浪以一个正弦为周期,向左滑动的动画无限循环。

<path d="M0 150 
                 C30 130,60 130, 90 150
                 S150 170,180 150 
                 S240 130,270 150
                 S330 170,360 150
                 V300 H0 Z" fill="rgba(0, 0, 50, .2)"  stroke-width="3"/>

动画

SVG的动画元素是和SMIL开发组合作开发的。SMIL开发组和SVG开发组合作开发了SMIL动画规范,在规范中制定了一个基本的XML动画特征集合。SVG吸收了SMIL动画规范当中的动画优点,并提供了一些SVG继承实现。

指定动画应用的对象

  1. 通过 xlink:href="#id", animate 和 指定元素要属于同一个 svg 标签下。
<rect id="cool_shape" ... />

<animate xlink:href="#cool_shape" ... />
  1. 嵌套在元素内
<rect id="cool_shape" ... >

  <animate ... />

</rect>

需要应用动画的属性
通过 attributeName 来指定需要过渡的属性,但是它只能接收一个值,如果有多个值的时候需要使用多个 animate 标签来实现。

如移动一个圆点

<svg width='500' height='500' version='1.1' xmlns='http://www.w3.org/2000/svg'>
  <circle  cx="30" cy="30" r="5" fill="red">
    <animate dur="1s" attributeName="cx" to="130"/>
    <animate dur="1s" attributeName="cy" to="130"/>
  </circle>
</svg>

常用属性

  • dur 持续时间 值:3s
  • fill 是否保留动画最后一帧 可选值:freeze/remove
  • begin 可选值: 2s/ click + 1s / 0s
  • restart 动画是否重新开始(出现于动画还在加载过程中,是否运行它重新开始加载) 可选值:always/whenNotActive/never
  • repeatCount 值:2
  • keyTimes="0; 0.5; 0.8; 1" 指定 keyframe 对应的动画,配合 values 一起使用
// 如果 values 有多段值而 keyTimes 没有指定,那么每个阶段都会被均分
<animate
    values="50; 490; 350; 450"
    keyTimes="0; 0.5; 0.8; 1"
    ... />
  • calcMode 设置运动的速率 可选值:linear/paced/spline 具体要用可了解需要哪个速率
  • additive 是否在原先的基础上累加 可选值:sum/replace
<svg width='500' height='500' version='1.1' xmlns='http://www.w3.org/2000/svg'>
  // 从 130 移动到 230
  <circle  cx="130" cy="30" r="15" fill="red">
    <animate dur="1s" attributeName="cx" to="230" restart="never" fill="freeze"></animate>
  </circle>
  // 从 130 移动到 360
  <circle  cx="130" cy="30" r="15" fill="green">
    <animate begin="1s" dur="1s" attributeName="cx" additive="sum" from="0" to="230"  restart="never" fill="freeze"></animate>
  </circle>
</svg>
  • accumulate 在自己上一次动画结束到地方累加 可选值:sum/replace
<svg width='500' height='500' version='1.1' xmlns='http://www.w3.org/2000/svg'>
  // 第二次动画起点是 360 第三次是 460 
  <circle  cx="130" cy="30" r="15" fill="red">
    <animate accumulate="sum" dur="1s" attributeName="cx" to="230" repeatCount="3" fill="freeze"></animate>
  </circle>
</svg>
  • transform 属性改变有专门的 animateTransform 元素 指定attributeName="transform" 然后通过设定 type :(可选值 translate/scale/rotate/skewX/skewY)
<animateTransform 
      xlink:href="#deepPink-rectangle"
      attributeName="transform" 
      attributeType="XML"
      type="rotate"
      from="0 75 75"
      to="360 75 75" 
      dur="2s"
      begin="0s"
      repeatCount="indefinite"
      fill="freeze" 
      />

波浪动画

使用path 画出了波浪的样式,接下来使用 animateTransform 动起来。每次移动移动 180px 相当于画了2个正弦周期,每次动画到一个正弦周期然后回到圆点无限循环。为了让动画效果多样,可以添加多个波浪,并且每个波浪的样式有些许不同(速度、形状、透明度等)

<svg class="move-wrap" height='300' version='1.1' xmlns='http://www.w3.org/2000/svg'>
        <path d="M0 150 
                 C30 130,60 130, 90 150
                 S150 170,180 150 
                 S240 130,270 150
                 S330 170,360 150
                 V300 H0 Z" fill="rgba(0, 0, 50, .2)"  stroke-width="3">
          <animateTransform attributeName="transform" attributeType="XML" type="translate" from="0" to="-180" dur="3s" repeatCount="indefinite"></animateTransform>
      </path>
</svg>

波浪背景图完整demo代码

最后

svg 在曲线以及曲线轨迹动画方面有这css无法实现的优势,给动画很多可能性,不知道它性能怎么样,不管了先学了再说吧。

参考
A Guide to SVG Animations (SMIL)

path

超级强大的SVG SMIL animation动画详解

深度掌握SVG路径path的贝塞尔曲线指令