いきなりですが問題です.
HTML5 Canvasで円を描くには,「context.arc(x, y, r, 0, Math.PI * 2, false);」とします.contextはあらかじめセットされた変数です.
マウスのドラッグ操作の始点と終点をそれぞれ,円の中心と円周上の点とし,円を描くための半径rを計算してください.平方根はMath.sqrtで求められます.
昨日の記事のある意味続きです.tmlib.jsではstrokeCircle(x, y, r)を使えば円を描けますが,この記事では,tmlib.jsを使わないこととします.プログラミング言語は,今回もJavaScriptです.
答えを得るには,もう少し,情報が必要となります.ドラッグ操作の「始点と終点の座標」です.
始点は,onmousedownイベント*1のコールバック関数で,座標を取得し,グローバル変数xおよびyに格納しておきます.終点は,onmouseupイベントのコールバック関数で取得ができ,この関数の中で,半径rも計算することとします.
座標取得の方法には,clientXとclientY,pageXとpageY,offsetXとoffsetY,screenXとscreenYがあり,jQuery(JavaScript)でマウス座標やウィンドウサイズを取得して確認するツール | EasyRambleで違いが確認できます.今回は,ページ全体での位置座標を取得する,pageXとpageYを採用します.
コールバック関数の引数は,eventとしておきます.そうすると,event.pageXとevent.pageYが,座標を表すJavaScriptの式となります.
コーディングの前に,rを求める手順を,GIFアニメーションで表現してみました.
手順は次のとおりです.
- 図や数式を書ける領域(紙など)を用意する
- 適当に線分を引く
- 求めたい長さをとする
- 始点の座標を(x, y)とする
- 終点の座標を(event.pageX, event.pageY)とする
- 直角三角形を作り,水平成分と鉛直成分に分ける
- 幅をとする(=|event.pageX−x|)
- 高さをとする(=|event.pageY−y|)
- ,,の関係を三平方の定理で表す()
- について解く()
「半径r」としましたが,実際には始点と終点,2点間の距離を求めています.それと幅と高さに,絶対値記号が入りますが,2乗するので,計算にあたっては不要となります.
ではプログラムに…と行きたいのですが,もう一つだけ,解決しておきたいことがあります.始点の座標の(x, y)と,幅・高さの,との区別です.座標のxとyは,円を描く処理を追加する前のプログラムで,すでに使用されているものとします.そしてとに,プログラム内で適切な変数を用意しましょう.
「差」なので,diffやdeltaといった語が思い浮かびます.字数を減らしたいので,には変数dxを,には変数dyを,それぞれ割り当てることにします.
半径rを算出し,円を描くためのコードは,次のようになります.
var dx = event.pageX - x; var dy = event.pageY - y; var r = Math.sqrt(dx * dx + dy * dy); context.arc(x, y, r, 0, Math.PI * 2, false);
「2乗」について,「dx ^ 2」や「dx ** 2」といった書き方は,認められていません*2.べき乗関数を見つけてきて,「Math.pow(dx, 2)」と書くよりも,「dx * dx」のほうがスマートです.
プログラミングの授業で,学生に「rを計算しましょう」と問うと,おそらく一番気づきにくいのが,箇条書きの最初に挙げた「紙を用意する」だと思います.
次は,「適当に線分を引く」でしょうか.ここは,図示にあたっての「見通し」が必要なところです.直角三角形の斜辺の長さがとなり,残りの辺の長さは,水平成分(X座標)と鉛直成分(Y座標)に分けて,より先に計算できることを,認識しておくわけです*3.
高校の物理で,このように分ける訓練をしていれば,プログラミングもスムーズ…といきたいのですが,そう言い切っていいか分かりませんし,当学部では高校で物理を履修していない学生も入学してきます.
今回の図示や解法を,「新しい経験」としてもらってかまいません.コンピュータグラフィックスなどで,新たな表現技法を学ぶ際の土台になってくれればと願います.
*1:例えば,http://hakuhin.jp/js/mouse.html
*2:http://js-next.hatenablog.com/entry/2016/03/22/221353やhttps://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operatorsに,べき乗演算子「**」が書かれていますが,ECMAScript 2016のプロポーザルの段階らしく,手元のFirefox(バージョン50.1.0)で,開発ツールよりコンソールを出し,「3**2」を実行したものの,「SyntaxError: expected expression, got '*'」と返ってきました.
*3:ドラッグ操作の始点と終点の位置によっては,X座標やY座標の差が0となる場合も起こり得ますが,それでも,ゼロ割や負数の平方根に陥らず,上記の手順で円の半径(2点間の距離)が計算できるのも,別途確認しておきたいところです.