プログラム内で使う角度について
プログラム内で使う角度はラジアン(radian)という単位に変換しなければなりません。これは角度に円周率(π)を掛けて180で割ることで求めることができます。
たとえば、60°をラジアンに変換すると次のようになります。
const radian = 60 * Math.PI / 180
そこでラジアンを計算する関数を作っておきます。
functions.jsに次のように書き込みます。
const calcRadian = (angle) => {
return angle * Math.PI / 180;
MEMO
変数名の
radian
は角度を表します。一方、変数名の
radius
は線の長さ(半径)を表します。 スペルが似ているため間違わないよう気をつけてください。
回転後の座標位置の求め方
次のような長さが1の線を60度回転させたら、座標位置はどうなるでしょうか?
これは三角関数のサインとコサインを使って求めることができます。
この場合のx座標は、cos60°となります。Javascriptでは Math.cos
で計算できます。引数には角度を渡しますが、単位はラジアンでなければなりません。そこでx座標は次のようにして求めます。
const radian = calcRadian(60)
const x = Math.cos(radian);
次にy座標は、sin60°となります。 Math.sin
を使って同じように計算します。
const radian = calcRadian(60)
const x = Math.sin(radian);
// xの値は0.8660254037844386
よって、この場合の座標位置は { x: 0.5, y: 0.8660254037844386 }
となります。
線の長さと原点が変わった場合
中心が(30, 40)で線の長さが50の場合の回転後の座標位置はどうなるでしょうか?
同じようにサインとコサインで求めますが、線の長さを掛けて、中心座標を足す必要があります。
const radian = calcRadian(60)
const x = Math.cos(radian) * 50 + 30;
const y = Math.sin(radian) * 50 + 40;
よって、この場合の座標位置は { x: 55, y: 83.30127018922192 }
となります。
回転後の座標位置を求める関数の作成
functions.jsに次のように書き込みます。
* @param centerPos 中心となる座標位置
* @param radian 回転させる角度(単位:ラジアン)
const calcPos = (centerPos, radian, radius) => {
x: Math.cos(radian) * radius + centerPos.x,
y: Math.sin(radian) * radius + centerPos.y
現在の節の座標位置の求め方
現在の節が存在している角度は線の回転角度×回転回数+初期角度で求めることができます。
たとえば、線の長さが100で、初期角度を90°に設定しているとします。
回転角度が-160°で、それを3回、回転させたとします。
そうすると現在の角度は-160×3+90=-390°となります。よって、現在の節の座標は次のようにして求められます。
const centerPos = { x: 0, y: 0 };
const radian = calcRadian(-390);
const nodePos = calcPos(centerPos, radian, radius);
// nodePosは、{ x: 86.6025403784439, y: -50 }
すべての節の座標位置を計算する関数の作成
functions.jsに次のように書き込みます。
関数内の rotateCount
は回転回数、 initialRadian
は初期角度のことで、main.jsで設定する変数です。
const createNodePosList = () => {
const nodePosList = [{ x: 0, y: 0 }];
lineDataList.forEach((lineData, i) => {
const centerPos = nodePosList[i];
const currentRadian = calcRadian(lineData.angle) * rotateCount + initialRadian;
const nodePos = calcPos(centerPos, currentRadian, lineData.radius);
nodePosList.push(nodePos);
canvasを初期状態にする関数の作成
functions.jsに次のように書き込みます。
nodePosList = createNodePosList();
fillBgCanvas(bgColor, mainCanvasCtx);
clearCanvas(needleCanvasCtx);
drawNeedle(nodePosList, lineDataList, needleCanvasCtx);
回転針を回転させる関数の作成
functions.jsに次のように書き込みます。
const rotateNeedle = () => {
const nextNodePosList = createNodePosList();
drawTrajectories(nodePosList, nextNodePosList, lineDataList, mainCanvasCtx);
clearCanvas(needleCanvasCtx);
drawNeedle(nextNodePosList, lineDataList, needleCanvasCtx);
nodePosList = nextNodePosList;
「自動描画」ボタンを押したときの処理
functions.jsに次のように書き込みます。
if (runId !== null) return;
runId = window.setTimeout(run, drawInterval);
runId
はmain.jsで定義している変数です。自動描画しているときはsetTimeoutの戻り値が入ります。nullの場合は自動描画を止めていることを意味します。
「描く」ボタンを押したときの処理
functions.jsに次のように書き込みます。
if (runId !== null) return;
「自動描画」ボタンを押したときの処理
functions.jsに次のように書き込みます。
if (runId === null) return;
window.clearInterval(runId);
main.jsの作成
main.jsに次のように書き込みます。
// 回転針の初期角度。時計の12時方向を初期角度にしている
const initialRadian = calcRadian(90);
// 360度をラジアンにした変換した値。点を描くときに使う
const radian360 = calcRadian(360);
// setTimeoutの戻り値を入れる。nullの場合は描画を止めていることを意味する。
// 2つのcanvasの描画コンテキストの初期設定する
const mainCanvasCtx = initCanvasCtx('main-canvas');
const needleCanvasCtx = initCanvasCtx('needle-canvas');
document.getElementById('draw-button').addEventListener('click', draw);
document.getElementById('start-button').addEventListener('click', autoDraw);
document.getElementById('stop-button').addEventListener('click', stopDraw);
document.getElementById('reset-button').addEventListener('click', initDraw);
これで完成です!index.htmlをブラウザから開いてみてください。
設定を変更していろんな模様を描こう!
settings.jsの設定を変更するといろんな模様を描くことができます。
それぞれの設定項目の入力欄を作成すれば、次のような幾何学模様メーカーを作成することもできます。
線を回転させて幾何学模様を描きます。線の長さや回転角度を変えると予想外な模様ができたりします。