ウェブサイト作成用備忘録・１２号：ページ読み込み時にcanvasアニメーションを実行【コピペでプレビュー＋α】

今回はcreateJSの勉強のまとめとして、簡単なcanvasアニメーションを実装してみました。

（下記はコピペでプレビューVerですが、一連の処理はJavaScriptのみで完結しているので、本来はheadタグにJQueryとcreateJSのURL+JSファイルを埋め込むだけでアニメーションを実行してくれます）

```html

<!doctype html>
<html>

<head>
  <!-- エンコードの指定 -->
  <meta charset="UTF-8">
  <meta http-equiv="content-language" content="ja">
  <!-- IEで常に標準モードで表示させる -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <!-- viewport(レスポンシブ用) -->
  <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0">
  <!-- jquery -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <!-- createJS -->
  <script src="https://code.createjs.com/1.0.0/createjs.min.js"></script>
</head>

<body></body>
<script>
  jQuery(document).ready(function () {
    // ページ読み込み時に発火
    $(document).ready(function () {

      const max_w = window.innerWidth;
      const max_h = window.innerHeight;
      const rect_w = window.innerWidth * .05;

      // canvas登録
      const canvas = document.createElement("canvas");
      $(canvas).css({
        'position': 'fixed',
        'top': '0',
        'left': '0',
        'width': '100%',
        'height': '100%',
        'z-index': '9999'
      });
      $("body").append(canvas);

      // stage登録
      const stage = new createjs.Stage(canvas);
      stage.canvas.width = max_w;
      stage.canvas.height = max_h;
      if (window.devicePixelRatio) {
        canvas.width *= devicePixelRatio;
        canvas.height *= devicePixelRatio;
        canvas.style.width = String(canvas.width / devicePixelRatio) + "px";
        canvas.style.height = String(canvas.height / devicePixelRatio) + "px";
        stage.scaleX = stage.scaleY = window.devicePixelRatio;
      }

      // container登録
      const rect_a_container = new createjs.Container();
      const rect_b_container = new createjs.Container();
      // ループ分で10回
      for (var i = 0; i < 10; i++) {
        // 長方形を作成し
        var rect_a = new createjs.Shape();
        var rect_a_x = (window.innerWidth * i) * .1;
        rect_a.graphics
          .beginFill("#000000")
          .beginStroke("#000000")
          .setStrokeStyle(.5, "square")
          .drawRect(rect_a_x, 0, rect_w, max_h);
        // コンテナに追加
        rect_a_container.addChild(rect_a);
      }
      // ループ分で10回
      for (var i = 0; i < 10; i++) {
        // 長方形を作成し
        var rect_b = new createjs.Shape();
        var rect_b_x = ((window.innerWidth * i) * .1) + (window.innerWidth * .05);
        rect_b.graphics
          .beginFill("#000000")
          .beginStroke("#000000")
          .setStrokeStyle(.5, "square")
          .drawRect(rect_b_x, 0, rect_w, max_h);
        // コンテナに追加
        rect_b_container.addChild(rect_b);
      }
      stage.addChild(rect_a_container);
      stage.addChild(rect_b_container);

    　//tween登録
    　const rect_a_t = createjs.Tween.get(rect_a_container)
      　.wait(700)
      　.to({
        　y: window.innerHeight
      　}, 1000, createjs.Ease.cubicInOut);

    　const rect_b_t = createjs.Tween.get(rect_b_container)
      　.wait(700)
      　.to({
        　y: window.innerHeight * -1
      　}, 1000, createjs.Ease.cubicInOut)
      　.call(canvas_end);

　　　//timeline登録
    　const timeline = new createjs.Timeline();
    　timeline.addTween(rect_a_t, rect_b_t);


      // 画面更新の頻度を60FPSに設定
      createjs.Ticker.timingMode = createjs.Ticker.RAF;
      // 時間経過
      const timer = createjs.Ticker.addEventListener("tick", function () {
        stage.update(); //画面更新
      });

      // canvas終了
      function canvas_end() {
        //全てのTweenを削除
        createjs.Tween.removeAllTweens();
        //Tickerを削除
        createjs.Ticker.removeEventListener("tick", timer);
        //全てのオブジェクトを削除
        stage.removeAllChildren();
        //stageを削除
        stage.clear();
        //canvasを削除
        $(canvas).remove();
      }
    });
  });
</script>

</html>

```

作成の際に工夫したポイントは…
１：JavaScript側で処理を完結させる為に、createElementメソッドでcanvasタグを作成し、CSS設定もJQueryのCSSメソッドで設定している点

２：chromeのデベロッパーツール上では確認できないのですが、レティーナディスプレイ未対策のcanvasはスマホ等でそのまま表示すると引き延ばされてぼやけた表示になってしまう為、createJSのstageオブジェクト作成時に…

```
stage.canvas.width = max_w;（画面サイズ分の横幅）
stage.canvas.height = max_h;（画面サイズ分の縦幅）
↓
if (window.devicePixelRatio) {
（レティーナディスプレイかどうかの判定）
↓
canvas.width *= devicePixelRatio;
canvas.height *= devicePixelRatio;
（↑canvasタグ内のwidth,height属性をレティーナディスプレイ分拡大）
↓
canvas.style.width = String(canvas.width / devicePixelRatio) + "px";
canvas.style.height = String(canvas.height / devicePixelRatio) + "px";
（↑canvasタグのCSS設定を元々の表示サイズまで縮小）
↓
stage.scaleX = stage.scaleY = window.devicePixelRatio;
（↑createJS内のstageオブジェクトをレティーナディスプレイ分拡大）
（※ただし、canvasタグのCSS設定が優先される）

```

上記の処理を加える事で対策しています！（受け売りです）

３：createJSはstageオブジェクト内にcontainerオブジェクトを作成する事で複数のディスプレイオブジェクトをまとめて制御することが出来ます。そこで、containerを二つ作成し、それぞれにfor文の繰り返し処理で長方形を交互に10個ずつ配置する事で、start時点では画面全体が黒く塗りつぶされた状態になります。

同じ処理をHTML+CSSやSVG制御だけで実現しようとすると、テキストの量が多くなりがちですが、JavaScriptで対応する事でより楽に実装が出来るようになったと思います。

４：createJSのtweenJSでディスプレイオブジェクトのアニメーション制御が可能になるのですが、日本語の解説サイトでは複数のアニメーションの同時処理の方法が中々見つからなくて実装に苦戦しました…

これはTimelineメソッドを使用する事で実装が出来ました。

```js

//tween登録
const rect_a_t = createjs.Tween.get(rect_a_container)
  .wait(700)
  .to({
    y: window.innerHeight
  }, 1000, createjs.Ease.cubicInOut);

const rect_b_t = createjs.Tween.get(rect_b_container)
  .wait(700)
  .to({
    y: window.innerHeight * -1
  }, 1000, createjs.Ease.cubicInOut)
  .call(canvas_end);
  // （↑timelineメソッドに登録するtweenを変数で宣言）

//timeline登録
const timeline = new createjs.Timeline();
timeline.addTween(rect_a_t, rect_b_t);
// （↑timelineメソッドに先ほどのtweenの変数を登録）
// （※timelineメソッド無しでプレビューを確認した時は最初に登録したtweenのみが発火して、以降のtweenは反応がありませんでした）

```

ちなみに、同時ではなくてＡ→Ｂと連続で発火させる場合は…

```js

function rect_a_t () {
  createjs.Tween.get(rect_a_container)
    .wait(700)
    .to({
      y: window.innerHeight
    }, 1000, createjs.Ease.cubicInOut)
    .call(rect_b_t);
}

function rect_b_t () {
  createjs.Tween.get(rect_b_container)
    .wait(700)
    .to({
      y: window.innerHeight * -1
    }, 1000, createjs.Ease.cubicInOut)
    .call(canvas_end);
}

```

↑の様にcreateJSのcallメソッドを使用して、tweenを登録した各関数を呼び出す事で順番にアニメーションが可能です

５：アニメーション実行後callメソッドでcanvas終了関数を呼び出し、生成したcanvasタグ含めてすべての処理を削除する事でブラウザの負担を減らすようにしています。

```js

// canvas終了
function canvas_end() {
  //全てのTweenを削除
  createjs.Tween.removeAllTweens();
  //Tickerを削除
  createjs.Ticker.removeEventListener("tick", timer);
  //全てのオブジェクトを削除
  stage.removeAllChildren();
  //stageを削除
  stage.clear();
  //canvasを削除
  $(canvas).remove();
}

```

最初はcanvasタグを削除すれば関連するcreateJSの処理も勝手に終了すると思っていたのですが、実際にはそんなことはなく、特にTickerに処理が残っていると内部では60fpsで永遠に処理が続いてしまう為、注意が必要だと思いました。

今回は以上になります。自分用の備忘録ですが、誰かの参考になれば幸いです。