モーションパスアニメーションのモジュールを作った

## はじめに

モーションパスアニメーションのJavaScriptモジュールを作りましたのでご紹介します。こんなやつです。  

<a href = "https://masatomakino.github.io/createjs-particle-waypoint/demo/"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9556/d93c4e36-5db1-113c-4e10-3c5145663923.gif"></a>  

デモは[こちらから](https://masatomakino.github.io/createjs-particle-waypoint/demo/)。

## 目的

モーションパスに沿った粒子が流れるアニメーションは

- 粒子の速度
- 粒子の生成頻度
- アニメーションの停止 / 再開

でユーザーに直感的に情報を伝えることができ、機能や機器のインジケーターとして利用できます。

こうしたアニメーションは応用の幅が広く、利用頻度も高いためモジュールとしてまとめて再利用できるようにしました。

## モジュールの構成

モジュールの構成は2つに分かれています。

[![ReadMe Card](https://github-readme-stats.vercel.app/api/pin/?username=MasatoMakino&repo=particle-waypoint)](https://github.com/MasatoMakino/particle-waypoint)

まずは単純にモーションパスから座標の割り出しと、パーティクルの生成管理のみを行うモジュール`particle-waypoint`があります。このモジュール単体では描画機能がありません。

[![ReadMe Card](https://github-readme-stats.vercel.app/api/pin/?username=MasatoMakino&repo=createjs-particle-waypoint)](https://github.com/MasatoMakino/createjs-particle-waypoint)

[![ReadMe Card](https://github-readme-stats.vercel.app/api/pin/?username=MasatoMakino&repo=threejs-particle-waypoint)](https://github.com/MasatoMakino/threejs-particle-waypoint)

`particle-waypoint`を拡張し、描画ライブラリと組み合わせたものが`createjs-particle-waypoint`と`threejs-particle-waypoint`になります。`particle-waypoint`はその他の描画ライブラリとも組み合わせ可能になっています。

## デモ

`createjs-particle-waypoint`を例にして、デモを紹介します。

<a href = "https://masatomakino.github.io/createjs-particle-waypoint/demo/particle.html"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9556/2d231671-89d5-69de-5026-fce8941f3d64.jpeg" width=480px></a>

単一のパーティクルをモーションパスに沿って操作するデモは[こちらから](https://masatomakino.github.io/createjs-particle-waypoint/demo/demo_Particle.html)。
画面左上のGUIから、パラメーター`t`を変更するとパーティクルが移動します。また、`path`を変更すると軌道を、`ease`を変更するとイージング効果を設定できます。

<a href = "https://masatomakino.github.io/createjs-particle-waypoint/demo/"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9556/f3c6d0fa-271c-8d2a-3e9f-89b1b76596a9.jpeg" width=480px></a>

パーティクルを連続的に生成するデモは[こちらから](https://masatomakino.github.io/createjs-particle-waypoint/demo/demo_ParticleGenerator.html)。
パーティクルの生成間隔、速度、イージング、モーションパスなどを操作できます。

## 機能

`particle-waypoint`の主な機能を紹介します。

### モーションパス

モーションパスの指定は、以下の形式に対応しています。

- 2次元座標の配列
- 3次元座標の配列
- 3次ベジェ曲線

### パーティクルの逐次生成とループ

パーティクルの生成方法は、以下の方法に対応しています。

- 一定時間間隔での逐次生成と破棄
- アニメーション開始時に一括生成

逐次生成はアニメーションの自由度が高く、一括生成は処理の負荷が低くなります。

### 再生 / 停止 / バルブ

アニメーションの再生/停止は任意のタイミングで行えます。ブラウザがバックグラウンドに回っても破綻や遅延を起こさずにアニメーションを再開できます。
また、アニメーションを続行したままパーティクルの逐次生成のみを停止/再開することもできます。

### イージング

パーティクルの移動にイージング関数を組み合わせることができます。各種ライブラリのイージング関数をそのまま適用できるので、 少ない工数で演出に一味加えることができます。

## 導入方法

`createjs-particle-waypoint`を例に、導入方法の解説をします。

### インストール

`createjs-particle-waypoint`は[CreateJS](https://github.com/CreateJS/CreateJS)に依存しています。html側で先にCreateJSを読み込んでください。

```html
<script src="https://code.createjs.com/1.0.0/createjs.min.js"></script>
```

`createjs-particle-waypoint`のインストールをnpm経由で行います。

```bash
npm install https://github.com/MasatoMakino/createjs-particle-waypoint.git --save-dev
```

### インポート

このモジュールは、ES6のjsファイルとTypeScript用の型定義ファイルで構成されています。動作に必要なクラスをインポートします。

```js
import {
  CanvasParticleWay,
  CanvasParticleGenerator
} from "createjs-particle-waypoint";
```

### 初期化

座標の配列を用意し、モーションパスを生成します。

```js
const points = [[100, 100], [100, 200], [200, 200], [200, 300]];
const wayPoint = new CanvasParticleWay(points);
```

次にCreateJSのステージを初期化し、

```js
const updateStage = () => {
  stage.update();
};

const canvas = document.getElementById("canvas");
const stage = new createjs.Stage(canvas);

createjs.Ticker.timingMode = createjs.Ticker.RAF;
createjs.Ticker.on("tick", updateStage);
```

ステージとモーションパスを与えてパーティクル生成器を初期化します。

```js
const shape = new createjs.Shape();
shape.graphics
  .beginFill("#F00")
  .drawCircle(0, 0, 4)
  .endFill();

const generator = new CanvasParticleGenerator(stage, wayPoint, shape);
generator.play();
```

これでアニメーションが始まります。

## API Documents

より詳しい機能についてはこちらをご参照ください。

- [particle-waypoint](https://masatomakino.github.io/particle-waypoint/api/)
- [createjs-particle-waypoint](https://masatomakino.github.io/createjs-particle-waypoint/api/)
- [threejs-particle-waypoint](https://masatomakino.github.io/threejs-particle-waypoint/api/)

## 参考記事

- [ベジエ曲線について](http://d.hatena.ne.jp/shspage/20140625/1403702735)
- [ベジェ曲線の長さを求める](https://ryosukeeeee.hatenablog.com/entry/2018/12/02/170314)
- [イラレの円は本当は円じゃない（もしくは時空の裂け目について）](http://n-yuji.hatenablog.jp/entry/20131017/p1)
ベジェ曲線で円を描き、正円と比較するテストコードを書いたところ、時空の裂け目に落ちて詰まりました。
- [ベジェ曲線による円の描画の制御点の位置はなぜ 0.55228…なのか?](https://cat-in-136.github.io/2014/03/bezier-1-kappa.html)
ベジェ曲線での円の制御点について詳しく解説されています。
- [CreateJS File:MotionGuidePlugin.js](https://www.createjs.com/docs/tweenjs/files/tweenjs_plugins_MotionGuidePlugin.js.html#l402)
2次ベジェ曲線でのモーションパスの分割数はなんと10でした。荒い分割でもアニメーション目的なら十分な精度が出るというのは驚きでした。
- [累積和を何も考えずに書けるようにする！](https://qiita.com/drken/items/56a6b68edef8fc605821)
累積和を利用すると中間座標が低負荷で算出できます。