Canvasを数学/競プロ等の解説に使うと便利かもしれない

久しぶりにCanvasで遊びました。

developer.mozilla.org

CanvasはHTML+JavaScriptで動くので、こういう場所(はてなブログ)でも使えます。 試しに簡単なプログラムを書いてみたので見ていってください。


突然ですが問題です

傾角を変えることのできる斜面に質量8.0kgの物体を置いて、斜面を水平の状態から徐々に傾けると, 傾角が30°になったときにすべり出した. 面を水平にしたとき, この物体を水平に押して動かすために必要な力は何Nか.

引用元 森北出版株式会社 「やさしく学べる基礎物理 新装版」 P38


こういう問題を解くにはまず図を描きますよね。 そこでさらに動きが付けられるとイメージが湧きやすくなる(かもしれない)ということで、Canvasで作ってみました。

スライダーに合わせてぬるぬる動くので触ってみてください。
(下に何も表示されない場合リロードしてみてください)




ちなみに問題の答えは45Nなんですが(正解でしたか?^^)、伝えたいのはそこではなくて、 JSが動く環境ならどこでも動くCanvasを上手く使えば問題や解説の質を高めることができるのではないかと思いました。

何年も前から「Canvasは流行るぞ」って思ってるんですけど一向に流行らないんですよね...。たまに使われてるのを目にするんですけどね。

せっかくなのでコードも貼っておきます。書きなぐりなのでちょっと読みづらいかもm(__)m

HTML

<div>
  <canvas id="canvas" width="200" height="200"></canvas>
  <br />
  <label for="degree">傾角</label><br>
  <input type="range" min="0" max="30" value="0" id="degree">
</div>

JavaScript

<script>
const draw = function(degree) {
  const canvas = document.getElementById('canvas');
  const ctx = canvas.getContext('2d');
  const width = 200;
  const height = 200;

  ctx.clearRect(0,0,width,height)

  // 土台になる直線を描画
  ctx.beginPath();
  ctx.moveTo(0, 180);
  ctx.lineTo(width, 180);

  const leftPadding = 30;
  const bottomPadding = 20;

  const radian = (degree / 180.0) * Math.PI;
  const x = (height - bottomPadding) / Math.tan(radian) + leftPadding;

  // θに合わせて直線を描画
  ctx.moveTo(leftPadding, 180);
  ctx.lineTo(x, 0);
  ctx.closePath();
  ctx.stroke();

  // どうやら、Canvasでは、特定のオブジェクトだけを回転させるということはできないようです。
  // 物体(青いやつ)だけをθに合わせて回転させたかったんですが、
  // canvasのcontext自体をrotateして物体(青いやつ)を描画し、その後contextを元に戻しています。
  ctx.save();
  ctx.translate(leftPadding, 180);
  const x1 = 100 * Math.cos(radian);
  const y1 = -100 * Math.sin(radian);

  ctx.rotate(-radian);
  if(degree === '30'){
    ctx.fillText("傾角が30°になったときに物体が滑りだす", x1 - 60, y1 - 20);
    ctx.fillText("<-----", x1 - 20, y1 + 30);
    ctx.fillStyle = 'rgb(200,0,0)';
  }else{
    ctx.fillStyle = 'rgb(0,0,200)';
  }
  // 物体(青いやつ)を描画
  ctx.fillRect(100, 0, 40, -40);
  ctx.restore();
}

const element = document.getElementById('degree');

draw(0);
element.addEventListener('input', function (evt) {
  draw(this.value);
});

</script>