LoginSignup
5
5

More than 5 years have passed since last update.

mo.js -DOM Animation with SVG-

Last updated at Posted at 2016-03-17

SVGパスを使ったアニメーションライブラリ

mo.jsは非jQuery依存のシンプルなアニメーションライブラリです。http://mojs.io/
公式デモがかなり軽量に動いていたので試しに触ってみました。
svgのパスを元にstyleをガシガシ書き換えてつくり込む感じ。

APIは公式を見ればあんまり説明必要なさそうだったので、webpack+babelでやってみたらこうなった、というコードを乗せておきます。凝った動きを作りこむためには沢山svgを用意しパスをゴネゴネする必要がありそうだったので、svgはsvg-inline-loaderで読み込み、GUIで演出に集中できる様にするのがゴールです。

webpack.config.js
loaders: [
      { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ },
      { test: /\.svg$/, loader: 'svg-inline'}
    ]

こんな感じのsvgを用意しておきます。サイズは100px_100px。
バウンスのイージング曲線ですね。

animatePath.png

円を10個動かして何かしようとしてみました。

script.js
import Circles from './circles';
new Circles('.circles',10).run();

せっかくの非jQuery依存なので、querySelectorとDOMParserで、importしたsvgからpath要素のd属性を拾います。そのd属性からTweenに渡すeasing関数を生成します。これでわざわざd属性をコピペしなくて済む様になりました。

circles.js
import mojs from 'mo-js';
import Circle from './circle';
import AnimatePath from '../svg/animatePath.svg';

export default class Circles {
  constructor(selector, count) {
    this.circles = [];
    const dom = document.querySelector(selector);
    const svg = new DOMParser().parseFromString(AnimatePath,'text/xml');
    const d = svg.querySelector('path').getAttribute('d');
    const easing = mojs.easing.path(d);
    for (let i=0; i<count; i++) {
      const c = new Circle(easing,i);
      dom.appendChild(c.dom);
      this.circles.push(c);
    }
    return this;
  }
  run() {
    for (let i=0; i<this.circles.length; i++) {
      this.circles[i].run();
    }
    return this;
  }
}


せっかくのbabelなので、OOPに寄せていければいいなと。今のとこmojs.Tweenのoptionがかなり少ないので、setTimeoutでdelayを追加してみた。(今入っているoptionのdelayはアニメーションリピートのインターバルを指してる)公式のAPIsが非リンクだったので、まだこれからいろいろ実装するものだと思われる。

circle.js
import mojs from 'mo-js';

export default class Circle {
  constructor(easing,x) {
    let div = document.createElement('div');
    div.setAttribute('class', 'circle');
    div.setAttribute('data-css-hide', 'true');
    this.dom = div;
    this.easing = easing;
    this.x = x;
    return this;
  }
  run() {
    setTimeout(() => {
      new mojs.Tween({
        repeat: 99999,
        delay: 0,
        duration: 2000,
        onUpdate: (progress) => {
          let value = this.easing(progress);
          this.dom.style.transform =
          `translateX(${20*this.x-100}px)
           translateY(${(1-value)*100}px)
           scale(${value})`;
        }
      }).run();
      this.dom.setAttribute('data-css-hide', 'false');
    }, this.x*30);
    return this;
  }
};

用意したstyleはこんな感じ。

style.styl
@import 'nib';
global-reset();

.container {
  width: 100%;
  height: 100%;
  position: fixed;
  overflow: hidden;
}

.circles {
  top: 50%;
  left: 50%;
  position: fixed;
}

.circle {
  size = 10px;
  width: size;
  height: size;
  position: absolute;
  margin-left: @width*-.5;
  margin-top: @height*-.5;
  border-radius: @width*.5;
  background: #aaf;
  &[data-css-hide="true"] {
    display:none;
  }
}

これらをpackするとこんな残念な感じの:sob:サンプルができます。

これだったらcssAnimationだけで完結できるね…

で、演出には集中できるの?

svgを保存する度にbrowserSyncとかで即確認、演出に集中しようっていう目的なのですが、svgファイルは一度閉じてしまうとIllustratorでは座標がずれてしまい、sketch.appでは直接編集出来ず、どちらも元ファイルから書き出ししなければいけない様子で、ここのフローは今後も調査が必要だなぁというお話でした。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5