SVG基礎及其動畫應用淺析

本文做者:錢鴻昌(閃火)javascript

1、咱們爲何使用svg

  1. 和高清png來作個對比css

    繼續對比html

    一樣高清的質地,矢量圖不畏懼放大,體積小。這裏要說明一點就是,由於 SVG 中保存的是點、線、面的信息,與分辨率和圖形大小無關,只是跟圖像的複雜程度有關,因此圖像文件所佔的存儲空間一般會比 png 小。前端

  2. 優化 SEO 和無障礙的利器,由於 SVG 圖像是使用XML(可擴展標記語言【英語:Extensible Markup Language,簡稱:XML】標記指計算機所能理解的信息符號,經過此種標記,計算機之間能夠處理包含各類信息的文章等)來標記構建的,瀏覽器經過繪製每一個點和線來打印它們,而不是用預約義的像素填充某些空間。這確保 SVG 圖像能夠適應不一樣的屏幕大小和分辨率。vue

  3. 因爲是在 XML 中定義的,SVG 圖像比 JPG 或 PNG 圖像更靈活,並且咱們可使用 CSS 和 JavaScript 與它們進行交互。SVG 圖像設置能夠包含 CSS 和 JavaScript。在 react、vue 這種數據驅動視圖的框架下,對於 SVG 操做就更加如魚得水了。(下文會跟你們分享一些小的 SVG 動畫在咱們項目中的實踐)java

  4. 在運用層面上,SVG 提供了一些圖像編輯效果,好比屏蔽和剪裁、應用過濾器等等。而且SVG 只是文本,所以可使用 GZip 對其進行有效壓縮。react

2、瞭解 SVG 經常使用元素及其使用

大多數教程網上都能找到,這裏寫一些我以爲值得說起的點git

2-1. 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="300" height="300" viewBox="0, 0, 100, 200" xmlns="http://www.w3.org/2000/svg" version="1.1">
    <circle cx="100" cy="50" r="49" stroke="black" stroke-width="2" fill="red" />
</svg>
複製代碼

這就是咱們從設計手裏拿到的 SVG 源文件,咱們掰開揉碎了說。首先咱們把 SVG 內部代碼所有去掉不看,因而成了這樣github

<?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="300" height="300" viewBox="0, 0, 100, 200" xmlns="http://www.w3.org/2000/svg" version="1.1">
</svg>
複製代碼

這是99% SVG 都會表現出來的形式和及一些屬性,其中包含 width、height 這兩個視口屬性,viewBox 視圖屬性,xmlns 屬性。咱們一行一行看web

第一行:包含了 XML 聲明,XML 聲明其實和 HTML 文檔的 DTD 聲明是相似的。類比 HTML5 的聲明方式

<!DOCTYPE html>
複製代碼

SVG 的文檔聲明方式(劃重點:通常若是 SVG 運用在 HTML 裏,咱們能夠不寫這樣的文檔聲明,但若是是單獨的 SVG 文件,那就須要寫了,不然瀏覽器可能會不認識)

<?xml version="1.0" standalone="no"?>
複製代碼

咱們看到的 standalone 屬性是在代表該 xml 聲明是不是獨立的,若是不是即 standalone="no",那後面會引入外部的 dtd ,如第二行第三行所示。 version 屬性用於指明 SVG 文檔遵循規範的版本。 它只容許在根元素<svg> 上使用。 它純粹是一個說明,對渲染或處理沒有任何影響。雖然它接受任何數字,可是隻有1.0 和 1.1.這兩個有效的選擇。

第四行:這是 SVG 內容的開始

<svg width="300" height="300" viewBox="0, 0, 100, 200" xmlns="http://www.w3.org/2000/svg" version="1.1">
</svg>
複製代碼
  • xmlns 屬性是 SVG 的 XML 聲明空間,這一部分相似於 HTML 中的 xmlns="www.w3.org/1999/xhtml"
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
複製代碼
  • width & height 屬性,能夠理解成畫布的大小。沒錯是畫布的大小。舉個例子:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width=100 height="100">
    <circle cx="50" cy="50" r="49" stroke="black" stroke-width="1" fill="red" />
</svg>
複製代碼

當前這個 SVG 的畫布大小是 100 * 100 的畫布,咱們畫上一個半徑爲 49 再加 1 個單位的描邊的圓。恰好撐滿沒毛病。所見即所得。那咱們試一下改變 width 和 height。發現

<svg style="background:#007fff" xmlns="http://www.w3.org/2000/svg" version="1.1" width="300" height="300">
    <circle cx="50" cy="50" r="49" stroke="black" stroke-width="1" fill="red" />
</svg>
複製代碼

咱們能夠看到藍色區域就是咱們定的 width 和 height ,圖形部分依然是那個圓沒有變化。這樣咱們就理解了 width 和 height 的做用。

  • viewBox 屬性,接下來配合 viewBox 這個屬性咱們再來修改下代碼
<svg style="background:#007fff" xmlns="http://www.w3.org/2000/svg" version="1.1" <!-- viewBox定義-->
    viewBox="0, 0, 100, 100"
    width="300"
    height="300" >
    <circle cx="50" cy="50" r="49" stroke="black" stroke-width="1" fill="red" />
</svg>
複製代碼

咱們能夠看到藍色區域大小不變,而咱們的圓卻變得很大,大到撐滿了整個畫布。沒錯,你的想法是對的,所謂 viewBox 這個屬性能夠理解爲咱們微信聊天時的截圖操做。viewBox 屬性的四個參數,前兩個表示截圖起點,後面兩個表示截圖終點,均是以左上角定點爲原點。最後把截圖再拉伸放在 SVG 畫布上,就成了咱們上面看到的 SVG 了。下面咱們再修改一次 viewBox 成 0, 0, 50, 50 幫助理解

<svg style="background:#007fff" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0, 0, 50, 50" width="300" height="300" >
    <circle cx="50" cy="50" r="49" stroke="black" stroke-width="1" fill="red" />
</svg>
複製代碼

因此整個邏輯大概是這樣的

2-2.path 標籤

在 SVG 裏,你能夠把 path 當作是最基本的繪製元素,正由於它是最基本的,萬變不離其宗,他能演化出各類複雜的繪製效果。因此 path 是最基本也是最複雜的繪製元素。

path 的基礎屬性和其表明的意義

咱們知道一個 path 標籤,最重要的屬性是 d 屬性,它是一組指令和參數的集合。在 d 屬性的值裏,咱們能看到一堆很是複雜的指令字符串。

<path d=" M73.8616812,68.8664775 L74.5015359,74.5939423 L68.1746283,71.7969507 C66.2299599,72.4159872 64.1377269,72.7711218 61.9444643,72.7711218 C51.9719158,72.7711218 43.8883163,65.7823167 43.8883163,57.1611168 C43.8883163,48.5399169 51.9719158,41.5511118 61.9444643,41.5511118 C71.9164005,41.5511118 80,48.5399169 80,57.1611168 C80,61.8286883 77.6181486,66.006419 73.8616812,68.8664775" id="Fill-1" fill="#FFFFFF"></path>
複製代碼

其實徹底不用以爲噁心,這裏繼續掰開揉碎了說

  • d 屬性裏的那些指令
指令 參數 含義
M x y 將畫筆移動到點(x,y)
L x y 畫筆從當前的點繪製線段到點(x,y)
H x 畫筆從當前的點繪製水平線段到點(x,y0),y0 表示繪製前畫筆所在 y 軸座標,也就是 y 軸不變
V y 畫筆從當前的點繪製豎直線段到點(x0,y),x0 表示繪製前畫筆所在 x 軸座標,也就是 x 軸不變
A rx ry x-axis-rotation large-arc-flag sweep-flag x y 畫筆從當前的點繪製一段圓弧到點(x,y)
C x1 y1, x2 y2, x y 畫筆從當前的點繪製一段三次貝塞爾曲線到點(x,y)
S x2 y2, x y 特殊版本的三次貝塞爾曲線(省略第一個控制點)
Q x1 y1, x y 繪製二次貝塞爾曲線到點(x,y)
T x y 特殊版本的二次貝塞爾曲線(省略控制點)
Z 無參數 繪製閉合圖形,若是 d 屬性不指定Z命令,則繪製線段,而不是封閉圖形

以上是 path 路徑中的所有指令,其中加粗部分爲經常使用基礎指令,相對來講比較好理解。每一個指令都有對應的小寫指令。例如M 10,10 有對應的 m 10,10 。大寫表明絕對位置,所謂絕對位置即對 SVG 畫布左上角原點的絕對。小寫表明相對位置,所謂相對位置是以當前畫筆所在位置進行定位

  • A(arc)畫弧指令
A rx ry x-axis-rotation large-arc-flag sweep-flag x y

<svg width="100%" height="100%">
    <path d="M0 0 A 45 45, 0, 0, 0, 45 45 L 45 0 Z" fill="green"/>
</svg>
複製代碼

畫了張圖,幫助理解

按照圖中的步驟,咱們能夠畫出兩個圓都知足,因而再看到其中A指令有三個0咱們沒有解釋,回顧下 A 指令,並結合這張圖咱們能夠更好的理解

A rx ry x-axis-rotation large-arc-flag sweep-flag x y

  • 貝塞爾曲線

關於貝塞爾曲線,張老師這篇文章已經說得很是清楚了,說得很是易懂深度理解 SVG 路徑,推薦給但願更多瞭解 svg 路徑的同窗

2-3.基本圖形

基本圖形這塊相對比較好理解,咱們直接一張表總結下,不作過多贅述

圖形 標籤 模板 含義
矩形 < rect > <rect x="60" y="10" rx="10" ry="10" width="30" height="30"/> x:起點橫座標,y:起點縱座標,rx:倒角x軸方向半徑,ry:倒角x軸方向半徑,width:寬度,height:高度
圓形 < circle > <circle cx="100" cy="100" r="50" fill="#fff"></circle> cx:圓心橫座標,cy:圓心縱座標,r:半徑
橢圓 < ellipse > <ellipse cx="75" cy="75" rx="20" ry="5"/> cx:橢圓心橫座標,cy:橢圓心縱座標,rx:橢圓x軸方向半徑,ry:橢圓y軸方向半徑
直線 < line > <line x1="10" x2="50" y1="110" y2="150"/> x1,y1:起點,x2,y2:終點
折線 < polyline > <polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145"/> 每兩個點以空格配對爲一個座標點,逗號隔開造成座標集合。連成折線。
多邊形 < polygon > <polygon points="50 160, 55 180, 70 180, 60 190, 65 205, 50 195, 35 205, 40 190, 30 180, 45 180"/> 相似折線,不一樣的是,最後一個點會自動閉合第一個點,造成閉環。

2-4.symbol標籤

symbol 標籤是咱們直播團隊 icon 管理平臺實現的核心技術點,它的做用說白話點就是至關因而一個元件,放在咱們的工具箱裏,就像下面這樣:

<svg class="svg-sprite">[工具箱]
	<symbol id="icon-wave_add" viewBox="0 0 76 76"><path d="M38 0a4 4 0 014 4v30h30a4 4 0 110 8H41.999L42 72a4 4 0 11-8 0l-.001-30H4a4 4 0 110-8h30V4a4 4 0 014-4z" fill="currentColor" fill-rule="evenodd" opacity="none"></path></symbol>
	<symbol id="icon-time" viewBox="0 0 10 10"><path d="M5 0a5 5 0 110 10A5 5 0 015 0zm0 1.5a.5.5 0 00-.5.5v3.02l.008.088a.5.5 0 00.238.343L7.02 6.794l.082.039a.5.5 0 00.603-.215l.039-.082a.5.5 0 00-.216-.603L5.5 4.735V2l-.008-.09A.5.5 0 005 1.5z" fill="rgba(153,153,153,1)" fill-rule="evenodd" class=" "></path></symbol>
	<symbol id="icon-wave_delete" viewBox="0 0 40 40"><g fill="none" fill-rule="evenodd"><circle fill="#000" opacity="0.2" cx="20" cy="20" r="20"></circle><path stroke="#FFF" stroke-width="4" stroke-linecap="round" d="M13 13l14 14M27 13L13 27"></path></g></symbol>
</svg>
複製代碼

放一份就能夠無限引用。當它在工具箱裏時,咱們是看不到它的(頁面不會渲染它),只有咱們使用了<use>標籤對其進行實例引用時,咱們才能夠在頁面上看到它:

<use xlink:href="#icon-time"></use>
複製代碼

咱們使用<symbol> + <use>的組合,來實現svg雪碧圖,是否是以爲很easy。

有的同窗會有疑問,symbol 標籤和 g 標籤,放在 defs 裏彷彿都是在定義一個可複用的模塊,那麼二者之間有什麼區別呢?在個人理解裏,symbol 相對於g 標籤最大的不一樣在於 symbol 能夠給可複用代碼塊增長視圖屬性和視口屬性。方便在服用的時候直接調整到合適的運用(打印)尺寸。

3、svg 動畫及其運用

3-1.svg 動畫概要

其實關於 SVG 動畫,要說的有不少,本文咱們主要說一下 SVG 動畫的一些基本屬性和運用技巧
一、SMIL 驅動
二、JavaScript 驅動
三、CSS 驅動

技術 描述 備註
SMIL 很強大且純粹的標籤化動畫 雖然 Chrome 45之後棄用了SMIL,可是依然支持,各大瀏覽器的支持度都挺好的
CSS CSS 還只能實現簡單的動畫 offset-path 的兼容性不好。css 動畫不適合作交互性很強的動畫
JavaScript 複雜動畫就要用到 JS 了,包括世面上的一些 SVG 動畫庫,也都是 JS 去實現的

SVG 是基於 XML 的矢量圖形描述語言,能夠近似理解成 HTML,因此能和 JS 以及 CSS 進行交互。 特 別是 CSS,咱們可使用 CSS3 來對 SVG 作動畫處理。可是要記住的是僅當 HTML 內聯包含 SVG 文件 時,咱們纔可使用 CSS 對其作樣式開發。本文咱們針對平時 CSS3 + HTML不容易實現, 而利用 SVG 能夠快速簡便實現的幾種場景作相應介紹

3-2.SVG 動畫實踐

一、直線的變化
二、path 路徑實現圖形的平滑變幻
三、描邊動畫
四、指定軌跡運動

3-2-一、直線的變化

下面這張圖是一個 GIF 的 icon,體積大約是 156KB,壓縮以後。

living.gif

若是咱們用 SVG 去實現的話。應該怎麼作呢。咱們分爲如下兩種方式,親測兼容性都 OK

CSS+SVG 實現的代碼實踐

基於 SMIL 實現的代碼實踐

總結&說明

知識點1: SVG 中有不少屬性咱們是能夠用 CSS 去描述的。在基於 CSS 動畫三劍客(animation, transform, transition)的基礎上。咱們對一些屬性進行控制,就達到咱們想要的動畫效果。下面兩點值得說明:

  • transform:transform 有兩種用法,一個是在 SVG 標籤裏寫的 transform 屬性、另外一種是在 CSS 文件裏寫的 transform,他們有着本質的區別。
<rect transform="rotate(45deg) ..."  ... />

rect {
    transform: rotate(45deg)
}
/** 行內的 transform 屬性,他的執行基點是在咱們 svg 元素的左上角也就是 svg 的座標原點。**/
/** 而 CSS 的 transform 原點則在元素自己的中心點。**/
複製代碼
  • CSS可描述屬性: 不少文章告訴咱們 CSS 能夠控制 SVG 去作動畫,可是實際開發過程當中咱們會更想知道,到底哪些屬性咱們能夠作css控制,這裏給你們列出一些經常使用屬性而且能夠放心使用的屬性
CSS 可控屬性名 可實現場景
理論上全部的顯示屬性,均可以使用 CSS 控制包括:好比 stroke-width、color、fill 等等 SVG 的顯示屬性 大部分的顯示樣式動態變化
x 咱們知道矩形有 x、y 屬性,其含義是起始點,控制 x,咱們能夠動態控制矩形的X軸位移
y 控制 y,咱們能夠動態控制矩形的 Y 軸向位移
cx <circle cx="100" cy="100" r="50" fill="#fff" />這是一個圓形,控制 cx 能夠控制圓形(或者橢圓)的 X 軸位移
cy 控制 cy 能夠控制圓形(或者橢圓)的 Y 軸位移
r r 是圓的半徑,控制 r 能夠控制圓形的大小
rx rx 是橢圓的 X 軸方向半徑,控制 rx 能夠控制橢圓的大小
ry ry 是橢圓的 Y 軸方向半徑,控制 ry 能夠控制橢圓的大小
d path 標籤的 d 屬性,控制 d 的路徑信息,能夠控制圖形的變幻(d 屬性在 safari 上是不支持 css 描述的。咱們下文會詳細的說明
PS:若是各位看官們在平常開發中,不清楚該屬性是否能夠經過 css 去控制,這邊給你們提供一個查詢連接 不支持 CSS 控制的 SVG 相關屬性

知識點2: 能夠利用 SMIL 對 SVG 作動畫處理,舉個例子,一樣的動畫效果,下面這段代碼不用 CSS 也能夠實現

export default function App() {
   return (
     <div className="App"> <svg width="100%" height="100%" viewBox="0 0 100% 100%"> {[1, 2, 3, 4, 5].map((it, index) => ( <line key={index} stroke="#000" strokeWidth="2" x1={15 + index * 5} y1="8" x2={15 + index * 5} y2="22" > <animate attributeName="y1" values="8; 15; 8" dur="1s" begin={`${(5 % (index + 1)) * 0.2}s`} repeatCount="indefinite" /> <animate attributeName="y2" values="22; 15; 22" dur="1s" begin={`${(5 % (index + 1)) * 0.2}s`} repeatCount="indefinite" /> </line> ))} </svg> </div>
   );
 }
複製代碼

那麼 什麼是 SVG 的 SMIL 呢
這裏不想再對其作大篇幅的贅述,由於網上有不少文章都已經說得比較詳細了SMIL 動畫指欄SVG SMIL animation 動畫詳解。 本文更想和你們交流的是在SMIL驅動和CSS驅動如何作選擇的問題。
雖說早在 Chrome 45,chrome 就已經官宣要棄用 SMIL,可是到目前位置,各大瀏覽器廠商對它的支持度是這樣的

image.png Chrom 宣佈棄用 SMIL 是由於要支持 CSS Animation 與 Web Animation 的發展,因此咱們能夠理解爲當前是在一個過渡狀態,確實有一些暫時CSS 還無法支持或者支持度不好的動畫效果,SMIL 能夠輕鬆完成。可是基於 web 動畫技術發展的大趨勢,仍是建議咱們 SVG 動畫實現方案的選擇優先級是CSS 驅動 -> JS 驅動(咱們能夠採用一些框架,文末會給你們推薦一些好用的框架) -> SMIL 驅動

3-2-二、path 路徑的變化(圖形平滑變化)

image.png image.png

CSS+SVG 實現的代碼實踐 Logo 變化

基於 SMIL 實現的代碼實踐 Logo 變化

CSS+SVG 實現的代碼實踐播放暫停

基於 SMIL 實現的代碼實踐播放暫停

總結&說明

知識點1: 經過對<path/> d 屬性的控制,咱們能夠實現不少動畫效果,對於 d 屬性的控制目前有兩種方式,一種是經過 CSS 控制,另外一種是經過 SMIL 控制,可是目前因爲 safari 不支持用 CSS 來描述<path>標籤的 d 屬性。因此在實現這種平滑的形狀變形效果上不推薦使用 CSS。更加推薦使用SMIL或者第三方庫去實現

基於 CSS:

path {
      transition: ease all 0.3s; // 就像對dom同樣的對待svg

      &.play { //這裏是播放狀態下的<path />路徑
        d: path("M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z");
      }

      &.pause { //這裏是播放狀態下的<path />路徑
        d: path(
          "M 12,26 16.33,26 16.33,10 12,10 z M 20.66,26 25,26 25,10 20.66,10 z"
        );
      }
    }
複製代碼

基於 SMIL(即經過<animate>實現對<path> d 屬性的動態控制):

const pathMap = {
    from: "M 12,26 16.33,26 16.33,10 12,10 z M 20.66,26 25,26 25,10 20.66,10 z",
    to: "M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z"
  };
  <svg class="icon" viewBox="0 0 120 120" width="400" height="400"> <path d="M 12,26 16.33,26 16.33,10 12,10 z M 20.66,26 25,26 25,10 20.66,10 z" fill="#000000" > <animate attributeName="d" from={play ? pathMap.from : pathMap.to} to={play ? pathMap.to : pathMap.from} dur="0.3s" begin="indefinite" // 這裏設置開始時間爲無限以達到不自動播放的效果 fill="freeze" /> </path> </svg>
複製代碼

以上兩個 path 路徑的切換,就能夠帶來這種平滑過渡的效果。

play.gif

知識點2:
咱們看到的圖形變幻,都須要遵循一個原則就是點數對齊原則,什麼意思呢?咱們能夠看下面的demo,五角星到 10 邊形(多邊形畫的很差,抱歉...😜)。,都是 10 個控制點到 10 個控制點的過分。因此效果平滑

image.png

image.png

而下圖的 10 個點到 3 個點就沒有這種平滑的過渡效果了(固然如今不少的 SVG 動畫框架已經解決了這個問題。見文末的框架推薦 )

image.png

3-2-三、描邊動畫的應用

image.png

image.png

CSS+SVG 實現的代碼實踐-星環

CSS+SVG 實現的代碼實踐- LOGO 描邊

基於 SMIL 實現的代碼實踐-進度環

總結&說明

知識點1:
相似的描邊動畫咱們能夠拿來作不少效果,好比各類形狀的進度條、好比文字的描邊、好比霓虹燈流水燈光等等流動動畫效果。而描邊動畫的核心點就在於 SVG 的兩個顯示屬性分別是 stroke-dasharray、stroke-dashoffset,咱們上文說了,幾乎全部的顯示屬性均可以用 CSS 去控制,因此這種動畫,建議使用 CSS 去開發。

屬性 值舉例 描述 支持範圍
stroke-dasharray 1 3 4 4 它的值是一個序列,能夠傳入多個值,分別指定描邊短線的長度和描邊線間距,多個值依次循環,若是傳入3個值,相似於 stroke-dasharray: 1,2,3。則會自動複製一份再生效 <circle>, <ellipse>, <line>, <mesh>, <path>, <polygon>, <polyline>, <rect> <altGlyph>, <altGlyphDef>, <altGlyphItem>, <glyph>, <glyphRef>, <textPath>, <text>, <tref>, <tspan>
stroke-dashoffset 10 描邊線段的起始位置距離圖形繪製起點的偏移量。正負值能夠決定順時針仍是逆時針走向 跟stroke-dasharray一致

設想一個場景,一個倒計時須要從 100 到 0,對應的視覺效果也就是從全描邊到無描邊。那麼咱們初始狀態將 stroke-dasharray 的第一個值設爲 2πr (周長),第二個值設也設爲 2πr (周長)。那麼咱們會獲得一個整圓。

image.png

這時若是咱們把圓展開就能看到這樣的場景

image.png 因此要實現進度的動態變化其實有兩種方案
第一種是將stroke-dasharray的第一個值從2πr(周長)調整到0。原展開圖中的黑色部分沒有了(能夠理解爲變成了一個點以下圖,看不見了),只剩下虛線部分是空白間隙了。

第二種是將stroke-dashoffset的值從0調整到-2πr(或者增長到2πr)。對比第一張圖成下圖的樣子
image.png

知識點2:
在實際開發中,咱們會遇到一些比較複雜的圖形須要作描邊,這個時候咱們沒辦法去獲得它的周長是多少,這時候分兩種場景處理。一種是在CSS裏咱們能夠將stroke-dasharray的第二個值設置成一個很是大的數字,而後再去調整第一個值好比:

path {
        stroke-dasharray: 0(調整到合適的值) 99999999999999
    }
複製代碼

若是在js裏咱們須要動態去獲取周長的話,SVG提供了原生的api能夠去獲取path的周長。

const inPath = document.getElementById("inner-path");
    console.log(inPath.getTotalLength());
複製代碼

ps:有些資料說該方法只能用於<path />,可是筆者親測了在safair和chrome上,基本能夠支持全部的基礎圖形以及<path />,可是<text />不支持,瀏覽器會報not a function。

既然說到了getTotalLength(),那麼順帶說下getPointAtLength()。getPointAtLength,顧名思義就是根據距離獲取點座標。意思就是根據到起始點的距離,獲取該指定距離對應的點的座標。座標系原點爲該圖形的起始點。在一些指向型的動畫上咱們可能會運用到這個api。

3-2-四、軌跡運動動畫的應用

fly.gif

基於SMIL實現的代碼實踐-軌跡運動

總結&說明

{/* 咱們將整個飛機圖形元件用g標籤包起 */}
<g transform="translate(-100, -35) scale(0.1)">
  <path d="M164.485419 578.709313L196.274694 794.731891c0.722484 5.53904 8.188147 7.224835 11.078081 2.408278l75.860772-121.377234 740.063969-363.409219L164.485419 578.709313z" fill="#F68206" ></path>
  <path d="M2.167451 440.233302l159.668861 132.214487 857.828787-260.334901zM289.475071 679.375353l191.217309 153.407337 542.344309-518.743179z" fill="#FF9900" ></path>
  <path d="M204.222013 800.030103l125.23048-80.677328-48.888053-39.014111-76.342427 118.4873" fill="#D3650B" ></path>
  {/* 而後在這裏,咱們利用animateMotion,去作這個軌跡運動 */}
  <animateMotion path="M 0 450 Q 150 50 250 50 Q 350 0 400 50 Q 500 50 450 200 C 300 350 250 200 500 50 C 600 50 750 200 650 250 A 50 50 0 1 1 800 50 " begin="0s" rotate="auto" dur="20s" repeatCount="indefinite" />
</g>
複製代碼

這裏咱們用到了SMIL裏的<animateMotion />,animateMotion裏的path屬性,咱們也能夠像這樣去使用

<defs>
        <path id="theMotionPath" d="xxx" />
    </defs>
    <animateMotion>
        <mpath xlink:href="#theMotionPath"/>
    </animateMotion>
複製代碼

實際生產中,咱們這種軌跡運動的需求,是建議使用SMIL去實現的,固然CSS也是有實現方案的《使用CSS offset-path讓元素沿着不規則路徑運動》。可是CSS的兼容實在不敢恭維,勸退一波。

4、寫在最後

1、 建議將CSS動畫用於無變形的過渡或簡單動畫。尤爲是在硬件加速時。CSS不須要加載其餘資源(通常指三方庫),而且懸停時的小變換能夠爲交互帶來更好的效果。特別是當你不須要3d、物理體感、或進行大量堆疊動畫效果時建議選用CSS。另外,CSS方便調試也是很大的一個優點。

2、對於較長的動畫,開發時會變得很是複雜且須要花精力去調試,而CSS調整時間尺度很困難,尤爲是當你須要操縱一些細微幀時,我的以爲SMIL更合適作有序的,複雜的堆疊動畫羣的場景。

3、對於變形的動畫,建議使用SMIL或者第三方庫。推薦的比較優秀的三方庫有如下幾個。

庫名 描述
GSAP 全稱是GreenSock Animation Platform,之前流行用 flash 的時候,GSAP就叱吒江湖的存在,GSAP有兩個版本一個是 flash 版本,一個是 javascript 版本,也就是咱們說的 GSAP js。GSAP 速度快。GSAP專門優化了動畫性能,使之實現和css同樣的高性能動畫效果;輕量與模塊化;
Snap.svgSVG.jsVelocity.js 這三個庫一直會被開發者拿來對比,基本上會用jQuery,就會使用這三個庫,也就是說入手友好,Snap.svg 更偏向於支持現代瀏覽器,因此它的體量也會小一些。對比 Snap.svg 來看 SVG.js ,SVG.js 的寫法更加的清晰,使用時會有更好的體驗,且自稱提供接近完整的 SVG 規範覆蓋。Snap.svg 風格就更像一個俠客,寫起來會很瀟灑可是很差讀,Velocity 也很強大,簡單易用、高性能、功能豐富
anime.js anime.js 雖然功能沒有 GASP 強大,可是體積很樂觀,gzip壓縮完只有9kb左右,知足平常需求開發仍是足夠的
D3 Data-Driven Documents 顧名思義,更加適合用於建立數據可視化圖形場景去使用

4、如何使用 SMIL 進行硬件加速,使用 代替,並設置 x、y、z 值(z 爲 0)。原理與 CSS 相似,這會將元素移到它本身的層,從而在其發生運動時不會從新繪製。

參考資料

本文發佈自 網易雲音樂大前端團隊,文章未經受權禁止任何形式的轉載。咱們常年招收前端、iOS、Android,若是你準備換工做,又剛好喜歡雲音樂,那就加入咱們 grp.music-fe(at)corp.netease.com!

相關文章
相關標籤/搜索