SVG 通常會搭配 CSS Animation 做動畫,效能很不錯。但問題來了,如果設計師給一張很複雜的 SVG Banner 圖,需要只動裡面其中幾個物件,那使用 JS 會比較方便,就不用每張切圖對 x,y 位置,且 JS 能撰寫比較多使用者互動。這次就來測試使用 SVG.js 做動畫。
查看動畫結果點這裡。
步驟一:找一張大的 SVG Banner 圖片
從 https://www.vecteezy.com/ 找一張可以測試的圖片。
把下載的檔案用 Illustrator 開啟,將想要做動畫的群組取名,如此一來以拉輸出後的 svg 檔案會自動在 html tag 加上 id 的屬性。
步驟二:開始做動畫
安裝套件。
1
| npm install @svgdotjs/svg.js
|
引入套件使用。
1
| import { SVG } from "@svgdotjs/svg.js";
|
以氣球和氣球旁邊的愛心為例。會先用 SVG selector 把物件選取起來,在針對個別物件做 animate 的串連。若 animate 只有一次的話,可以用 loop 函數做重複即可,不需要另外寫 function。
先用愛心一次 animate 來說明。
1 2 3
| const BalloonLove = SVG("#svgjs #BalloonLove"); BalloonLove.opacity(0.5); BalloonLove.animate(1000, 0, 'now').translate(-10, -30).opacity(1).loop(true, true);
|
若 animate 分多段的話,以氣球為例需要寫一個函數重複執行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const Balloon = SVG("#svgjs #Balloon");
function BalloonLoop() { Balloon.animate(1000) .ease("<>") .translate(-30, 10) .animate(1000) .ease("<>") .translate(70, 10) .animate(1000) .ease("<>") .translate(-40, -20) .after(BalloonLoop); } BalloonLoop();
|
步驟三:和使用者做互動
這邊做了一個小互動是當 Happy Valentine’s Day 動畫結束後,會感應使用者的滑鼠位置,做文字群組的相對位置移動。
先在 html 設定 mousemove 監聽事件,這裡搭配 vue cli 做測試。
1 2 3
| <template> <svg ... @mousemove="moveTxt">...</svg> </template>
|
接著在 js 設定變數,讓 svg 動畫結束後,才偵測使用者滑鼠,做文字群組的位移。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import { SVG } from "@svgdotjs/svg.js";
export default { data() { return { initTxtX: null, initTxtY: null, canMoveTxt: false, }; }, mounted() { this.startSVGjs(); }, methods: { startSVGjs() { ... TxtLove.animate(1000, 5000).transform({translateY: 0}).opacity(1).after(this.setTxtMove); }, setTxtMove() { const TxtGroup = SVG("#svgjs #TxtGroup"); this.initTxtX = TxtGroup.x(); this.initTxtY = TxtGroup.y(); this.canMoveTxt = true; }, moveTxt(e) { if(!this.canMoveTxt) return; const range = 100; const eventX = e.clientX; const eventY = e.clientY; const TxtGroup = SVG("#svgjs #TxtGroup"); const ratio = window.innerWidth / 2500; const gapX = eventX - this.initTxtX * ratio; const gapY = eventY - this.initTxtY * ratio; let moveX, moveY; if(gapX < 0) { moveX = Math.abs(gapX) > range ? range * (-1) : gapX; } else { moveX = Math.abs(gapX) > range ? range : gapX; } if(gapY < 0) { moveY = Math.abs(gapY) > range ? range * (-1) : gapY; } else { moveY = Math.abs(gapY) > range ? range : gapY; } TxtGroup.transform({translateX: moveX, translateY: moveY}); }, }, };
|
如此一來就能操作複雜的大張 svg 圖和使用者互動囉~所有原始碼在Github,下次見~