どうでもいいプログラム研究所

とある編集者によるIT、Web、ソフトウェア、プログラミングに関する雑記と覚え書き

JavaScriptとCanvasでブラウザに星空を描く

f:id:tdyu5021:20191119005505p:plain

 CanvasJavaScriptの練習として星空を描いてみました。初心者がゼロから作ったものなのでわりと簡単です。

ソースコード

先にソースコードを載せておきます。HTMLはCanvasタグを設けるだけでOK。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1">
<script type="text/javascript" src="script.js"></script>
<title>夜空</title>
</head>
<body onload="draw()" style ="margin:0">
<canvas id = "canvas"></canvas>
</body>
</html>

 JavaScriptは以下です。

function draw(){
    canvas = document.getElementById("canvas");
    c = canvas.getContext("2d");
    //canvasの領域を画面サイズに
	canvas.width = document.documentElement.clientWidth;
	canvas.height = document.documentElement.clientHeight;

	//グラデーションの設定と描画
    var g = c.createLinearGradient(canvas.width/2, 0, canvas.width/2, canvas.height);
	g.addColorStop(0, '#000');
	g.addColorStop(1, '#021a69');
	c.fillStyle = g;
    c.fillRect(0,0,canvas.width,canvas.height);

	var maxX = Math.floor(canvas.width/10);
	var maxY = Math.floor(canvas.height/10);

	//流れ星*************************************	

	//translateする前の状態を保持
	c.save();

	var x00 = 100;
	var y00 = 100; 
	var len = 300;
	var dia0 = 2;
	c.translate(600,100);
	c.rotate(-(18 * Math.PI / 180));
	c.fillStyle = "#ffffff"; 
	c.beginPath();
	c.moveTo(x00,y00);
	c.lineTo(x00+len,y00+dia0*2);	
	c.lineTo(x00,y00+dia0*2);
	c.closePath();
	c.fill();	
	c.beginPath();
	c.arc(x00,y00+dia0,dia0,0, Math.PI*2, false);
	c.fill();	
	c.closePath();

	//前の状態を戻す
	c.restore();

	//光り輝く星*************************************		
	for(var i=0; i<15; i++){
		var x1 = Math.floor(Math.random()*maxX)*10;
		var y1 = Math.floor(Math.random()*maxY)*10;
		var dia = Math.floor(Math.random()*10)+15;
		c.lineWidth=0;
		c.strokeStyle = "#ffffff"; 
		c.fillStyle = "rgba(255, 255, 255, 0.1)"; 
		//外側の円
		c.shadowColor = "#ffffff";
		c.shadowOffsetX = 0;
		c.shadowOffsetY = 0;
		c.shadowBlur = 3;
		c.beginPath();
		c.arc(x1, y1, dia/2.5, 0, Math.PI*2, false); 
		c.closePath();	
		c.fill();
		//内側の円
		c.beginPath();
		c.fillStyle = "#ffffff"; 
		c.arc(x1, y1, dia/5, 0, Math.PI*2, false);
		c.closePath();	
		c.fill();
		//横棒
		c.beginPath();
		c.moveTo(x1-dia,y1);
		c.lineTo(x1,y1-1);	
		c.lineTo(x1+dia,y1);
		c.lineTo(x1,y1+1);
		c.closePath();
		c.fill();
		//縦棒
		c.beginPath();
		c.moveTo(x1,y1-dia);
		c.lineTo(x1-1,y1);	
		c.lineTo(x1,y1+dia);
		c.lineTo(x1+1,y1);
		c.closePath();
		c.fill();
	}

	//通常の星(円だけ)*************************************
	var a = [1,1,1,1,1.5,1.5,2,2.5];	
	c.fillStyle = "#ffffff";
	c.shadowColor = "#ffffff";
	c.shadowOffsetX = 0;
	c.shadowOffsetY = 0;
	c.shadowBlur = 3;
    for(var i = 0; i< 300; i++){   
		var x = Math.floor(Math.random()*maxX)*10;
		var y = Math.floor(Math.random()*maxY)*10;
		var n = Math.floor(Math.random()*a.length);
		var radius = a[n];
		c.beginPath();
		c.arc(x, y, radius, 0, Math.PI*2, false);
		c.closePath();
		c.fill();
	}

	//輝く星(円+十字)*********************************
	for(var i=0; i<20; i++){
		var x = Math.floor(Math.random()*maxX)*10;
		var y = Math.floor(Math.random()*maxY)*10;
		
		//円
		var dist = Math.floor(Math.random()*3)+1;
		c.fillStyle = "#ffffff";
		c.shadowBlur = 4;
		c.beginPath();
		c.arc(x, y, dist, 0, Math.PI*2, false); 
		c.closePath();
		c.fill();

		var diff = dist*(2/3);
		//横棒
		c.lineWidth=0.8;
		c.strokeStyle = "#ffffff"; 
		c.beginPath();
		c.moveTo(x-(dist+diff),y);
		c.lineTo(x+dist+diff,y);
		c.closePath();
		c.stroke();
		
		//縦棒
		c.beginPath();
		c.moveTo(x,y-(dist+diff));
		c.lineTo(x,y+dist+diff);
		c.closePath();
		c.stroke();
	}
}

このスクリプトで覚えたこと(個人的備忘録)

Canvas初心者の私が、これを作成するにあたって初めて知った知識を以下に備忘録兼学習メモ的に記します。

線形グラデーションを描く

これはcreateLinearGradientメソッドというものを使います。

createLinearGradient(x0, y0, x1, y1)という形を取り、引数1と引数2はグラデーションの開始地点のxとy座標、引数3と引数4はグラデーションの終了地点のxとy座標です。

画像を回転させる

描いた星空の中に、斜めの線で表現した流れ星があります。これは真横に書いた図形をrotateメソッドで斜めにしています。このメソッドは引数を1つ取り、ラジアンで回転させる角度を指定します。ただ、このメソッドは対象のオブジェクトを中心に回転させるのでなく、画面の左上を起点に回転させてしまうので、そのままでは使いづらいです。そこで一緒に使うのが次のに紹介するtranslateメソッドです。

座標位置をずらす

Canvasは、デフォルトでは座標の左上が(0,0)ですが、translateメソッドを使うと座標の位置をずらすことができます。これをrotateメソッドと組み合わせて使うと、rotateで回転させる座標を左上起点でなく、回転させる自分自身にすることができます。

※注:なのですが、今回のコードはそうなっていません。rotateしたとき、ほどよい場所に流れ星が来るよう適当な数字を入れているだけです。

canvasの状態を記憶して元に戻す

ちなみにtranslateメソッドで座標をずらすと以降が座標が全部ずれてしまうので、saveメソッドでtranslate前のCanvasを保持しておき、流れ星を作ったあとにrestoreメソッドを使って元に戻しています。こうすれば以降の記述はtranslateメソッドの影響は受けません。

ぼかしをかける

夜空に輝く星を作るのに欠かせないのが、ぼかしです。shadowBlurプロパティを指定するとオブジェクトにぼかしをかけられます。

Canvasのサイズを画面幅に合わせる

私がいままで作ってきたプログラムでは、CanvasのサイズはCSSやHTML側で固定値にすることが多かったのですが、今回は開いた画面いっぱいに描画したいので、可変にする必要があります。画面幅に合わせてCanvas領域を指定する方法を探したところ以下のように書けばOKのようです。

canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;

今回手を抜いたところ

星空はランダムに描画されますが、面倒だったので流れ星は場所が決め打ちになっています。その点は手を抜きました。

小さい星はただ丸とか単純な十字を書いただけですが、光り輝く星は割ときれいに作れたかなと個人的に気に入ってます。

Canvasでアート系はもっと作ってみたいです。(目指すはジェネレーティブアート)