Hatena::ブログ(Diary)

Webと文字

よければ、はてブしてください。( ´∀`) George.Nagaoka@gmail.com

JavaScript IME:海外からブラウザで日本語を変換 新URL 旧URL:
多言語入力ブックマークレット:ブラウザでロシア語、中国語、アラビア語・・・
【軍曹が】携帯電話開発の現状【語る】をAA化した
AAのデータベース
趣味のページ

2010-04-13

Canvasに色々描いてみた

canvas要素

 HTMLの仕様に図形を描くことができるcanvas要素というものがあります(参考資料1)。JavaScriptとの親和性がとってもいいのが特徴なのです。ここに色々描いて現実逃避してみます。

画面ぴったりに

 どうでもいいことなのですが、canvasの大きさを画面ぴったりにします。bodyのマージンとパディングを0にすることが必要です。以下のコードはjQueryが必要です。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
<title></title>
<script language="javascript" type="text/javascript" src="jquery-1.4.2.min.js">
</script>
<script language="javascript" type="text/javascript" src="init.js">
</script>
</head>
<body id="body1" onload="init();">
</body>
</html>
function init(){
	var c=canvasHWSet();
}

function canvasHWSet(){
	$(document.body).css({"margin":0,"padding":0});//重要!
	var width = $(document.body).width();
	var height = $(window).height();
	var canvas = $("<canvas id='canvas2'><canvas>").css({
		"cursor":"pointer"
	});
	canvas.attr("width",width);
	canvas.attr("height",height);

	$(document.body).append(canvas);
	return [canvas,width,height];
};

ベクトルクラス

 ベクトルクラスを定義して、描画メソッドを追加します。これで簡単にベクトルを描くことができます。x0,y0からx1,y1に向かう定義です。drawメソッドはコンテキスト引数に取り、それに対して自身を描画します。

function Vector() {
    this.initialize.apply(this, arguments);
}
Vector.prototype = {
	initialize:function(x0,y0,x1,y1){
		this._x0 = x0;
		this._y0 = y0;
		this._x1 = x1;
		this._y1 = y1;
	},
	_x0:0,
	_y0:0,
	_x1:0,
	_y1:0,
	draw:function(context){
		context.beginPath();
		context.lineWidth =1;
		context.moveTo(this._x0,this._y0);
		context.lineTo(this._x1,this._y1);
		context.stroke();
	},
	clone:function(){
		var v = new Vector(this._x0,this._y0,this._x1,this._y1);
		return v;
	}
}

function init(){
	var c=canvasHWSet();
	var context = c[0].get(0).getContext("2d");
	var nv = new Vector(100,100,200,200);
	nv.draw(context);

ベクトルの向きを変える

 あるベクトルを角度θだけ向きを変えるには回転の概念を使います。詳しくは参考資料3を見てください。あるベクトルXの終点から角度θだけ回転させた同じ大きさのベクトルYを得るには、Xを原点に持って行き、そこから回転をかけて、それをXの終点に持っていくという操作をします。なぜこんな面倒な関数が必要なのかは後でわかります。

//このメソッドは今のベクトルに角度deg[°]だけ回転させ、さらにその始点を今のベクトルの終点からにしたベクトルをnewして返す。
Vector.prototype = {
	newFromEndPointRotate:function(deg){
		var rad = 0.0174532925 * deg;//degreeをradianに変換する
		var xx = this._x1 -this._x0;
		var yy = this._y1 -this._y0;
		var x = xx * Math.cos(rad) - yy * Math.sin(rad);
		var y = xx * Math.sin(rad) + yy * Math.cos(rad);
		return (new Vector(this._x1 , this._y1,this._x1 + x,this._y1 + y));
	}
}

L-system

 今回はcanvasフラクタル図形を描いてみます。フラクタル図形を簡単に描くためにL-systemと呼ばれる仕組みを利用します。以下にwikipedia(参考資料2)の例を挙げます。

例 2:フィボナッチ数列

  V : A, B

  S : なし

  初期値: A

  規則 : (A → B), (B → AB)

計算を進めると、以下のような文字列となる。

  n = 0 : A

  n = 1 : B

  n = 2 : AB

  n = 3 : BAB

  n = 4 : ABBAB

  n = 5 : BABABBAB

この文字列の各文字数を n=0 から順に数えると、フィボナッチ数列(1 1 2 3 5 8 13 21 34 55 89 …)となっている。

 要は文字列の置換えの繰り返しです。ただし、規則は同時に適用させることに注意してください。単純にreplaceしてはいけません。以下の関数wikipediaのコッホ曲線の規則を参考にして作成したものです。初期値と回数を引数にとり、返値として置き換え後の文字列を返します。

function makeKochCurve(n,omega){
	var text=omega;
	for(var i=0;i<n;i++){
		var buff="";
		for(var j=0;j<text.length;j++){
			switch(text.charAt(j)){
			case "F":
				buff +="F+F-F-F+F";break;
			case "-":
			case "+":
				buff +=text.charAt(j);
			}
		}
		text = buff;
	}
	return text;
}

コッホ曲線を描く

 wikipediaを参考にしてコッホ曲線を描いてみます。文字列の置き換えは先程作成しました。次はこの文字列を図形に置き換える必要があります。文字列の中の+と−は現在のベクトルから90°または-90°回転させる命令です。これらを簡単に行うのがベクトルクラスのnewFromEndPointRotateメソッドです。これによって現在のベクトルから簡単に回転したベクトルを得ることができます。

function onClick(event){
	var context =  event.data.c[0].get(0).getContext("2d");
	var test =makeKochCurve(3,"F");
	var cv = false; //current vector
	var ca =false; //current angle

	for(var i=0;i<test.length;i++){
		switch(test.charAt(i)){
		case "F":
			if(!cv){
				//Y軸は下に向かって正。なのでそのままだと下向きなる。よって図形を上下反転させるためにマイナスである。
				cv = new Vector(event.pageX,event.pageY,event.pageX -10,event.pageY);
				cv.draw(context);
			}else{
				cv = cv.newFromEndPointRotate(ca);
				cv.draw(context);
			}
			ca = 0;
			break;
		case "-":ca -= 90;break;
		case "+":ca +=  90;break;
		}
	}
}

サンプル:クリックした場所から図形を描きます(FireFoxのみ確認)

=>http://www28095u.sakura.ne.jp/lsystem/makeKochCurve/

シェルピンスキーの三角形を描く

 setInterval関数を利用して、1ベクトルづつ描いていくのを眺めてみます。

	var timeID = setInterval(function(){
		if(test.length < i) clearInterval(timeID);
		switch(test.charAt(i)){
		case "A":
		case "B":
			if(!cv){
				cv = new Vector(event.pageX,event.pageY,event.pageX -5,event.pageY);
				cv.draw(context);
			}else{
				cv = cv.newFromEndPointRotate(ca);
				cv.draw(context);
			}
			ca=0;
			break;
		case "-":ca =ca -60;break;
		case "+":ca =ca+  60;break;
		}
		i++;
	},1);

サンプル:クリックした場所から図形を描きます(FireFoxのみ確認)

=>http://www28095u.sakura.ne.jp/lsystem/makeSierpinskiGasket/

Fractal plantを描いてみる

 英語版のwikipediaに載っています。特徴的なのは今までと違って[と]の二つの記号が出てきている点です。それぞれその時の値と角度を「保存する」のとそれを「読み出す」のになります。これは丁度スタックの考え方です。arrayに用意されているpushとpopメソッドを利用して簡単に実装できます。また、Fのみが描画命令で、Xは含まないことに注意して下さい。

	var cv = false; //current vector
	var ca =false; //current angle
	var stack =[];//stack

	var i=0;
	var timeID = setInterval(function(){
		if(test.length < i) clearInterval(timeID);
		switch(test.charAt(i)){
		case "F":
			if(!cv){
				cv = new Vector(event.pageX,event.pageY,event.pageX -5,event.pageY);
				cv.draw(context);
			}else{
				cv = cv.newFromEndPointRotate(ca);
				cv.draw(context);
			}
			ca = 0;
			break;
		case "[":
			stack.push([cv.clone(),ca]);
			break;
		case "]":
			var c = stack.pop();
			cv = c[0];
			ca = c[1];
			break;

		case "-":ca -= 25;break;
		case "+":ca +=  25;break;
		}
		i++;
	},1);

サンプル:クリックした場所から図形を描きます(FireFoxのみ確認)

=>http://www28095u.sakura.ne.jp/lsystem/makeFractalPlant/

終わり

      ._
       \ヽ, ,、
        `''|/ノ
         .|
     _   |
     \`ヽ、|
      \, V
         `L,,_
         |ヽ、)  ,、
        /    ヽYノ
       /    r''ヽ、.|
      |     `ー-ヽ|ヮ
      |       `|
      |.        |
      ヽ、      |
        ヽ____ノ


┼ヽ  -|r‐、. レ |
d⌒) ./| _ノ  __ノ

参考資料

  1. Canvas - MDC
  2. L-system - Wikipedia
  3. シューティングゲームと二次元ベクトル

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/project_the_tower2/20100413/1271180521
Connection: close