週末プログラミング。
canvas内で描画した線にマウスが触れたかどうかを判定するコード。
円や長方形に触れたかどうかのjavascriptサンプルはstackoverflowでそれなりにヒットするけど、直線は見つからなかったので書いてみた。
デモページ(触れたかどうかはコンソールに出力)
コード
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
<h1>Canvas</h1>
<div class="wrapper">
<canvas id="drawArea" width="300" height="300" style="background-color:#ecc;">Canvas not supported</canvas>
</div>
<p>直線にヒットしたかを判定する javascript サンプルプログラム</p>
<p>判定方法は下記URLの計算式を参考にしました。</p>
<a href="http://www.iot-kyoto.com/satoh/2016/01/16/hittest-001/">http://www.iot-kyoto.com/satoh/2016/01/16/hittest-001/</a>
</body>
<script>
var lines = [
{ x1: 10, y1: 20, x2: 120, y2: 180, width: 2, style: "#c00"},
{ x1: 110, y1: 230, x2: 220, y2: 180, width: 6, style: "#000" },
{ x1: 210, y1: 5, x2: 170, y2: 10, width: 3, style: "#080" },
{ x1: 20, y1: 205, x2: 280, y2: 10, width: 10, style: "#00c" }
]
function setup() {
for (var i = 0; i < lines.length; i++) {
line = lines[i];
var angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
line.sn = Math.sin(angle);
line.cs = Math.cos(angle);
}
}
function drawCanvas() {
setup();
var canvas = document.getElementById('drawArea');
var context = canvas.getContext('2d');
for (var i = 0; i < lines.length; i++) {
line = lines[i];
drawLine(context, line.x1, line.y1, line.x2, line.y2, line.width, line.style);
}
canvas.onmousemove = function (e) {
var r = canvas.getBoundingClientRect();
var x = e.clientX - r.left;
var y = e.clientY - r.top;
hover = false;
for (var i = 0; i < lines.length; i++) {
line = lines[i];
hover = isHit(x, y, line.x1, line.y1, line.x2, line.y2, line.width, line.sn, line.cs);
if (hover) {
console.log("Hit:" + i + "番目の線にヒットしました", x, y);
break;
}
}
}
}
function isHit(px, py, x1, y1, x2, y2, h, sn, cs) {
var ret = false;
var xm1 = x1 - px;
var ym1 = y1 - py;
var xm2 = x2 - px;
var ym2 = y2 - py;
var xr1 = xm1 * cs + ym1 * sn;
var yr1 = -xm1 * sn + ym1 * cs;
var xr2 = xm2 * cs + ym2 * sn;
var yr2 = -xm2 * sn + ym2 * cs;
var sx = xr1;
var sy = yr1 - h/2;
var dx = xr2 - xr1;
var dy = h;
if (sx > 0 || sy > 0 || sx + dx < 0 || sy + dy <= 0) {
ret = false;
} else {
ret = true;
}
return ret;
}
function drawLine(context, ax, ay, bx, by, w, s) {
context.lineWidth = w;
context.strokeStyle = s;
context.beginPath();
context.moveTo(ax, ay);
context.lineTo(bx, by);
context.stroke();
}
window.onload = () => {
drawCanvas();
};
</script>
</html>
2020/9/22 幅の判定が誤っていたため修正。