LoginSignup
5
6

More than 5 years have passed since last update.

ノイズアニメーションをワンタッチで実現する

Last updated at Posted at 2018-11-28

sample.png
ゾンビランドサガの公式サイト(の一部)でノイズアニメーションが使われているのを見て、「これはライブラリ化できそうだな」と思い立ち、衝動的に作ったのがこちらです。

Noise Maker - デモ
Noise Maker - リポジトリ

ノイズアニメーションのロジック

ゾンビランドサガではこんな画像を別途用意して使っていますが、これを Canvas で動的に生成することで利便性と汎用性を高めることにしました(言い回しが大げさ)。

  1. 仮想 Canvas を作成
  2. 1 ピクセルごとにランダムな RGBA 値を設定
  3. 指定された DOM ノードの背景画像に Data URI として設定
  4. アニメーションループ内で background-position をランダムに設定

NoiseMaker クラスについて

上記のロジックに基づいて作ったのが NoiseMaker クラスです。以下特徴。

  • 複数の DOM ノードに異なるノイズアニメーションを設定可能
  • ノイズアニメーションを削除可能
  • ノイズ画像のサイズを設定可能
  • 各ピクセルの RGBA 値に対して最小乱数値と最大乱数値を設定可能
  • Firefox では若干遅い( background-position の反映が遅い?)

以下コード。

class NoiseMaker {
  constructor () {
    this.configs = {};
    this.configId = 0;
    setInterval(() => {
      for (let key in this.configs) {
        this.configs[key].target.style['background-position'] = `${this.irandom(0, this.configs[key].width)}px ${this.irandom(0, this.configs[key].height)}px`;
      }
    }, 1);
  }
  make (config) {
    const canvas = document.createElement('canvas');
    canvas.setAttribute('width', config.width);
    canvas.setAttribute('height', config.height);
    const context = canvas.getContext('2d');
    const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
    for (let y = 0; y < imageData.height; y ++) {
      for (let x = 0; x < imageData.width; x ++) {
        const index = (imageData.width * y + x) * 4;
        imageData.data[index] = this.irandom(config.r[0], config.r[1]);
        imageData.data[index + 1] = this.irandom(config.g[0], config.g[1]);
        imageData.data[index + 2] = this.irandom(config.b[0], config.b[1]);
        imageData.data[index + 3] = this.irandom(config.a[0], config.a[1]);
      }
    }
    context.putImageData(imageData, 0, 0, 0, 0, canvas.width, canvas.height);
    config.target.style['background-image'] = `url(${canvas.toDataURL()})`;
    this.configs[this.configId.toString()] = config;
    return this.configId ++;
  }
  remove (configId) {
    this.configs[configId].target.style['background-image'] = null;
    this.configs[configId].target.style['background-position'] = null;
    delete this.configs[configId];
  }
  irandom (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }
}

使い方。

// オブジェクトの作成
const noiseMaker = new NoiseMaker();
// ノイズアニメーションの作成
let configId = noiseMaker.make({
  target: document.querySelector('.target'),
  width: 320,
  height: 320,
  r: [ 0, 255 ],
  g: [ 0, 255 ],
  b: [ 0, 255 ],
  a: [ 0, 255 ]
});
// ノイズアニメーションの削除
noiseMaker.remove(configId);

なお、デモでは二箇所に異なるアニメーションを設定しています。

終わりに

即興で書いたので色々アレですが、大体こんな感じで良いと思います。α値を低めに抑えるのがコツですね。あとはアイディア次第で。

5
6
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
6