讓文字沿着路徑動起來 (SVG)

路徑動畫的效果仍是挺有意思的,而 Web 中經常使用的方法就是 SVG。
先上一個效果圖:
javascript

SVG

要在 SVG 裏面實現文字路徑動畫仍是比較簡單的,SVG 裏面就有自然的支持。css

咱們先搞個 SVG 路徑html

<svg id="textPathDemo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="960" viewBox="0 0 581 120">
            <path stroke="#FF4444" d="M62.9 14.9c-25-7.74-56.6 4.8-60.4 24.3-3.73 19.6 21.6 35 39.6 37.6 42.8 6.2 72.9-53.4 116-58.9 65-18.2 191 101 215 28.8 5-16.7-7-49.1-34-44-34 11.5-31 46.5-14 69.3 9.38 12.6 24.2 20.6 39.8 22.9 91.4 9.05 102-98.9 176-86.7 18.8 3.81 33 17.3 36.7 34.6 2.01 10.2.124 21.1-5.18 30.1" fill="none" stroke-width="1" stroke-dasharray="5 5" id="text-path1"></path>
            <text>
                <textPath xlink:href="#text-path1" class="text-content" textLength="160" startOffset="160">
                    SVG 文字路徑動畫 
                </textPath>
            </text>
        </svg>複製代碼

這裏的 path 就是用來定義路徑的,這個路徑我是網上找的,通常作的話能夠用 AI 等 SVG 製做工具,幾個關鍵屬性介紹一下。前端

  • stroke-dasharray 表示用虛線描邊。可選值爲none, , inherit。java

    • none 表示不用虛線描邊
    • inherit 表示繼承node

      這個屬性頗有用,基本上 SVG 動畫都須要用到,這是一個逗號或者空格分隔的數值列表,第一個值表示線段的長度,第二個值表示線段間空白的長度,例子中 stroke-dasharray="5 5"中,第一個 5 表示虛線中的線段的長度,而第二個 5 表示兩個線段間的長度是 5px。因此出來的效果是每段虛線的間隔都是同樣的。其實這個dasharray能夠不僅兩個值,能夠有不少個,會循環依次用到線段和空白之間。css3

  • stroke,stroke-width 分別表示描邊長度和描邊寬度,這裏就是改顏色用的。git

這裏比較關鍵的是 textPath 這個節點,這裏就是定義文字按照什麼路徑排列的。程序員

其中主要的屬性:github

  • xlink:href : 這裏表示要用哪條路徑,注意咱們在 path 那設置的 id 屬性。
  • textLength : 表示文字的長度,這裏 160 是我瞎猜的。
  • startOffset : 表示文字開始的偏移量,也就是文字開始點在路徑中的位置。

如今出來的效果是這樣的:

如今還沒動,要讓它動起來很簡單,上面咱們介紹了 startOffset 屬性表示文字起始點,只要改變這個起始點就能夠動了。

因而咱們來加點 javascript:

var txtEle = $(".text-content");
    var rafId = null;
    var isEnd = false;

    var animateFunc = function(start, step, end){
        var startOffset = start + step;
        if (startOffset >= end){
            startOffset = end
            isEnd = true;
        }
        // txtEle.attr("startOffset", startOffset); // not work
        txtEle[0].setAttribute("startOffset", startOffset);

        if(isEnd){
            cancelAnimationFrame(rafId);
            return;
        }

        requestAnimationFrame(function(){
            animateFunc(startOffset,step,end);
        })
    }

    var steps = Math.round( 5000/16.7 );  // 5000 means 5s
    var len = 830;

    var step = len / steps;

    animateFunc(-160, step, len);複製代碼

代碼比較簡單,可是有幾個地方我要說明一下。
首先是我把 jQuery 裏面設置的 attr 的方法 txtEle.attr("startOffset", startOffset); 註釋了,由於 jq 會把屬性用小寫寫到元素裏面,而這裏的 startOffset 恰恰是大小寫敏感的,因此要改用 dom 的 setAttribute 方法。
而後,這段代碼裏面有幾個地方寫的是 hard code,好比 var len = 830;,中的 830,animateFunc(-160, step, len); 中的 -160。

這裏 830 表示的是文字要走的路徑的長度,這 830 是我大概算出來的,由於咱們想文字停在最後那裏,而不是跑出去,計算方法是路徑的長度減去文字長度,固然這個值不是很準確。

文字停在最後

animateFunc(-160, step, len); 中的 -160 表示的是文字起始點,由於咱們想有個進場效果,而不是全部文字一開始就排在起始點,因此要負出去,而 160 是我大概算的文字長度,這裏也不許確。

文字進場效果

寫完這段 js,發現本身兜了個大圈。以前在 一個比想象中更騷氣的圓-svg實現 一文中介紹過 SVG 的 animate 標籤,若是隻是單純的動,這裏大能夠用 animate 來作。

添加 animatetextPath 中:

<textPath xlink:href="#text-path1" class="text-content" textLength="160" startOffset="-160">
            SVG 文字路徑動畫 
             <animate attributeName="startOffset" from="-160" to ="830" begin="0s" dur="5s" repeatCount="1"/>
        </textPath>複製代碼

這裏 attributeName表示動畫屬性是 startOffset,begin 表示開始的延時,dur 表示時間整個動畫的時間,frome 和 to 表示初始值和最終值,repeatCount 表示重複次數,這裏是 1 次,若是用 indefinite 表示無限次。只是加這個進去,是沒有停在最後的樣式的,作完一次,字就不見了。這裏 from 和 to 也能夠用 0% 和 100% ,這樣就沒有進場效果。這個節點雖然好用,可是仍是比較適合無限循環運動的場景。

這裏要想精細的控制,仍是要靠 js。

可是,做爲一個要弄懂這是什麼,從哪裏來,到哪裏去的程序員,面對代碼中不少半猜半算的值,是不能視而不見的,並且路徑什麼的如今都是寫死的,弊端略大,因而咱們能夠藉助一個強大的庫,snap.svg.js。

Snap.svg

Snap.svg 是一個強大的 SVG 操做庫,提供了豐富的接口,惟一的問題是,你須要瞭解熟悉 SVG 的基礎知識。

引入 Snap.svg 以後,咱們的 html 代碼能夠變得比較簡單:

<svg id="textPathDemo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="960" viewBox="0 0 581 120">

    </svg>
    <script src="http://cdn.bootcss.com/snap.svg/0.4.1/snap.svg-min.js"></script>複製代碼

就留一個 SVG 元素就好。

而後咱們就開始利用 Snap.svg 幫咱們幹活。

window.onload = function () {
        var path = "M62.9 14.9c-25-7.74-56.6 4.8-60.4 24.3-3.73 19.6 21.6 35 39.6 37.6 42.8 6.2 72.9-53.4 116-58.9 65-18.2 191 101 215 28.8 5-16.7-7-49.1-34-44-34 11.5-31 46.5-14 69.3 9.38 12.6 24.2 20.6 39.8 22.9 91.4 9.05 102-98.9 176-86.7 18.8 3.81 33 17.3 36.7 34.6 2.01 10.2.124 21.1-5.18 30.1";

        var s = Snap('#textPathDemo');

        path = s.path(path).attr({ 'fill': 'none', 'stroke': '1',"stroke":"#FF4444","stroke-dasharray":"5 5"});

        var pathLength  = Snap.path.getTotalLength(path);

        console.log(pathLength);

        var txt = s.text(0,0,'SVG 文字路徑動畫');

        var txtLength = txt.node.clientWidth;

        var text = txt
                .attr({ 'textpath': path, 'fill':'#003399' })
                .textPath.attr({ 'startOffset': -txtLength })
                .animate({ 'startOffset': pathLength-txtLength }, 5000, mina.easeinout );
    };複製代碼

代碼不是很長,簡單解釋一下。

  1. 一開始定義了一段 path,這裏就是咱們要用來作路徑動畫用的。
  2. 而後建立一個 snap 對象:var s = Snap('#textPathDemo');
  3. 把 path 放到咱們的 snap 中,並設置了一堆以前咱們在 html 裏面設置的屬性 path = s.path(path).attr({ 'fill': 'none', 'stroke': '1',"stroke":"#FF4444","stroke-dasharray":"5 5"});
  4. 高潮來了,var pathLength = Snap.path.getTotalLength(path); 算出路徑的長度,不用猜了。
  5. 建立文字,var txt = s.text(0,0,'SVG 文字路徑動畫');
  6. 算出文字長度,var txtLength = txt.node.clientWidth; ,這裏說一下,我在 Snap 的文檔中沒找到怎麼算文字長度的,這個是打印上面那個 txt 對象後發現的,若是有更好的方法,麻煩告知哈。
  7. 給文字設置一堆東西 var text = txt.attr({ 'textpath': path, 'fill':'#003399' }) ,主要設置 textpath
  8. 設置 textpath 中的屬性:.textPath.attr({ 'startOffset': -txtLength }) 這裏是支持鏈式調用的,設置起始點爲 -txtLength 是爲了有文字進場效果。
  9. 設置動畫,給爺動一個。.animate({ 'startOffset': pathLength-txtLength }, 5000, mina.easeinout ); 這裏設置了要作動畫的屬性爲 startOffset,最後的位置爲 pathLength-txtLength 即路徑長度減去文字長度,動畫時間 5000 毫秒,以及動畫函數 main.easeinout 這個動畫函數是庫提供的,類比 css3 中的 easeinout 的效果,比以前咱們用勻速要生動一些。

效果:

簡簡單單,不再用猜長度值了,文字改版的時候也不用手動計算文字長度。
產品經理跟我說文字是不會變的,我知道這是最大的謊話。

結語

因爲我對 SVG 也不是太熟悉,有些地方可能有所疏漏,有什麼疑問歡迎留言,有什麼寫錯的地方,歡迎指出哈。

SVG Demo 源碼地址:github.com/bob-chen/ca…

Snap.svg Demo 源碼地址:github.com/bob-chen/ca…

若是頁面使用了 base 標籤,可能會引發路徑找不到的狀況,能夠參考 tips - 解決 base 標籤形成 SVG 效果失效

碎碎念

記錄一些所思所想,寫寫科技與人文,寫寫生活狀態,寫寫讀書感悟,主要是扯淡和感悟,歡迎關注,交流。

微信公衆號:程序員的詩和遠方

公衆號ID : MonkeyCoder-Life

參考

snapsvg.io/
javascript.ruanyifeng.com/htmlapi/svg…
www.htmleaf.com/ziliaoku/qi…


本文對你有幫助?歡迎掃碼加入前端學習小組微信羣:

相關文章
相關標籤/搜索