ICS MEDIAのトップページに掲載しているモーショングラフィック。これはCSS3とHTML5 Canvas要素を使って作成したものです。時間経過とともに波の形状と色彩が変化し、多彩な表現を楽しめるようになっています。

本記事ではCSS3とHTML5 Canvasの理解につながることを目標に、このモーショングラフィックの作成方法をステップ形式で解説します。サンプルのソースコードは全てGitHubにて公開していますので、あわせて参照ください。


▲ 完成版サンプル。実装する上で重要な表現のエッセンスだけを絞って解説します

ステップ1. CSS3でグラデーション背景の作成

はじめに、時間経過で色彩が変化するグラフィックを作成しましょう。CSS3で縦に長いグラデーションの背景を用意し、CSSアニメーションを使って縦方向に移動させることでグラデーションが変化する表現ができます(ステップ1のソースコード)。

#bg {
  /* 背景グラデーションの作成 */
  background: linear-gradient(to bottom,
    hsl(180, 80%, 40%),
    hsl(240, 80%, 60%),
    hsl(300, 80%, 40%));
  background-size: 400% 400%;
  animation: AnimationName 10s ease infinite;
}

@keyframes AnimationName {
  0% { background-position: 50% 0% }
  50% { background-position: 50% 100% }
  100% { background-position: 50% 0% }
}

ステップ2. 波のモーショングラフィックを描く

波のモーショングラフィックは、HTML5 Canvasで描いています。フレームワークとしてCreateJSProcessing.jsを使っています(CreateJSは当サイト内のチュートリアルが学習に便利です)。作り方は「FrocessingではじめるActionScriptドローイング|gihyo.jp」で紹介されているので参考になるでしょう(別の言語ですが、ActionScript 3.0とJavaScriptが似ているので参考になります)。

ポイントとしてはランダム関数として離散乱数が得られるMath.random()ではなく、連続した乱数(パーリンノイズ)が得られるProcessingのnoise()関数を使って曲線の頂点を計算していることです(波の表示クラスのコード)。

const vertexArr = [];
// 波の次の目標値を計算
for (let i = 0; i <= vertexNum; i++) {
  // 乱数を取得、-0.5〜+0.5の範囲
  const noiseNum = noise(i * 0.2, this._time + timeOffset) - 0.5;
  // 目標座標を計算。画面の高さに比例
  vertexArr[i] = noiseNum * stageH * 2;
}

ステップ3. 波に残像を加える

Canvas要素は直前の描画結果を引き継ぐという処理が可能です。この方法を使えば残像効果を実装することができます。詳しくは月刊誌Web Designing 2015年6月号の連載「応用講座Flash for HTML5」にて解説しましたので参考ください。ステップ2で作成した波の表現に残像効果を加えてみましょう。

残像効果は具体的には次のコードで実装することができます(ステップ3のコード)。

// 薄く暗く塗る
const context = stage.canvas.getContext("2d");
context.fillStyle = "rgba(0, 0, 0, 0.2)"; // 4番目の透明度がポイント
context.fillRect(0, 0, 幅, 高さ);
// 表現を更新
stage.update();

ステップ4. 照明効果を作成する

151124_step_3

今までのステップとは別に、演出を華やかにするために一部分だけ光があたっているような演出をcanvas要素で作成しましょう。円形グラデーションの円を2つ配置して、左右に動かします。周期的な動きを作るには三角関数を使うと便利でしょう(ステップ4のコード)。

// 円のX座標 (左右に周期的に移動させる)
const dx = w * 1 / 3 + w / 10 * Math.sin(Date.now() / 4000);
// 円のY座標
const dy = h * 1 / 3;
// 円の大きさ
const size = w / 2;

ステップ5. 波と照明効果を合算する

ステップ3とステップ4で作成した表現を合成します。輝度(ルミナンス)だけで合成したいので、canvas要素のglobalCompositeOperationプロパティーをlighterに設定してdrawImage()メソッドで合成します(ステップ5のコード)。

// 2つのステージを合成する
const ctx = 照明のステージ.canvas.getContext("2d");
ctx.globalCompositeOperation = "lighter";
ctx.drawImage(波のステージ.canvas, 0, 0);

ステップ6. グラデーション背景と合成

最後にステップ1とステップ5の表現を合成します。記事「CSS3のブレンドモードmix-blend-modeを使いこなそう」で紹介したようにCSS3のmix-blend-modeプロパティーを用い特殊なブレンドモードとしてHTML要素を重ねあわせます。これで完成です!(ステップ6のコード)

#canvasOverlay {
  mix-blend-mode: hard-light;
}

ここまでの手順を図解すると次のようになります。一つ一つのステップは単純ななものですが、どうやって合成するかがポイントであったかがわかります。

まとめ

この手の表現は仕組みがわかれば意外とシンプルです。ブレンドモードとして利用しているCSS3のmix-blend-modeプロパティーと、canvas要素のglobalCompositeOperationプロパティーの両方を使えばHTML5での表現の幅が広がります。

いきなりコードで実現するのが難しいという方はPhotoshop等の画像加工ソフトで試してから、コードで実装するとイメージしやすいと思います。ぜひみなさんもwebでのモーショングラフィックに挑戦ください。