canvasでキラキラした背景を作る方法

tech.kayac.com、ささやかにリニューアルしました!

tech.kayac.comをご覧の皆さん、はじめまして。意匠部ME課のfuchigamiといいます。
どうして技術部ブログに意匠部の野郎が?って感じですが、
技術部ブログのリニューアル記念ということで、ちゃっかりcanvasについて記事を書こうと思います。

最初なので、、、

簡単にぼくの属性を説明すると、html5とか好き、CSS3とか好き、canvasとか興味ある、非モテ、javascriptはjQueryがなんとなくわかる程度、非リア充。こんな感じです。
今回のリニューアルではコーディング全般を担当しました。

特に、プログラミングに関してはド素人だ!ということを強調しておきます。

そんなぼくが、canvasを使ってキラキラした背景を作ってみました

「リニューアルするからには新しいことがやりたいよね。だったらhtml5とcss3だろう。せっかくだからcanvas使いたい。」という自然な流れのもと、これはチャンスだ!と、前々から温めていた「canvasを背景に使う」ネタをやろうと思いました。

そうなんです、実はこのブログの背景、canvasで表示しています。

あれ、canvasってなんだっけ??

canvasはhtml5から追加された要素で、javascriptから図形などの描画ができます。
つい先日も当ブログで取り上げられましたね。雰囲気としてはprocessingに近いかな?といった感じです。
今更聞けないcanvasの基礎の基礎

ピンとこない人もいるかもしれませんが、実際に見てみると
その可能性にドキドキしちゃうはずです。
この有名なcanvasのデモ、超カッコいいですね。
HTML5 Canvas and Audio Experiment

ということで、canvasを使ってみた経験を踏まえて、この背景の作り方を書きたいと思います。

canvasを背景にします。

では実際に書きながら作っていきたいと思います。

htmlとcssを書く

まずはcanvasタグをhtmlに配置してみましょう。ウインドウサイズいっぱいにするために、divで囲っておきます。

これだけだと、canvasは 300px × 150px のただの長方形ですね。
とりあえず、#wrapperを画面全体に広げて固定配置にしましょう。

html{
	min-height: 100%;
	overflow: auto;
	position:relative;
	z-index: 1;
	background: #000;
}

body{
	min-height: 100%;
	margin: 0;
	padding: 0;
	overflow: auto;
	position: relative;
	z-index: 1;
}

body > #wrapper{
	height: auto;
	overflow: auto;
	position: fixed;
	z-index: 1;
	width: 100%;
	height:100%;
	min-height:100%;
}

canvas{
	z-index: 1;
	position: fixed;
}

余計なスタイルが混じっているかもしれませんが、とりあえずこれで#wrapperが全画面かつ固定配置になったはずです

canvasのサイズを決めよう

canvasにはサイズの指定方法が2種類あります。

  • canvasタグのwidth属性・height属性で指定
  • cssで幅と高さを指定

なんとなくCSSでサイズを指定したくなります。ですが、CSSでサイズを決めると問題がありました。なんと、単純に引き延ばされるだけで、canavsの実際の大きさは変わってないみたいなんです。imgタグにサイズcssでサイズ指定するような感じです。
なので、ここはwidth属性とheight属性にサイズを指定することにします。(cssでサイズ指定できる方法があったら教えてください!)

しかし、再び問題発生。

width="100%" height="100%"としても、100px×100pxのcanvasが表示されてしまいます。
どうやら、canvasの高さと幅は%で指定しても単位が無視されてしまうみたいですね。

javascriptの力を借りてみる

どうやらhtmlとcssだけではcanvasを背景にできないぞ。そう悟ったぼくはjavascriptでサイズを指定することにしました。雰囲気JSer渕上の誕生です。
イメージ的には、div#wrapperのサイズを取得して、canvasのwidth属性・height属性に指定する、というもの。
以下のように書いてみると上手くいきました。
きっともっとスマートに書けるはずですが、深いことは考えずに行きましょう。

function sizing(){
	$("#canv").attr({height:$("#wrapper").height()});
	$("#canv").attr({width:$("#wrapper").width()});
}

これでcanvasをウインドウサイズにして固定配置にすることができました。

続いて、キラキラした光を描いていきます

canvasを背景のように配置することができたので、次にcanvasの内側を作っていきます。

まずは基礎の基礎を。

何事も基礎が大事です。そうです、あのエントリーをじっくりよんで勉強しましょう。
今更聞けないcanvasの基礎の基礎
nagataくん、ありがとう!

本当によく書けた記事ですね。基礎が理解できたところで、光を描画する仕組みを考えてみたいと思います。

いかにして光を表現するか

結論から言うと、以下の手順で光っぽい表現を実現しています。

  1. ランダムな場所に、ランダムな半径の、ランダムな色の、円を複数描く
  2. 円の中心から外周に向かって透明度のグラデーションをかける。→ぼかし
  3. 円の色をglobalCompositeOperation = "lighter";でブレンドする
    →photoshopでいうところの「覆い焼き(リニア)-加算」に近い感じ

photoshopで画像を作るときと、基本的には同じ考え方ですね。

canvasで再現しよう

それではこれをcanvasで再現してみましょう。再び雰囲気JSer渕上の登場です。

円を描く準備

	var star = new Array(10); //円の情報を格納する配列を作る
	for( i=0; i<star.length; i++ ){
		star[i] = new Array(7);
		star[i][0] = Math.random()*canvas.width;	 // x座標をランダムに決める
		star[i][1] = Math.random()*canvas.height;  // y座標をランダムに決める
		star[i][2] = Math.random()*canvas.width/3 + canvas.width/14;	// 半径rをランダムに決める
		var r = Math.random()*255;	// R 円の色を決める
		var g = Math.random()*255;	// G
		var b = Math.random()*255;	// B
		r = Math.ceil(r);
		g = Math.ceil(g);
		b = Math.ceil(b);
		star[i][4] = r;		//r
		star[i][5] = g;		//g
		star[i][6] = b;		//b
	}

なんとなく配列とか使えばいいんじゃないの、というド素人感丸出しですが、要するに円の情報をランダムに決めています。

グラデーションをかけて、円を描画する

var draw = function draw(){
	
	//reset
	ctx.globalCompositeOperation = "source-over";
	ctx.fillStyle = "rgba(0, 0, 0, 1)";
	ctx.fillRect(0, 0, canvas.width, canvas.height);
	
	ctx.globalCompositeOperation = "lighter";
	
	//point
	for(i=0; i<star.length; i++){
		ctx.beginPath();
		var edgecolor1 = "rgba(" + star[i][4] + "," + star[i][5] + "," + star[i][6] + ",0.93)";
		var edgecolor2 = "rgba(" + star[i][4] + "," + star[i][5] + "," + star[i][6] + ",0.6)";
		var edgecolor3 = "rgba(" + star[i][4] + "," + star[i][5] + "," + star[i][6] + ",0.1)";
		var edgecolor4 = "rgba(" + star[i][4] + "," + star[i][5] + "," + star[i][6] + ",0)";
		var gradblur = ctx.createRadialGradient(star[i][0], star[i][1], 0, star[i][0], star[i][1], star[i][2]);
		gradblur.addColorStop(0,edgecolor1);
		gradblur.addColorStop(0.4,edgecolor1);
		gradblur.addColorStop(0.7,edgecolor2);
		gradblur.addColorStop(0.9,edgecolor3);
		gradblur.addColorStop(1,edgecolor4);
		ctx.fillStyle = gradblur;
		ctx.arc(star[i][0], star[i][1], star[i][2], 0, Math.PI*2, false);
		ctx.fill();
	}
};

なんとなくforとか使って円をいっぱい書いています。ふたたびド素人感丸出しですね。
だれかぼくにプログラミングを教えてください。
グラデーションの指定がやたらと細かくなっているのは、ちょうどいいぼかし具合をさぐった結果です。
canvasにブラーフィルターが実装されたらうれしいんですが、どうなんでしょうか。

以上のようなスクリプトを書いた結果、この背景のようなキラキラした光が表現できました。

光っぽく見せるポイント

  1. 色のブレンド方法を指定

    globalCompositeOperation = "lighter"
    この指定こそがキモです。

  2. 円のエッジをぼかす(ぼかしている風に見せる)

    グラデーションを使って円のエッジをぼかしているように見せます。
    色を rgba(100,100,100,0.5) のようにrgba指定することでアルファのグラデーションをかけることができます。

おわり

以上、ざっくりとでしたが、このブログの背景の作り方をまとめてみました。
canvasっていろんな可能性があるんだな?と思っていただければ幸いです!

カヤックでは変態な技術者・マークアップエンジニアを募集しています!