JavaScript

11. プログラムを汎用的にする

プログラミングでヴィジュアルを作る面白さの一つは、(最終的なヴァジュアルを作るのではなく)ヴァジュアルの作り方を作る点にあると言えます。

そのための1歩として、簡単なプログラムであっても、なるべく汎用的に作ると良いでしょう。

今までの項目では、例えば線を描く場合であっても、その座標に直接数値を指定していました。変数を利用した方が良い場合は、数値ではなく変数を使い数値を間接的に指定することで、プログラムが汎用的になることがあります。

座標や変更する可能性がある数を変数にしたり、計算で求めたりする 1

例えば「8.繰返し」では、線を21本描くプログラムを以下のように書きました。

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

function loadFunc() {

	var canvas = document.getElementById( "stage" );
	var ctx = canvas.getContext( "2d" );

	ctx.strokeStyle = "#339933";

	for( var i = 0; i < 21; i++ ) {
		ctx.beginPath();
		ctx.moveTo( 50 + i * 20, 50 );
		ctx.lineTo( 50 + i * 20, 450 );
		ctx.closePath();
		ctx.stroke();
	}

}

このプログラムですが、線の描画位置や本数、長さを検討したり、修正、発展させる可能性があるのであれば、12、13行目の始点・終点の座標(50とか450とか)や線を描く幅(20)などは変数とした方が良いかもしれません。つまり、以下のように書いた方が望ましい場合があります。

window.addEventListener( "load", loadFunc, false );
 
function loadFunc() {
 
	var canvas = document.getElementById( "stage" );
	var ctx = canvas.getContext( "2d" );

	var repeatNum = 21;	//繰返し回数
	var linePitch = 20;	//線の間隔

 	var lineLeftX = 50; //線を描き始める左端のx座標
	var lineTopY = 50;	//線を描き始める上端のy座標

	var lineLength = 400;	//線の長さ
	var lineBottomY = lineTopY + lineLength;	//線の描き終わりのy座標
	
	ctx.strokeStyle = "#339933";

 	for( var i = 0; i < repeatNum; i++ ) {
		var drawPointX = lineLeftX + i * linePitch;
		ctx.beginPath();
		ctx.moveTo( drawPointX, lineTopY );
		ctx.lineTo( drawPointX, lineBottomY );
		ctx.closePath();
		ctx.stroke();
	}

}

moveTo()とlineTo()で使っていた数値を、プログラムの冒頭で定義した変数に置き換えています。

この書き方は、線全体の左上を基準にする書き方になっています。指定したlineLeftX、lineTopYからlinePitch、lineLength、repeatNumの値に応じて(左上を基準に、指定した間隔、長さ、本数に応じて)線が描かれます。

ある程度の本数、長さの場合で、本数や長さを変えても描画範囲の中央に描きたいのであれば、以下のように書いた方が良いでしょう。

window.addEventListener( "load", loadFunc, false );
 
function loadFunc() {
 
	var canvas = document.getElementById( "stage" );
	var ctx = canvas.getContext( "2d" );

	var repeatNum = 21;	  //繰返し回数
	var linePitch = 20;	  //線の間隔

	var lineLength = 400; //線の長さ

	var linesWidth = linePitch * ( repeatNum - 1 );		 //線全体の横幅
	var rightLeftX = ( canvas.width - linesWidth ) / 2;	 //左右の余白
	var topBottomY = ( canvas.height - lineLength ) / 2; //上下の余白
	var lineBottomY = topBottomY + lineLength;	//線の描き終わりのy座標
	
	ctx.strokeStyle = "#339933";

 	for( var i = 0; i < repeatNum; i++ ) {
		var drawPointX = rightLeftX + i * linePitch;
		ctx.beginPath();
		ctx.moveTo( drawPointX, topBottomY );
		ctx.lineTo( drawPointX, lineBottomY );
		ctx.closePath();
		ctx.stroke();
	}

}

13行目、線全体の横幅を線の間隔と繰返しの回数から求めています。

14、15行目、canvas.widthとcanvas.heightと書くと、それぞれ描画範囲の横幅と高さを得ることができます(ここでのcanvasとは、5行目でvarの後に書いているcanvasという変数のことです。5行目でvarの後に書いた変数名に続けて、.width、.heightと書くと、描画範囲の横幅と高さになります)。描画範囲の横幅と高さを利用して、線全体の左右と上下の余白を計算しています。

linePitchやlineLength、repeatNumをある程度の範囲であれば変更しても、線全体が描画範囲の中央に描かれることになります。数値を変えて、試してみて下さい。

線全体を中央に1
repeatNum = 30 linePitch = 5 lineLength = 200

線全体を中央に2
repeatNum = 5 linePitch = 50 lineLength = 450

中央に描画するのではなく、上下左右の余白を固定するのであれば、繰返しの回数から線の間隔を計算で求めた方が良いでしょう。

何の値を変数にし、どのような計算で値を求めるかは、どのようなプログラムを書きたいか、どのような変更をする可能性があるかによって異なります。

始めから変数を利用するのが難しければ、このページの冒頭のようにとりあえず数値を使っておき、後からできる部分を変数に置き換えていくなどすると良いでしょう。

ページの先頭へ↑

座標や変更する可能性がある数を変数にしたり、計算で求めたりする 2

同様に「8.繰返し」では、円を縦横に並べるプログラムを以下のように書きました。

window.addEventListener( "load", loadFunc, false );
  
function loadFunc() {
  
    var canvas = document.getElementById( "stage" );
    var ctx = canvas.getContext( "2d" );
     
    ctx.strokeStyle = "#339933";
 
    for( var i = 0; i < 9; i++ ) {
        for( var j = 0; j < 9; j++ ) {
            ctx.beginPath();
            ctx.arc( 50 + j * 50, 50 + i * 50, 20, 0, Math.PI*2, false );
            ctx.stroke();
        }
    }
 
}

繰返しの回数は、同じ数を縦横に繰り返すのであれば、2箇所に指定があるので、変数にした方が良いのはもちろんですが、それ以外も以下のように書き換えてみます。

window.addEventListener( "load", loadFunc, false );
  
function loadFunc() {
  
    var canvas = document.getElementById( "stage" );
    var ctx = canvas.getContext( "2d" );
 
 	var repeatNum = 9;		//繰返しの回数
	var circlePitch = 50;	//円の間隔
	var circleRadius = 20;	//円の半径

	var pitchWidth = circlePitch * ( repeatNum - 1 );	
	var leftX = ( canvas.width - pitchWidth ) / 2;		//余白

    ctx.strokeStyle = "#339933";

    for( var i = 0; i < repeatNum; i++ ) {
        for( var j = 0; j < repeatNum; j++ ) {
			var drawPointX = leftX + j * circlePitch;
			var drawPointY = leftX + i * circlePitch;
            ctx.beginPath();
            ctx.arc( drawPointX, drawPointY, circleRadius, 0, Math.PI*2, false );
            ctx.stroke();
        }
    }
 
}

8〜10行目、繰返しの回数、円の間隔(隣り合う円の中心間の距離)、円の半径をそれぞれ変数にし、12、13行目で複数の円が描かれる範囲と周囲の余白の値を求めています(余白と書きましたが、描画範囲をより円が描かれる範囲が大きい場合には、描画範囲をどれだけはみ出すかという値になります)。

19、20行目は、x座標とy座標の値を一端変数に代入しています。

このように書いて、以下、repeatNum、circlePitch、circleRadiusの値を色々と変えてみます。

円を縦横に並べる1
repeatNum = 5 circlePitch = 10 circleRadius = 100

円を縦横に並べる2
repeatNum = 10 circlePitch = 20 circleRadius = 100

円を縦横に並べる3
repeatNum = 10 circlePitch = 50 circleRadius = 100

繰返しの回数、円の間隔、円の半径を変えただけで、描画処理そのものは変えていませんが、一見、同じ描画処理とは思えない差が生まれます。

この辺りまでくると、描画処理を作る、つまりヴィジュアルの作り方を作るということの雰囲気や楽しさの一端が味わえるのではないでしょうか。

ページの先頭へ↑

< 10. ランダム

12. 関数で処理をまとめる >