虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

Anime.js + SVG で画像をヌルヌル動かす!

※本記事は予約投稿です。

こんにちは、通販サイトのフロントチームでエンジニアをしています、Y.I. です。
本記事は虎の穴ラボ Advent Calendar 2021 - Qiita 5日目の記事です。

4日目はY.F.さんの「Denoでdll/soを読み込む(deno FFI)」でした。
また、明日6日目は大場さんの「Swagger + API GatewayでAPI定義を流用したAPIサーバー構築」です。

それでは早速 第5回、「anime.js + SVG で画像をヌルヌル動かす!」スタートです!!! f:id:toranoana-lab:20211201172309p:plain

目次

  • 何をやるか
  • Anime.jsとは
  • 実装手順
    • 手順1:SVGを用意する
    • 手順2:DOM(動かす対象・画像)を用意する。
    • 手順3:Anime.jsで動きを作る
    • 手順4:Anime.jsで動かす
  • 作例紹介
    • 作例1:深夜を徘徊するエンジニア
    • 作例2:闇夜を舞うエンジニア
  • 補足
    • 補足1:開発のコツ
    • 補足2:Adobe Illustrator を学ぶのに便利な情報
  • おわりに

何をやるか

本記事でご紹介するのは、「SVGのpathに沿って画像(DOM)を動かす」というとてもシンプルな内容です。
DOMを動かす方法は他にも沢山ありますが、一つの例として紹介させていただきます。
実装に悩んだ時に、「こんな方法もあったなあ」と思い出していただたら幸いです。

DOMを動かすだけのシンプルな内容。Anime.jsの公式Documentにもサンプルあり

Anime.jsとは

Anime.jsはシンプルでパワフルな、JavaScriptアニメーションライブラリです。 総容量が17.3kbと、とても軽量であり、DOMに対して手軽にアニメーションを付与することができます。

詳しくは公式ドキュメントを見ていただくとわかりやすいのですが、個々のアニメーションをJavaScriptのオブジェクト単位で管理できるため、アニメーションの調整を直感的かつシンプルに行える点が個人的に気に入っています。

animejs.com

※ Anime.jsに関しては、過去にQiitaにて記事を書かせていただきましたので、よろしければぜひこちらもご覧ください。

実装手順

手順1:SVG(動かす軌跡)を用意する

それでは実装の方法について、順番に内容を見ていきます。

DOMを動かす手順は、大きく分けて4つです。

手順1:SVG(動かす軌跡)を用意する (← イマココ)
手順2:DOM(動かす対象・画像)を用意する
手順3:Anime.jsで動きを作る
手順4:Anime.jsで動かす

まず初めに、動かしたいpathを持ったSVGを用意します。今回はシンプルに、直線を一本引いただけのSVGを使うことにします。
※ SVGの書き方についてはMDNの解説がわかりやすく参考になります。

<svg id="svg01" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080">
<!-- XY座標(0, 600)から長さ1,900の水平線を引く -->
  <path d="M 0 600 H 1900" />
</svg>

developer.mozilla.org

手順2:DOM(動かす対象・画像)を用意する。

次に、DOM(動かす対象・画像)を用意します。 今回の実装では、とらラボのエンジニアに動いてもらうこととします。

今回の素材はこちら... 日頃お世話になっている先輩エンジニアに動いてもらいます。

<div class="chara01"></div>

上記のように動かす対象のHTMLを用意します(今回はキャラ画像をbackground-imageで設定)。

手順3:Anime.jsで動きを作る

手順3では、手順1と2でそれぞれ用意したSVGとDOMを組み合わせて、実際のアニメーションを定義します。
ここではAnime.jsで提供されているanimeオブジェクトを使用して、"walk" という名前のアニメーションを定義します。

const path = anime.path("#svg01 path"); // animeオブジェクトを使用してDOMのpathを取得する。

const walk = { // "walk"という名前でpathに沿った動きを定義する
  targets: ".chara01", // ここでは動かしたいDOMを渡す
  easing: "linear", // イージングは一定(linear)に設定
  translateX: path("x"), // 取得したpathのx座標を設定
  translateY: path("y"), // 同じく、pathのy座標を設定
  duration: 3000, // 実行時間を(適当に)3000msで設定
};

これで準備完了です。

手順4:Anime.jsで動かす

最後に、手順3で作ったオブジェクト実行します。

anime(walk); // 手順2で作成した "walk"オブジェクトを引数にして実行

すると...

...

動いたーーーーー!!!!!

エンジニア_アニメーション
gifなのでカクついて見えるが実際は滑らか

SVGとDOMを用意して、ほんの少しコードを書いてあげるだけで、簡単にアニメーションを実装することができました。

作例紹介

作例1:深夜を徘徊するエンジニア

上記までで基本の実装は完了です。 しかしキャラクターの動きが乏しく、実際にキャラクターが歩いているようには見えません。 そこでもう少しだけアニメーションを調整してみたいと思います。

まずは、DOM要素を微調整します。

<div class="chara01">
  <img src="画像のパス"> // アニメーションの調整に伴い、background-imageではなimgタグで画像を表示するように変更
</div>

次に、JSでアニメーションを調整します。
// 歩くアニメーション(調整版)
const walk = {
  targets: ".chara01", 
  easing: "linear",
  translateX: path("x"), 
  translateY: path("y"), 
  duration: 3000, 
  direction: "alternate", // [New!] 進行方向を設定. 'alternate' は 「行って戻る」
  loop: true // [New!]  動作をループさせる
};

//  [New!] キャラを左右に揺らす
const swing = {
  targets: ".chara01 img", // 左右に揺らす動きを新規作成したimgタグに設定する
  easing: "linear", // イージングは一定(linear)に設定
  rotate: [10, -10], // 左右に10度ずつ揺らす
  direction: "alternate", // 揺れる方向を設定。「行って戻る」ように揺らがせる
  duration: 300, // 歩く速度の1/10くらいに設定
  loop: true, // 揺れを繰り返す
};

anime(walk);
anime(swing);

上記を設定した上で、さらに背景画像をセットしてやると...

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

歩いたーーーーー!!!!!

アニメーション_作例1
作例1:深夜を徘徊するエンジニア。こんな深夜にどこへ行こうというのかね?

シンプルな直線移動だけでは不自然だった表現も、ごくわずかに手を加えてあげるだけで、一気に「歩いている感」が生まれました。 Anime.jsの強みである、「ちょっとした調整を素早く直感的にできる」という点が表れた作例と言えます。

作例2:闇夜を舞うエンジニア

作例1に続いて、今度はもう少し複雑な動きを表現してみます。

はじめに、Adobe Illustrator (以下イラレと呼称)を使用して下記のようなpathを作り、SVGで書き出します。

イラレで適当に書いた曲線。もちろんイラレでなくても構いません。

続いて、「作例1」と同じ手順で、SVGのDOM取得と、アニメーションの設定を行います。

const path02 = anime.path("#svg02 path"); // 同じようにDOMを取得して...
const anime02 = { // ここで動きを設定するだけ
  targets: ".chara02",
  easing: "linear", // イージングは一定(linear)に設定
  translateX: path02("x"),
  translateY: path02("y"),
  duration: 6000, // 今回は少し長めの時間で
  scale: [0.1, 2, 4], // 画像のサイズも少し変形してみる(x0.1 -> x2  -> x4)の順でサイズを変化
};
anime(anime02); // 上記の動きを実行

上記の記述を実行すると・・・

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

飛んだーーーーー!!!!!

アニメーション_作例2
作例2:闇夜を舞うエンジニア

イラレで作成したpathの通りにキャラクターが動いているのがわかるかと思います。軌跡の通りに動かすだけでは面白みがなかったので、scaleオプションを設定し流動的に画像サイズが変わるようにし、アニメーションに奥行きを付けてみました。
このような一見すると複雑な動きでも、SVGを用いることでシンプルに実装することができます。

補足

補足1:開発のコツ

アニメーションの細かい設定をする際は、作成したパスを実線として一時的に表示してあげると、細かいアニメーションの調整が行いやすいためオススメです。

svgのpathを赤色で表示したもの。pathを表示した状態だと、細かい動作のイメージ・実装が行いやすい。

<!-- 開発中のみ、strokeと stroke-width を設定して赤い実線を表示する -->
<path stroke="red" stroke-width="10" d="・・・" />

補足2:Adobe Illustrator を学ぶのに便利な情報

今回 の「作例2:闇夜を舞うエンジニア」のように複雑なpathを必要とする場合は、Adobe Illustrator (以下イラレと呼称)などのソフトを使用してベジェ曲線を引くことで、直感的にSVGのpathを作成できます。
イラレの場合はペンツールを使うことになるかと思いますが、慣れていない方(私もですが...)にとって、初めてペンツールを使う際は操作に戸惑うことがあるかもしれません。

そこで私が実際に参考にさせていただいたAdobe公式から提供されている解説動画を紹介させていただきます。これからチャレンジされるという方にはぜひオススメの動画です。

【CC道場 #010】これでお絵描き自由自在、ベジェの基本を極めよう - アドビ公式 - YouTube
(使い方説明はこちらの動画の16:00くらいから。)

おわりに

Anime.jsとSVGを使用して、DOMを動かす方法について紹介しました。読んでいただきありがとうございます。
ほとんどコードを書いていないので、「なんだ、これだけか」と拍子抜けされた方も多いかもしれません・・・。

ただ、この直感的でシンプルな記述は書いていてとても楽しく、またSVGを使用することで実装の省力化に役立つことがあるかと思います。 DOM操作には様々な方法がありますが、こんな方法もあるということを知っておいていただけたら幸いです。

それでは最後に、「作例1:深夜を徘徊するエンジニア」でご紹介したソース一式を紹介して終わりたいと思います。

明日6日目は大場さんの記事です!!!
ぜひご覧ください!!

<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>深夜を徘徊するエンジニア</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      body {
        background-color: #1655a0;
      }
      #svg01 {
          position: absolute;
          z-index: 100;
          top: 0;
      }
      .chara01 {
        position: absolute;
        z-index: 100;
        top: 0;
        width: 30%;
      }
      .chara01 img {
        max-width: 100%;
      }
      .bg_01 {
        width: 1920px;
        max-width: 100%;
        height: 1080px;
        background-image: url("./img/bg_01.png");
        background-size: 100% auto;
        background-repeat: no-repeat;
      }
    </style>
  </head>
  <body>
    <div class="bg_01"></div>
    <div class="chara01">
      <img src="./img/chara01.png" />
    </div>
    <div>
      <svg
        id="svg01"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 1920 1080"
      >
        <path d="M 0 600 H 1900" />
      </svg>
    </div>

    <script src="./anime.js"></script>
    <script>
      const path02 = anime.path("#svg01 path");
      const walk = {
        targets: ".chara01",
        easing: "linear",
        translateX: path02("x"),
        translateY: path02("y"),
        direction: "alternate",
        duration: 3000,
        loop: true
      };
      const swing = {
        targets: ".chara01 img",
        easing: "linear",
        rotate: [10, -10],
        direction: "alternate",
        duration: 300,
        loop: true,
      };
      anime(walk);
      anime(swing);
    </script>
  </body>
</html>

P.S.

採用情報

■募集職種
yumenosora.co.jp

カジュアル面談も随時開催中です

■お申し込みはこちら!
news.toranoana.jp

■ToraLab.fmスタートしました!

メンバーによるPodcastを配信中!
是非スキマ時間に聞いて頂けると嬉しいです。
anchor.fm

■Twitterもフォローしてくださいね!

ツイッターでも随時情報発信をしています
twitter.com