2018秋の無料相談会
2018秋の無料相談会
2018.09.11
#161
それいけ!フロントエンド

CANVASでドキドキする「アルファマスクアニメーション」を作ろう!

しんどうドリル

はじめまして、フロントエンドエンジニアのドリルです。今年の3月に入社いたしました。

「ドリル」というあだ名には、「深く掘り続ける、探求する」という意味があります(名付け親はLIGのデザイナー、藤田さんです)。今後はLIGブログでもさまざまなトピックを掘り下げて書いていきたいと思うので、どうぞよろしくお願いいたします!

さて今回は、CANVASでアルファマスクアニメーションを作る方法をご紹介します。

今回のゴール

こちらが完成形です。スポットライトを当てたような表現など、アニメーション表現に応用できます。ちなみにIE11対応です!

See the Pen CANVAS – ALPHA MASK by Sho Shindo (@kabukimono) on CodePen.

何かドキドキする動きですね。まさかツインテールだったとは。

用意するもの

2つの画像を準備します。

背景jpg画像(今回は400×250)

任意のjpg画像。今回はフロントエンドユニットのメンバー、はっちゃんさんの写真を用意しました。画像提供ありがとうございます。

マスク用png画像(今回は200×200)

境界線にアルファを含んだもの。Photoshopのフィルター、ぼかし(ガウス)で作成。
※作成方法の詳細は本題と外れてしまうので、割愛させていただきます。
マスク用画像

マスクをつくる

それではさっそくマスクを作ってみましょう。

HTML

<canvas id="js-canvas"></canvas>

JAVASCRIPT

// canvas要素を取得
var $canvas = document.querySelector('#js-canvas');

// 2Dコンテキストを取得
var ctx = $canvas.getContext('2d');

// canvasのサイズを指定
var canvasWidth = 400;
var canvasHeight = 250;
$canvas.width = canvasWidth;
$canvas.height = canvasHeight;

// マスクの画像
var mask = new Image();
mask.src = 'https://dl.dropbox.com/s/v470auaxuwnm4vc/mask.png';

// 背景の画像
var bg = new Image();
bg.src = 'https://dl.dropbox.com/s/83i4xh1ftnplzve/hatsushi.jpg';
// (※今回はDropboxから画像を読み込んでます)

// マスクの大きさの初期値
var expandVal = 200;

window.onload = function() {
	// 背景の画像
	ctx.drawImage(bg, 0, 0, canvasWidth, canvasHeight);

	// 合成方法の指定
	ctx.globalCompositeOperation = 'destination-in';

	// マスクの画像
	ctx.drawImage(mask, canvasWidth/2 - expandVal/2, canvasHeight/2 - expandVal/2, expandVal, expandVal);
}

結果

アルファチャンネルマスク

ここで重要なプロパティはglobalCompositeOperation(参照: HTML5.JP)です。こちらは図形や画像の処理方法を決めるプロパティになります。

CanvasRenderingContext2D.globalCompositeOperationプロパティは、新たな図形を描くときに適用する合成処理の種類を定めます。種類は文字列で、合成やブレンドモードのいずれが用いられるのかを決めます。
(引用元:MDN web docs

今回はdestination-inという画像と画像が重なった部分だけ描画するプロパティを使用しています。

さて、続いてマスクを動かしてみましょう。

マスクを動かす

// canvas要素を取得
var $canvas = document.querySelector('#js-canvas');

// 2Dコンテキストを取得
var ctx = $canvas.getContext('2d');

// canvasのサイズを指定
var canvasWidth = 400;
var canvasHeight = 250;
$canvas.width = canvasWidth;
$canvas.height = canvasHeight;

// マスクの画像
var mask = new Image();
mask.src = 'https://dl.dropbox.com/s/v470auaxuwnm4vc/mask.png';

// 背景の画像
var bg = new Image();
bg.src = 'https://dl.dropbox.com/s/83i4xh1ftnplzve/hatsushi.jpg';
// (※今回はDropboxから画像を読み込んでます)

// マスクの大きさの初期値
var expandVal = 200;

// 繰り返しの処理
function render() {
	// 現在の描画状態を保存
	ctx.save();

	// 背景の画像
	ctx.drawImage(bg, 0, 0, canvasWidth, canvasHeight);

	// 合成方法の指定
	ctx.globalCompositeOperation = 'destination-in';

	// マスクの画像
	ctx.drawImage(mask, canvasWidth/2 - expandVal/2, canvasHeight/2 - expandVal/2, expandVal, expandVal);

	// save(); 時点での描画状態を復元
	ctx.restore();

	// マスクを大きくする
	expandVal++;
	if (expandVal > canvasWidth) {
		// 0にするとマスクがかからない
		expandVal = 1;
	}

	requestAnimationFrame(render);
}

window.onload = function() {
	render();
}

ここで重要なプロパティはsave, restore(参照:HTML5.JP)です。

saveで描画前の状態を保存し、restoreで復元しています。この処理をしないと、globalCompositeOperationがすべての画像に適用され、正しく描画されなくなるのでご注意ください!

それでは最後に背景を黒にしましょう。

背景を黒くする

HTML

<div class="canvas__wrap">
	<canvas id="js-canvas"></canvas>
</div>

CSS

.canvas__wrap {
	width: 100%;
	background: #000;
}

上記の処理を行えば完成です!

完成したアニメーション

最後にもう一度。

See the Pen CANVAS – ALPHA MASK by Sho Shindo (@kabukimono) on CodePen.


やっぱりドキドキしますね……。

まとめ

いかがでしたか? 簡単なコードでしたが、何かに応用していただけたら幸いです。

CANVASですのでIE11でも動くかと思います。応用例としては、TweenMaxやTween.jsなどでイージングをつけたり、マスクを色々な形状にしてみるのも面白いかもしれません。いろいろと試してみてくださいね。

それでは、ドリルでした!