JavaScript
13. 描画の単位を考える
円や四角形を繰返し描く場合、1つ1つの円や四角を描画の単位と捉えることができます。
自分の作品を制作する際には、描画の単位を工夫してみることも必要でしょう。
ここで記述することは「12. 関数で処理をまとめる」で記した内容に似ていますが、描画の単位を関数として考えてみます。
描画の単位を関数として定義する
以下は「11. プログラムを汎用的にする」の項目で、縦横に円を描画したプログラムを少し変更したものです。
window.addEventListener( "load", loadFunc, false ); function loadFunc() { var canvas = document.getElementById( "stage" ); var ctx = canvas.getContext( "2d" ); var repeatNum = 9; var pitch = 50; var shapeSize = 40; var pitchWidth = pitch * ( repeatNum - 1 ); var leftX = ( canvas.width - pitchWidth ) / 2; ctx.strokeStyle = "hsla( 45, 80%, 50%, 0.8 )" ctx.fillStyle = "hsla( 45, 80%, 50%, 0.4 )"; for( var i = 0; i < repeatNum; i++ ) { for( var j = 0; j < repeatNum; j++ ) { var drawPointX = leftX + j * pitch; var drawPointY = leftX + i * pitch; drawShape( ctx, drawPointX, drawPointY, shapeSize ); } } } function drawShape( argCtx, centerX, centerY, size ) { argCtx.beginPath(); argCtx.arc( centerX, centerY, size, 0, Math.PI*2, false ); argCtx.fill(); }
22行目、今までのようにarc()命令を書いても同じ処理は実現できますが、ここではdrawShape()という関数を呼び出しています。
そして実際に円を描く命令は、28行目以降の関数drawShape()の中、29〜31行目に書いています。
次にdrawShape()以外のプログラムは変えずに、drawShape()の中の円を描く記述だけを変えてみます。つまりloadFunc()はいじらずに、drawShape()だけを変更します。
window.addEventListener( "load", loadFunc, false ); function loadFunc() { var canvas = document.getElementById( "stage" ); var ctx = canvas.getContext( "2d" ); var repeatNum = 9; var pitch = 50; var shapeSize = 40; var pitchWidth = pitch * ( repeatNum - 1 ); var leftX = ( canvas.width - pitchWidth ) / 2; ctx.strokeStyle = "hsla( 45, 80%, 50%, 0.8 )" ctx.fillStyle = "hsla( 45, 80%, 50%, 0.4 )"; for( var i = 0; i < repeatNum; i++ ) { for( var j = 0; j < repeatNum; j++ ) { var drawPointX = leftX + j * pitch; var drawPointY = leftX + i * pitch; drawShape( ctx, drawPointX, drawPointY, shapeSize ); } } } function drawShape( argCtx, centerX, centerY, size ) { argCtx.fillRect( centerX - size / 2, centerY - size / 2, size, size ); }
29行目、先ほどは円を描く命令だった部分を、矩形を描く命令に変えてみました。以下のようになります。
つまりこのように記述すると、描画単位として円や四角を選ぶということと、それをどのように描くかという描画処理とを関数として分けたことになります。drawShape()内に描かれた図形が繰返し描かれるわけですから、円や四角以外の独自の描画単位を作ろうと試みる場合は、その処理をdrawShape()内に記述すれば良いということになります。
円や矩形だけではなく、どのような描画の単位とするのが自分が望むプログラムとして相応しいのか、工夫を試みてみると良いでしょう。
いくつかのサンプル
以下、プログラムは関数drawShape()の部分のみ記載します。それ以外(loadFunc()の内容)は前述に同じです。
描画単位:単位内のランダムな地点を経由する折れ線
function drawShape( argCtx, centerX, centerY, size ) { var drawRepeat = 20; argCtx.beginPath(); argCtx.moveTo( centerX, centerY ); for( var i = 0; i < drawRepeat; i++ ) { var tmpX = Math.floor( Math.random() * size ) - size / 2; var tmpY = Math.floor( Math.random() * size ) - size / 2; argCtx.lineTo( centerX + tmpX, centerY + tmpY ); } argCtx.stroke(); }
描画単位:単位内の端から端まで、範囲内の中心を通る複数の線
function drawShape( argCtx, centerX, centerY, size ) { var drawRepeat = 6; for( var i = 0; i < drawRepeat; i++ ) { var tmpX = Math.floor( Math.random() * size ) - size/2; var tmpY = Math.floor( Math.random() * size ) - size/2; argCtx.beginPath(); argCtx.moveTo( centerX - tmpX, centerY - size / 2 ); argCtx.lineTo( centerX + tmpX, centerY + size / 2 ); argCtx.stroke(); argCtx.beginPath(); argCtx.moveTo( centerX - size / 2, centerY - tmpY ); argCtx.lineTo( centerX + size / 2, centerY + tmpY ); argCtx.stroke(); } }
描画単位:ランダムな描画角度の円弧
function drawShape( argCtx, centerX, centerY, size ) { var tmpSize = Math.floor( Math.random() * size/2 ) + size/2; var tmpStartAngle = Math.random() * Math.PI; var tmpEndAngle = Math.random() * Math.PI + Math.PI; argCtx.beginPath(); argCtx.arc( centerX, centerY, tmpSize, tmpStartAngle, tmpEndAngle, false ); argCtx.stroke(); }
drawShape内で、描き始めの範囲が0〜180度(0〜πラジアン)、描き終わりの範囲が180度〜360度(πラジアン〜2πラジアン)の円弧を描画。
描画単位:複数の円
function drawShape( argCtx, centerX, centerY, size ) { var tmpSize = Math.floor( Math.random() * size/4 ) + size/4; var tmpX = Math.floor( Math.random() * tmpSize ) - tmpSize/2; var tmpY = Math.floor( Math.random() * tmpSize ) - tmpSize/2; argCtx.beginPath(); argCtx.arc( centerX + tmpX, centerY + tmpY, tmpSize, 0, Math.PI*2, false ); argCtx.fill(); var drawRepeat = 4; for( var i = 0; i < drawRepeat; i++ ) { tmpSize = Math.floor( Math.random() * size/8 ) + size/8; tmpX = Math.floor( Math.random() * size/2 ) - size/4; tmpY = Math.floor( Math.random() * size/2 ) - size/4; argCtx.beginPath(); argCtx.arc( centerX + tmpX, centerY + tmpY, tmpSize, 0, Math.PI*2, false ); argCtx.fill(); } }
3行目、大きな円のサイズ。size/4からsize/2(サイズの4分の1からサイズの2分の1)までの間でランダム。
5、6行目、大きな円の中心がcenterX、centerYで指定された値からずれる範囲。-size/2からsize/2までの間でランダム。
14〜25行目、小さな円をdrawRepeatの数だけ描画。小さな円のサイズはsize/8からsize/4(サイズの8分の1からサイズの4分の1)までの間でランダム。中心がずれる位置は、-size/4からsize/4までの間でランダム。