DigiPress

Highly Flexible WordPress Theme

メニュー

Retina対応の canvas + Javascript による波形アニメーションサンプル

 2017/12/16
Retina対応の canvas + Javascript による波形アニメーションサンプル

弊社にて現在開発中のWordPressテーマに搭載する機能の候補として、各セクションの境界の形状に、波形の波打つアニメーション要素を表示する仕組みを簡単に作ってみました。

想定は、例えば弊社で提供中のDigiPressテーマに搭載の「パララックススクロール」ウィジェットで表示できるコンテンツの境界デザインとして表示することを考慮し、アニメーションさせる canvas要素は1ページ内に決められた数ではなく複数存在することを前提とします。

セクションの境界は、HTML5 canvas に対して、Javascript にて sin関数で波形を描画し、setTimeout関数で位置をずらしながらキャンバスを移動させます。

境界アニメーション要素の条件

  • 波形を描画するcanvas要素の数は不定のため、すべてのcanvas要素について波形の描画とアニメーションを実行する。
  • canvas の描画は高精細ディスプレイに対応させる。
  • 波形は1つの境界要素(canvas)に最大3つまで重ね合わせることができ、それぞれ波形の色を指定できる(アルファ値有効)。
  • 汎用性の観点から、波形の色はdata属性に指定し、Javascript側でそれを取得して動的に塗りつぶす。
  • 1つの境界要素(canvas)に波形が1つだけの場合は、波形の色のアルファ値は無効にする。

完成イメージがこちら。

See the Pen Wave animation with canvas (Retina ready) by digistate (@digistate) on CodePen.

HTMLの構成

波形の描画だけなら canvas タグのみでできますが、テキストや画像があるコンテンツ要素の境界として扱うため、ラッパー要素(.canvas-wrapper)でセクション全体を括り、その中に canvas(.wave-bar)とメインのコンテンツ(.inner)を配置します。

波形のみを表示する場合

<div class="canvas-wrapper">
  <canvas class="wave-bar" data-color1="#C8D32F"></canvas>
</div>

上部境界に波形を表示し、メインコンテンツの背景と同化させる場合

<div class="canvas-wrapper">
  <canvas class="wave-bar" data-color1="#43c0e4" data-color2="#43c0e4" data-color3="#43c0e4"></canvas>
  <div class="inner" data-bgcolor="#7DD1EF" data-color="#fff">メインコンテンツ</div>
</div>

波形は3つまで表示可能で、波形の色は、canvas要素の data-color1, data-color2, data-color3 属性で指定します。
この data-color[n] の数が波形の数に一致します。

境界の波形(canvas)とメインコンテンツ(.inner)が同化して見えるようにするために、メインコンテンツ要素には data-bgcolor背景カラーdata-colorフォントカラーを指定できるようにしておきます。
これらのカラーコードを、Javascript側で取得してメインコンテンツのスタイルに反映させます。

上下の境界に波形アニメーションを表示する場合

<div class="canvas-wrapper">
  <canvas class="wave-bar" data-color1="#96D601" data-color2="#00BA89"></canvas>
  <canvas class="wave-bar flipped" data-color1="#96D601" data-color2="#00BA89"></canvas>
</div>

上下の境界に波形を表示する場合は、canvas要素を2つ指定し、2つ目のセレクタに .flipped を加えます。
.flipped セレクタがある場合は、単純にCSSで要素を反転させて表示するようにしています。

Javascriptによるcanvasの描画

canvasの波形の描画処理については、今回参考にしたドキュメントに詳しく解説されているため割愛します。
ここでは、今回のサンプルで独自に追加した必要な処理について記載しておきます。

波形用canvas要素の取得、初期化

// .wave-bar セレクタを持つ要素をすべて取得
canvasList = document.querySelectorAll('.wave-bar');

// 各.wave-bar要素について順番に初期化
Array.prototype.forEach.call(canvasList, 
  function(canvas, index){
    // 初期化の処理
  }
);

document.querySelectorAllでセレクタを指定して、波形アニメーションを表示する対象要素をすべて取得し、Array.prototype.forEach.call という書式で、取得した canvasListオブジェクトをforeachのように順番に処理します。

canvasの描画を高精細ディスプレイに対応させる

canvasに幅と高さを表示したいサイズの数値でそのまま指定すると、Retinaディスプレイのような高精細ディスプレイでは、2倍以上の解像度が必要となるため、画像(img)と同じように描画が粗くなります。
これを解決するためには、まずは通常通りcanvasに表示したいサイズをセットします。

そのサイズに devicePixelRatio という、表示されるディスプレイのピクセル比を表すプロパティの数値を掛け、適切な解像度にリサイズ(拡大)します。
最後に、必要な解像度までリサイズ(拡大)したcanvas要素を、devicePixelRatio縮小します。

// 幅はブラウザの表示幅と同じにする
canvas.width = document.documentElement.clientWidth;

// devicePixelRatio分、拡大する
canvas.width *= devicePixelRatio;

// 高さはこのサンプルでは幅の4%
canvas.height = canvas.width * .04;

// devicePixelRatio分、拡大する
canvas.height *= devicePixelRatio;

// canvasのstyle属性にdevicePixelRatio分縮小した値をセット
canvas.style.height = String(canvas.height / devicePixelRatio) + "px";

ここでポイントとなるのが、レスポンシブ表示となるよう、canvasの幅は最後に devicePixelRatio分縮小せず、CSSで常に表示幅が100%でリサイズされるようにしておきます。

ラッパー要素に背景色を指定する

ラッパー要素(.canvas-wrapper)同士が切れ目なく波形の境界で繋がっているように見せれるデザインが構成できるよう、ラッパー要素にも背景カラーを指定できるようにします。
ラッパー要素の背景カラーは、canvas要素の data-bgcolor属性に指定します。

// canvas要素のdata属性を取得
var canvasDataSet = canvas.dataset;

// data-bgcolorがある場合
if (canvasDataSet.bgcolor) {
  // 親要素である.canvas-wrapper のスタイルに background-colorをセット
  canvas.parentNode.style.backgroundColor = canvasDataSet.bgcolor;
}

メインコンテンツ部分の配色

メインコンテンツ(.inner)がある場合、境界の波形(canvas)の色と同化させるため、.inner要素にもdata-bgcolordata-color属性を用意してメインコンテンツの背景カラーとフォントカラーを指定できるようにします。

// メインコンテンツ(.inner)要素を取得
var inner = canvas.nextElementSibling;

// メインコンテンツが存在する場合
if (inner){
  // .inner要素のdata属性を取得
  innerDataSet = inner.dataset;

  // data-color がある場合
  if (innerDataSet.color){
    // .inner要素のフォントカラーをセット
    inner.style.color = innerDataSet.color;
  }

  // data-bgcolor がある場合
  if (innerDataSet.bgcolor){
    // .inner要素の背景カラーをセット
    inner.style.backgroundColor = innerDataSet.bgcolor;
  }
}

アニメーションの速さや波形の数、形は作り方次第で様々な組み合わせが考えられるので、canvasだけでもかなりWebデザインの表現の幅が広がるのではないでしょうか。

[参考] Canvasで波のアニメーションを描画する
https://jsfiddle.net/39we73t1/
HTML5 CanvasとWebGLの高解像度対応はどこまで行うべきか

Share / Subscribe
Facebook Likes
Tweets
Hatena Bookmarks
Pinterest
Pocket
Feedly