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

Canvas

以前作ったCanvasで実現するカラフルな円が小さくなったり大きくなったりする背景の別バージョンを作ってみました。ソースを改良しようと思い作りましたが、ついでなのでちょっと違ったヤツをと思いまして。

動きとしての大きな変更点は軌跡を残してポワってさせたのと、イージングを数学関数でちゃんとしたもの?にしました。あとソースを改良した割にはこれといって軽くなった訳ではありませんのであしからず。(いやね、本当は軽くするつもりだったんだよ。でもね、僕の力じゃこれがゴニョゴニョ。)

Demo

必要なファイル

対応ブラウザ

  • Google Chrome
  • Safari3~
  • Firefox2~
  • Opera11

※Windowsのみの確認です。

IE7、8はアニメーションせずに1回のみ描写するようにしています。何故かって?尋常じゃないくらい重いからに決まってるでしょ。

コーディング&設定

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>

CSS

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

html {
	height: 100%;
}
body {
	min-height: 100%;
	background-color: #000000;
	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;
	background-color: rgba(0,0,0,0.7);
	-webkit-border-radius: 10px;
	-moz-border-radius: 10px;
	border-radius: 10px;
	margin: 20px auto;
	position: relative;
	z-index: 2;
}
#contents p {
	color: #ffffff;
}

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

JavaScript

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

(function($){

	$(function(){

		//変数宣言
		var canvasElm = $("#canvas");
		var canvasBg = $("#canvasbg");
		var alpha = 0.1;				//透明度
		var locArray = 100;				//位置の配列数
		var sizeArray = 100;			//サイズの配列数
		var colorArray = 600;			//カラーの配列数
		var speed = 50;					//アニメーション速度
		var colorLen = colorArray-2;
		var sizeLen = sizeArray-2;
		var locLen = locArray-2;
		var canvasWidth, canvasHeight;
		var ctx;
		var sizeNum = 0;
		var colorNum = 0;

		//配列作成
		randomLoc = [];
		randomSize = [];
		randomSizeInitial = [];
		randomColor = [];
		color = [];
		vector = [];

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

		//配列追加
		for(var i=0; i<locArray; i++){
			randomLoc.push(random(50, 50));
		}
		for(var i=0; i<sizeArray; i++){
			randomSize.push(random(70, 30));
		}
		for(var i=0; i<colorArray; i++){
			randomColor.push(random(255, 0));
		}
		for(var i=0; i<sizeArray; i++){
			vector.push(1);
		}
		for(var i=0, len=randomSize.length; i<len; i++){
			randomSizeInitial[i] = randomSize[i];
		}

		//Canvasサイズ取得関数
		function canvasSize(){
			canvasElm.attr("width", canvasBg.width()).attr("height", canvasBg.height());
			canvasWidth = canvasElm.width();
			canvasHeight = canvasElm.height();
		}

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

		//カラー取得関数
		function getColor(){
			for(var i=0; i<3; i++){
				color[i] = randomColor[colorNum];
				colorNum++;
				if(colorNum>colorLen){
					colorNum = 0;
				}
			}
			return "rgba("+color[0]+","+color[1]+","+color[2]+","+alpha+")";
		}

		//サイズ取得関数
		function getSize(){
			if(sizeNum>sizeLen){
				sizeNum = 0;
			}
			var size = randomSize[sizeNum];
			sizeNum++;
			return size;
		}

		//円表示コンストラクタ関数
		function Round(a_color, a_x, a_y, a_size){
			this.color = a_color;
			this.x = a_x;
			this.y = a_y;
			this.size = a_size;
		}

		//円表示メソッド
		Round.prototype.view = function(){
			ctx.fillStyle = this.color;
			ctx.beginPath();
			ctx.arc(this.x, this.y, this.size, 0, Math.PI*2, true);
			ctx.closePath();
			ctx.fill();
			locNum++;
			roundNum++;
		}

		//canvas表示内容関数
		function draw(){

			//Canvasに透明度のある背景色を重ねて徐々に消していく
			ctx.globalCompositeOperation = "source-over";
			ctx.beginPath();
			ctx.fillStyle = "rgba(0,0,0,0.1)";
			ctx.fillRect(0, 0, canvasWidth, canvasHeight);

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

			//変数初期化
			sizeNum = 0;
			colorNum = 0;
			locNum = 0;
			roundNum = 0;
			var locX = 0; 
			var locY = 0;

			//配列作成
			roundPool = [];

			//関数キャッシュ
			var f_getColor = getColor;
			var f_getSize = getSize;
			var f_Round = Round;

			//ランダムに円を作成
			for(var i=0, len=canvasHeight; i<len; i+=loc){
				for(var j=0, len=canvasWidth; j<len; j+=loc){
					var loc = randomLoc[locNum];
					if(locNum>locLen){
						locNum = 0;
					}
					roundPool[roundNum] = new f_Round(f_getColor(), loc*locX, loc*locY, f_getSize());
					roundPool[roundNum].view();
					locX++;
				}
				locX = 0;
				locY++;
			}

			//サイズ配列の数値を変更(アニメーション設定)
			for(var i=0, len=sizeArray; i<len; i++){
				var nowSize = randomSize[i]-1;
				var maxSize = randomSizeInitial[i];
				var easing = Math.floor(Math.pow(nowSize-(maxSize/2), 2)/(-Math.pow(maxSize, 2)/12)+4); //イージング設定
				if(nowSize>maxSize-1 || nowSize<2){ //サイズが0もしくは初期値になったら縮小拡大を反転する
					vector[i]*=-1;
				}
				randomSize[i]-=easing*=vector[i]; //次回描写の円のサイズを設定
			}

		}

		//Canvas表示
		$(window).bind("load",function(){
			canvasSize();
			init();
		})
		.bind("resize",function(){ //ウィンドウリサイズ時にCanvasのサイズを変更
			canvasSize();
		});

	});

})(jQuery);

ちょこっと説明

軌跡を残すには、Canvasを再描写する際に先程の描写を消すのではなく、透明度のある背景色を重ねていき徐々に消していくことで実現できます。

あとがき

イージングの数学関数を作るために8年ぶりくらいに2次関数を勉強しました。正直、正確な答えが出なかったので、取り敢えずJavaScriptに組み込んで勘で計算式を入れていくと・・・なんと奇跡的に出来ました。もう感無量です。

また数学関数を使わないといけない日(今回は別に必要に迫られた訳ではないけど)が来ることを考えて勉強すべきなだろうか数学を。

Comment

BB

Canvasでこれだけの表示をすると思いかと、思いきやいい感じで表示されますね。
環境IE9で表示落ちは感じません。

Syuji

BBさん。

さすがにデカイ画面にイッパイにすると重たくはなります。実験的なものなので円の数を多めにしていますので、そのあたりを調整したら使えなくはないかな~って感じですね。

Top