HTML5のCanvasに黄金螺旋を描く

HTML5のCanvasに黄金螺旋を描く

今回は、HTML5のCanvasに、黄金螺旋を描きます。巻き貝などに見られる美しいらせん構造です。

HTML5のCanvasに黄金螺旋を描く : デモ

HTML5のCanvasに黄金螺旋を描く : ZIPファイル(5kb)

HTML5のCanvasに黄金螺旋を描くための参考図

1.HTML

<!doctype html> <!-- 標準モードでWebページをレンダリング -->
<html lang="ja"> <!-- 言語指定付きのhtml要素 -->
	<head> <!-- ヘッダーの指定 HTMLページの生成に必要な情報を記述 -->
		<meta charset="UTF-8"> <!-- Web上の文字エンコーディングの指定 -->
		<title>HTML5のCanvasに黄金螺旋を描く</title> <!-- ブラウザの上部ウィンドウのバーに表示されるタイトル -->
        <link href="css/base.css" rel="stylesheet" type="text/css"> <!-- cssファイル(デザインの仕様)の読み込み -->
		<script src="js/base.js"></script> <!-- JavaScriptファイル(制御の仕様)の読み込み -->
	</head>

    <body> <!-- HTMLページのメインコンテンツを示す要素 -->
        <canvas id = "viewArea" width = "275" height = "275"></canvas> <!-- 描画領域 -->
    </body>
</html>

2.CSS

@charset "UTF-8";

body /* bodyのデザイン */
{
	margin:0; /* borderより外側の余白は0 */
	padding:0; /* borderより内側の余白は0 */
	background-color: #fff; /* 背景色は白 */ 
	-webkit-transform:translateZ(0px); /* GPUの機能を使う */
}

#viewArea /* id名「viewArea」が付いたCanvas要素(タグ)のデザイン */
{
	position: absolute; /* 配置方法は絶対値 */
	top: 10px; /* Webのページの上から10ピクセルの位置 */
	left: 10px; /* Webのページの左から10ピクセルの位置 */
	width: 275px; /* 幅は275ピクセル */
	height: 275px; /* 高さは275ピクセル */
	border: 1px solid #000; /* 線は1ピクセルの太さで、実線、色は黒。上下左右に引く */
}

3.JavaScript

今回は、古いコーディングを移植したので、modelとviewには明確には分けなかった。

window.addEventListener("load", init, false);

function init()
{
	//変数の定義
	var startX = 0,
	startY = 0,
	side = 0,
	fai = (1 + Math.sqrt(5)) / 2,
	x1 = 0,
	y1 = 0,
	x2 = 0,
	y2 = 0,
	count = 0;
	
	//MVCデザインパターンの宣言
	function View(){}; //外観の処理を行うオブジェクトのグループ
	//function Controller(){}; //インタラクティブな制御を行なうオブジェクトのグループ(今回は使いません)
	function Model(){}; //ロジックの処理を行うオブジェクトのグループ
	
	//視覚の処理を行うオブジェクトのグループ
	View =
	{
		//空のinit関数を作る
		init : function()
		{
				
		}
	}
	
	//Viewの中の関数(init)にプロトタイプの変数や関数を定義します
	//プロトタイプには、インスタンスで使う共有の関数や変数を設定します
	View.init.prototype.draw = function()
	{
		var j = 0;
	
		//黄金螺旋が必要な数だけの最大値をiに設定
		//ここでは最大値は15
		for (var i = 0; i < 15 ; i++)
		{
			if (j > 3)
			{
				j = 0;
			}

			//螺旋の弧を描き始める最初の角度を決めます
			//ここでは、-180度から弧を描き始め、その次は90度、そして0度、最後に-90度という
			//サイクルを繰り返します。
			if (j == 0)
			{
				var deg = 0;
			}
			else
			if (j == 1)
			{
				deg = -90;
			}
			else
			if (j == 2)
			{
				deg = -180;
			}
			else
			if (j == 3)
			{
				deg = 90;
			}
			
			//初期設定や以後の描画のためのフラグを立てます
			if (i == 0)
			{
				var f = true;
			}
			else
			{
				f = false;
			}
			
			//黄金螺旋を描くための関数を読み込みます
			setGoldenRatio(deg,f,i);
			setGoldenSpiralDraw();
			j++;
		}
		
		
		function setGoldenRatio(deg,flag,i)
		{
			var deg = deg;
			
			if (flag === true)
			{
				//初期設定
				//最初の一辺の長さや座標位置を決めます
				//これらを基準にして、黄金螺旋を描いていきます
				side = 250;
				setXY();
				centerX -= side / 2;
				centerY += x1 / 2;
				startX = centerX;
				startY = centerY;
			}
			else
			{
				//黄金螺旋を描くための毎回の最初の座標位置を決めます
				startX = startX + x1 + x2;
				startY = startY + y1 + y2;
				//一辺の長さです。黄金比率に比例します
				side = Math.sqrt(x1 * x1 + y1 * y1);
				//上記のデータを元に毎回の新しい(x1, y1)、(x2, y2)を計算する関数です
				setXY();
			}
			
			//直線を黄金分割します
			//直線:(startX, startY) から始まり、 (x1, y1) を通って、 (x2, y2)が終点です
			function setXY()
			{
				x1 = Math.cos(deg * Math.PI / 180) * side / fai;
				y1 = Math.sin(deg * Math.PI / 180) * side / fai;
				x2 = Math.cos(deg * Math.PI / 180) * side / (fai*fai);
				y2 = Math.sin(deg * Math.PI / 180) * side / (fai*fai);
			}
		};

		function setGoldenSpiralDraw()
		{
			
			//上記のデータを元に、(startX, startY)から(startX + x1, startY + y1)まで、黄金比率の長い線分を青で描きます
			ctx.beginPath();
			ctx.lineWidth=1;
			ctx.strokeStyle="#0000ff";
			ctx.moveTo(startX, startY);
			ctx.lineTo(startX + x1, startY + y1);
			ctx.stroke();
			
			//上記のデータを元に、(startX + x1, startY + y1)から(startX + x1 + x2, startY + y1 + y2)まで、黄金比率の長い線分を赤で描きます
			ctx.beginPath();
			ctx.lineWidth=1;
			ctx.strokeStyle="#ff0000";
			ctx.moveTo(startX + x1, startY + y1);
			ctx.lineTo(startX + x1 + x2, startY + y1 + y2);
			ctx.stroke();

			//startX, startY、x1, x2、y1, y2を元に、黄金螺旋の弧を描きます
			if (i > 1)
			{
				//弧の半径を求めます
				var dx = x1 + x2;
				var dy = y1 + y2;
				var dis = fai * Math.sqrt(dx * dx + dy * dy);
				//線の太さ
				ctx.lineWidth=2;
				//線の色
				ctx.strokeStyle="#000000";
				//線を描き始める宣言
				ctx.beginPath();
				//弧の最初の座標値
				ctx.moveTo(startX + x1 + x2 + Math.cos(deg * Math.PI / 180)*dis, startY + y1 + y2 + Math.sin(deg * Math.PI / 180)*dis);
				//角度を1度ずつ減らしながら、弧を描いていきます
				var k = 90;
				while(k>=0)
				{
					k--;
					deg--;
					ctx.lineTo(startX + x1 + x2 + Math.cos(deg * Math.PI / 180)*dis, startY + y1 + y2 + Math.sin(deg * Math.PI / 180)*dis);
				}
				//線の描画の終わりを宣言
				ctx.stroke();
			}
		}
	}
	
	//ロジックの処理を行うオブジェクトのグループ
	Model = 
	{
		//空のinit関数を作る
		init: function()
		{

		}
	}
			
	//Modelの中の関数(init)にプロトタイプの変数や関数を定義します
	//プロトタイプには、インスタンスで使う共有の関数や変数を設定します
	Model.init.prototype.ready = function()
	{
		//Canvasのエレメント要素を変数に代入する
		theCanvas = document.getElementById("viewArea");

		//Canvasタグで2次元描画を行ないます
		ctx = theCanvas.getContext("2d");
		
		//Canvasの中心座標を取得
		//centerX: Canvasタグの横幅の1/2を取得
		var offsetX = (theCanvas.currentStyle || document.defaultView.getComputedStyle(theCanvas,'')).width;
		offsetX = Number(offsetX.replace('px',''));
		centerX =  offsetX / 2;
		
		//centerY: Canvasタグの高さの1/2を取得
		var offsetY = (theCanvas.currentStyle || document.defaultView.getComputedStyle(theCanvas,'')).height;
		offsetY = Number(offsetY.replace('px',''));
		centerY =  offsetY / 2;
	}
	
	//Modelの中のInit関数のインスタンスを生成
	var model = new Model.init();
	//Model関数のプロトタイプにあるready関数を呼び出します
	model.ready();
	
	//Viewの中のInit関数のインスタンスを生成
	var view = new View.init();
	//View関数のプロトタイプにあるdraw関数を呼び出します
	view.draw();
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です