JSライブラリ「Snap.svg」を使用すると、異なるpathで描いたSVG画像をスムーズに変形アニメーションさせられます。
このように、連続する2つの画像の間をコンピューターグラフィックスによって補間し、自然な変形を実現する技術を「モーフィング」と呼びます。
今回は、このモーフィングをJavaScriptライブラリ「Snap.svg」で実装する方法を解説します。
Snap.svgとは?

公式サイト:http://snapsvg.io/
ドキュメント:http://snapsvg.io/docs/
Snap.svgはAdobeが開発したJavaScriptライブラリです。
Snap.svgを使えば、JavaScriptからSVGを制御でき、アニメーションやクリック、ホバーなどのイベント処理を手軽に実装できます。
なお、Snap.svgは Apache License 2.0 の下で配布されており、オープンソースとして商用利用を含め無料で利用できます。
Snap.svgの使い方
Snap.svgのダウンロード方法
Snap.svgをプロジェクトに取り込むには以下の3つの方法があります。
- 公式サイトからファイルをダウンロードしてくる方法
- CDNを使う方法
- npmを使う方法
本記事では2番目のCDNを使う方法でSnap.svgの使い方を解説します。
SVGコードをアニメーションさせる方法
本例では、Snap.svgを用いてSVGコードで書かれた円(circle)をJavaScriptでアニメーションさせる基本手順を解説します。
<svg id="sample" width="200" height="200" viewBox="0 0 200 200">
<circle id="circle" cx="100" cy="100" r="100" fill="#ccc" />
</svg>

まずは、headタグの中に以下の行を追記します。
<script src="https://cdn.jsdelivr.net/npm/snapsvg@0.5.1/dist/snap.svg-min.min.js"></script>
これでSnapがブラウザのグローバルオブジェクトに公開され、利用できるようになります。
続いて、Snapでアニメーション対象のcircleを取得します。
Snap(“CSS selector”)と書くことで、指定したセレクターにマッチするSVG全体をラップできます。
document.addEventListener("DOMContentLoaded", function () {
const s = Snap("#sample");
});
さらに円要素を取得したい場合は、select(“CSS selector”)メソッドを使用します。
document.addEventListener("DOMContentLoaded", function () {
const s = Snap("#sample");
const circle = s.select("#circle");
});
アニメーションさせたい要素が取得されたら、あとはanimate(attrs, duration, [easing], [callback])メソッドを使って、取得した円要素をどのようにアニメーションさせたいか指定します。
4つのパラメーターの意味は以下の通りです。
パラメーター | 型 | 概要 |
---|---|---|
attrs | オブジェクト | 変更先の属性を表すキーと値の組み合わせを指定 |
duration | 数値 | アニメーションの継続時間をミリ秒で指定 |
easing(任意) | 関数 | イージング関数(あらかじめ用意されているmina関数、または独自に用意した関数)を指定 |
callback(任意) | 関数 | アニメーション終了後に呼び出したいコールバック関数を指定 |
document.addEventListener("DOMContentLoaded", function () {
const s = Snap("#sample");
const circle = s.select("#circle");
circle.animate({ r: 50 }, 1000, mina.easeinout);
});
これで、半径100pxの円が、一秒間かけて半径50pxにまで小さくなっていくアニメーションを実装できました。
Snap.svgには、他にも様々なメソッドが用意されており、非常に多くのことができます。興味がある方はぜひドキュメントを見てみて下さい。
document.addEventListener("DOMContentLoaded", function () {
const s = Snap("#sample");
const circle = s.select("#circle");
function shrink() {
circle.animate({ r: 50 }, 1000, mina.easeinout);
}
function expand() {
circle.animate({ r: 100 }, 1000, mina.easeinout);
}
circle.hover(shrink, expand);
});
Snap.svgを使って異なるpathで描いたSVG画像をスムーズに変形(モーフィング)させる方法
次に、Snap.svgをSVGモーフィングを実装する方法を解説します。
まずは、変化前の図形をイラストレーターを使って作成します。

続いて、viewBoxを揃えたいため、同じキャンバス上に変化前の図形を複製し、変化後の図形を作成します。

一点、モーフィングを実装する際は、変化前と変化後の図形でアンカーポイントを同数にしておかないと、綺麗にアニメーションされないため注意しましょう。
「ファイル>別名で保存」からSVG形式で保存します。

以上で、変化前と変化後のアイコンのSVGコードが取得できました。
イラストレーターでは書き出し時に不要な記述が付いてくるため、不要な部分のみあらかじめ削除しておきます。
<svg viewBox="0 0 1000 1000" width="200" height="200">
<defs>
<style>
.st0 {
fill: #b3b3b3;
}
</style>
</defs>
<path
class="st0"
d="M989.1,500c0,131.9-52.2,251.6-137.1,339.6-89,92.2-213.8,149.6-352.1,149.6s-275.6-63.3-365.2-163.7C57.7,739,10.9,625,10.9,500c0-119.8,43-229.5,114.5-314.5C215.1,78.7,349.6,10.9,500,10.9c132.7,0,253.1,52.8,341.2,138.6,91.3,88.9,148,213.1,148,350.5Z"
/>
<path
class="st0"
d="M989.1,500c0,131.9-226.3,77.5-311.2,165.5-89,92.2-39.7,323.7-178,323.7s-109.1-229.8-198.6-330.3C224.3,572.4,10.9,625,10.9,500c0-119.8,202.2-70.4,273.6-155.4C374.2,237.8,349.6,10.9,500,10.9c132.7,0,104.7,218,192.8,303.8,91.3,88.9,296.3,47.9,296.3,185.3Z"
/>
</svg>
次に、Snap.svgで各pathを操作できるようにするため、svgとpathにid属性を付与します。
また、変化後のpathはdisplay:noneとして初期状態では表示されないようにします。
<svg viewBox="0 0 1000 1000" width="200" height="200" id="sample">
<defs>
<style>
.st0 {
fill: #b3b3b3;
}
</style>
</defs>
<path
id="beforePath"
class="st0"
d="M989.1,500c0,131.9-52.2,251.6-137.1,339.6-89,92.2-213.8,149.6-352.1,149.6s-275.6-63.3-365.2-163.7C57.7,739,10.9,625,10.9,500c0-119.8,43-229.5,114.5-314.5C215.1,78.7,349.6,10.9,500,10.9c132.7,0,253.1,52.8,341.2,138.6,91.3,88.9,148,213.1,148,350.5Z"
/>
<path
id="afterPath"
style="display: none"
class="st0"
d="M989.1,500c0,131.9-226.3,77.5-311.2,165.5-89,92.2-39.7,323.7-178,323.7s-109.1-229.8-198.6-330.3C224.3,572.4,10.9,625,10.9,500c0-119.8,202.2-70.4,273.6-155.4C374.2,237.8,349.6,10.9,500,10.9c132.7,0,104.7,218,192.8,303.8,91.3,88.9,296.3,47.9,296.3,185.3Z"
/>
</svg>
Snap(“CSS selector”)、select(“CSS selector”)メソッドを使って、Snap.svgから各pathを操作できるようにします。
document.addEventListener("DOMContentLoaded", function () {
const s = Snap("#sample");
const beforePath = s.select("#beforePath");
const afterPath = s.select("#afterPath");
});
attr()メソッドを使って、beforePath、afterPathのd属性の値を取得します。
document.addEventListener("DOMContentLoaded", function () {
const s = Snap("#sample");
const beforePath = s.select("#beforePath");
const afterPath = s.select("#afterPath");
const dBeforePath = beforePath.attr("d");
const dAfterPath = afterPath.attr("d");
});
最後にanimate(attrs, duration, [easing], [callback])メソッドを使って、第一引数attrsの中で変更後のd属性の値を指定します。
パラメーター | 型 | 概要 |
---|---|---|
attrs | オブジェクト | 変更先の属性を表すキーと値の組み合わせを指定 |
duration | 数値 | アニメーションの継続時間をミリ秒で指定 |
easing(任意) | 関数 | イージング関数(あらかじめ用意されているmina関数、または独自に用意した関数)を指定 |
callback(任意) | 関数 | アニメーション終了後に呼び出したいコールバック関数を指定 |
document.addEventListener("DOMContentLoaded", function () {
const s = Snap("#sample");
const beforePath = s.select("#beforePath");
const afterPath = s.select("#afterPath");
const dBeforePath = beforePath.attr("d");
const dAfterPath = afterPath.attr("d");
beforePath.animate({ d: dAfterPath }, 1000, mina.easeinout);
});
これでモーフィングが実装できました。
なお、上の例ではbeforePathからafterPathへの変形が一度だけ行われましたが、以下のように書くことで、beforePathとafterPathを交互に変化させ続けることができます。
document.addEventListener("DOMContentLoaded", function () {
const s = Snap("#sample");
const beforePath = s.select("#beforePath");
const afterPath = s.select("#afterPath");
const dBeforePath = beforePath.attr("d");
const dAfterPath = afterPath.attr("d");
function svgMorphAnimation(toAfter = true) {
beforePath.animate(
{ d: toAfter ? dAfterPath : dBeforePath },
1000,
mina.easeinout,
function () {
svgMorphAnimation(!toAfter);
}
);
}
svgMorphAnimation(true);
});
まとめ
今回はSnap.svgの基本的な使い方、SVGモーフィングを実装する方法を解説しました。
Snap.svgが使えるようになると表現の幅が広がるため、ぜひこの機会にマスターしてみて下さい。
今回は以上になります。最後までご覧頂き、ありがとうございました。