マトリョーシカ的日常

ワクワクばらまく明日のブログ。

Railsアプリにanime.jsを導入して顔文字を動かす五月

いつのまにか四月が過ぎていった。暑さはないものの、日差しの強さは日毎に増すばかり。近所のツツジも開きつつある。私はどうかというと、特になにも変わらない。コードを書いている。

フィヨルドブートキャンプでのプラクティスもポートフォリオ作りに入ってきた。作ろうとしているアプリのデモ版をつくっている。最小限のところをやって、本当に実現可能かを見極めるのだ。今回はアニメーションを追加する。

anime.js の導入

アニメーションの実装は anime.js というライブラリを利用する。

anime.js • JavaScript animation engine

なんでもできそう。

Rails 7より、JavaScriptの構築にimport mapsを使うことがデフォルトになった。それをつかってみる。コマンドを打つ。

$ ./bin/importmap pin animejs 

これでパッケージを追加できた。

JavaScriptファイルを追加

既存のJavaScriptファイルとは別に、新しいファイルを追加する。そしてそこにanime.jsをimportする。

app/javascript/simurate.js

import anime from "animejs";

// 略

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>

<! --略 --> 
    <%= javascript_import_module_tag "simurate" %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

このように、javascript_import_module_tag とするとそのようになる。 参考: GitHub - rails/importmap-rails: Use ESM with importmap to manage modern JavaScript in Rails without transpiling or bundling.

svgを描く

<svg id="svg01" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
  <path d="M 0 60 H 100" />
</svg>

 こうするとパスが描ける。パスは軌道であるので、目には見えない。これに沿ってアニメーションをしていけばいいのだな。

コードたち

viewファイルは以下のように書く。ボタンを押すと顔文字が動くようにしよう。

app/views/simurates/index.html.erb

<%= button_tag 'Start', {id: "startbutton"} %>

<div class="svg-wrapper">
  <div id="ob1">(゜∀゜)</div>
  <div id="ob2">(つ´∀`)つ</div>
  <svg id="svg01" xmlns="http://www.w3.org/2000/svg" width="1000" height="500">
    <path fill=none stroke="red" d="M 0 0 L 200 300 L 20 300 Z"/>
  </svg>
</div>

app/javascript/simurate.js

import anime from "animejs";

function animeStart() {
  const path = anime.path("#svg01 path");
  let object1 = {
    targets: "#ob1",
    translateX: path("x"),
    translateY: path("y"),
    direction: "alternate",
    duration: 4000,
    loop: true,
    easing: "linear",
  };

  let object2 = {
    targets: "#ob2",
    translateX: path("x"),
    translateY: path("y"),
    direction: "alternate",
    duration: 4000,
    loop: true,
    easing: "easeInOutSine",
  };

  var tl = anime.timeline({
    easing: "easeOutExpo",
    duration: 500,
  });

  tl.add(object1).add(object2, "-=2000");
}

document.addEventListener("DOMContentLoaded", () => {
  const start = document.getElementById("startbutton");
  if (start) {
    start.addEventListener("click", animeStart(), false);
  }
});

スタイルシートはこんな感じ。

#ob1,
#ob2 {
  position: absolute;
  top: -15px;
  left: -25px;
}

.svg-wrapper {
  margin: 24px;
  position: relative;
}

うごく

test2.gif

https://www.youtube.com/watch?v=mAKYW_1f-dw

ここの動画が役に立った

Unsplash Benjamin Voros