Canvasで実現するカラフルな円が小さくなったり大きくなったりする背景

Canvas

ハイきました。待望のCanvasです。イロイロ頑張って動かしてみました。お手製の雑なイージング付きです。分かりやすいよう多少ウザ目に作っていますが、調整したら普通のページに組み込んでもイケるかも。結構重いですけどね。。。

自分ならCanvasで何をしたいかと考えたすえに、Flashの様なリッチ感をだしたいと思いたちこの内容にしました。いろんなサイトで見るCanvasに比べたらマダマダですが、どうぞご覧アレ。

Demo

※新バージョンを公開していますのでよろしければCanvasで実現するカラフルな円が小さくなったり大きくなったりする背景2をご覧下さい。

必要なファイル

対応ブラウザ

  • Google Chrome
  • Safari3~
  • Firefox2~
  • Opera10.6

※Windowsのみの確認です。

IEも頑張ればちゃんと表示できそうですが、どのみち処理が重いので除外しました。

コーディング&設定

HTML

HTMLヘッダー内でjquery.jsを読み込む。

<script src="jquery.js" type="text/javascript"></script>

bodyの直下に背景の要素(Canvas)とコンテンツの要素を用意する。以下の場合は#canvasbg#contentsになる。

<body>
	<div id="canvasbg">
		<canvas id="canvas"></canvas>
	</div>
	<div id="contents">
		<p>テキストテキストテキストテキストテキスト</P>
	</div>
</body>

※デモページのHTMLはテンプレートを崩さないよう記述を変更しています。

CSS

以下のCSSは基本的にCanvasを背景にする為の設定です。ただし、JavaScriptも使用して対応している為、下記CSSのみではCanvasを背景に出来ません。

html {
	height: 100%;
}
body {
	min-height: 100%;
	overflow: auto;
	position:relative;
	z-index: 1;
}
#canvasbg {
	height: auto;
	width: 100%;
	height:100%;
	min-height:100%;
	overflow: auto;
	position: fixed;
	z-index: 1;
}
#canvasbg canvas {
	position: fixed;
	z-index: 1;
}
#contents {
	width: 600px;
	margin: 20px auto;
	position: relative;
	z-index: 2;
}

※デモページのCSSはテンプレートを崩さないよう記述を変更しています。

※2012/4/7 コンテンツの高さがブラウザの表示領域より小さい場合に背景が切れていましたので、上記CSSを修正しました。

JavaScript

以下のスクリプトを記述。

$(function(){

	//変数宣言
	var Canvas = $("#canvas"),
	CanvasBg = $("#canvasbg"),
	alpha = 0.2, //透明度
	locArray = 100, //位置の配列数
	sizeArray = 100, //サイズの配列数
	colorArray = 600, //カラーの配列数
	speed = 50, //アニメーション速度
	canvasWidth,
	canvasHeight,
	locNum,
	sizeNum,
	colorNum,
	colorR,
	colorG,
	colorB,
	ctx,
	loc,
	nowSize;
	
	//配列作成
	randomLoc = new Array();
	randomSize = new Array();
	randomSizeInitial = new Array();
	randomColor = new Array();
	sizeValue = new Array();
	easing = new Array();

	//ランダム値作成関数
	function random(num,min){ //minは最小値、num+minは最大値
		randomNum = Math.floor(Math.random()*num)+min;
		return randomNum;
	}

	//配列追加
	for(var i=0; i<locArray; i++){
		randomLoc.push(random(50,50));
	}
	for(var i=0; i<sizeArray; i++){
		randomSize.push(random(90,10));
	}
	for(var i=0; i<colorArray; i++){
		randomColor.push(random(255,0));
	}
	for(var i=0; i<sizeArray; i++){
		sizeValue.push(1);
	}
	for(var i=0; i<randomSize.length; i++){
		randomSizeInitial[i] = randomSize[i];
	}
	for(var i=0; i<4; i++){
		easing.push(i+2);
	}

	//カラー設定関数
	function color(){
		 return "rgba("+colorR+","+colorG+","+colorB+","+alpha+")";
	}

	//サイズパーセンテージ設定関数
	function sizeRatio(num,ratio){
		return randomSizeInitial[num]/100*ratio;
	}

	//Canvas表示関数
	function init(){
		var canvas = document.getElementById("canvas");
		if (canvas.getContext){
			ctx = canvas.getContext("2d");
			setInterval(draw, speed); //draw関数を繰り返す
		}
	}

	//Canvas表示内容
	function draw(){

		//Canvasを#canvasbg(背景と同じサイズ)と同じサイズにする
		Canvas.attr({height:CanvasBg.height()}).attr({width:CanvasBg.width()});

		canvasWidth = Canvas.width();
		canvasHeight = Canvas.height();

		//Canvasをクリア
		ctx.clearRect(0,0,canvasWidth,canvasHeight);

		//円の重なり部分の描写を設定
		ctx.globalCompositeOperation = "lighter";

		//変数を0に設定
		locNum = 0;
		sizeNum = 0;
		colorNum = 0;

		//ランダムに円を作成
		for(var i=0; i<canvasWidth; i+=loc){
			for(var j=0; j<canvasWidth; j+=loc){
				loc = randomLoc[locNum++];
				if(locNum>randomLoc.length-1){
					locNum = 0;
				}
				size = randomSize[sizeNum++];
				if(sizeNum>randomSize.length-1){
					sizeNum = 0;
				}
				colorR = randomColor[colorNum++];
				colorG = randomColor[colorNum++];
				colorB = randomColor[colorNum++];
				if(colorNum>randomColor.length-1){
					colorNum = 0;
				}
				ctx.beginPath();
				ctx.fillStyle = color();
				ctx.arc(j, i, size, 0, Math.PI*2, true);
				ctx.fill();
			}
		}

		//サイズ配列の数値を変更(アニメーション設定)
		for(var i=0; i<randomSize.length; i++){

			nowSize = randomSize[i];

			//イージング設定
			if(nowSize<sizeRatio(i,90) && nowSize>sizeRatio(i,10)){
				sizeValue[i] *= easing[0];
			} else
			if(nowSize<sizeRatio(i,80) && nowSize>sizeRatio(i,20)){
				sizeValue[i] *= easing[1];
			} else
			if(nowSize<sizeRatio(i,70) && nowSize>sizeRatio(i,30)){
				sizeValue[i] *= easing[2];
			} else
			if(nowSize<sizeRatio(i,60) && nowSize>sizeRatio(i,40)){
				sizeValue[i] *= easing[3];
			}

			//サイズが0もしくは初期値になったら縮小拡大を反転する
			if(nowSize>randomSizeInitial[i] || nowSize<1){
				sizeValue[i] *= -1;
			}

			//縮小拡大の値を計算
			randomSize[i]-=sizeValue[i];

			//イージング用に変更したsizeValueの値をリセット
			switch(sizeValue[i]){
				case easing[0]:
				case -easing[0]:
					sizeValue[i] /= easing[0];
					break;
				case easing[1]:
				case -easing[1]:
					sizeValue[i] /= easing[1];
					break;
				case easing[2]:
				case -easing[2]:
					sizeValue[i] /= easing[2];
					break;
				case easing[3]:
				case -easing[3]:
					sizeValue[i] /= easing[3];
					break;
			}

		}

	}

	//Canvas表示
	init();

});

解説

Canvasは一度描写したものを消して再描写することによりアニメーションする為、ランダム値を毎回取得すると再描写ごとに違った表示になってしまいます。ですので、先にグローバルな配列としてランダム値を用意しておいて、再描写の度に同じ値を参照するようにする。そして、アニメーションさせる要素(今回はサイズ)の配列を再描写の際に変更することでアニメーションすることが出来ます。

かなり重くなってしまいましたが、円の数や再描写の速度を調整することで多少は軽くなります。

参考サイト

あとがき

折角だし?Canvasもやってみよう。って感じで作ってみましたが、面白いですねCanvas。お陰様で結構勉強になりました。CanvasってゆうよりJavaScriptの。ランダム値やらswitch文やら初めて使うものもチラホラとありましてね。最終的に想像通りに動作したので嬉しかったです。

ちなみに前の記事から1ヶ月ほども経っていました。なかなか記事の内容が思い浮かばなかったもので。今回の内容も記事にするつもりで作った訳ではなかったんですが、丁度いいやって思って載せました。思ったよりチャント出来たので。まー今後もこんな感じでダラダラと更新します。

Top