I'm trying to clamp a small point into a sphere, but every time I do it, I get a rectangle -- how can I clamp this correctly?
const canvas = document.getElementById("canvas");
const center = { x: canvas.width / 2, y: canvas.height / 2 }
const point = { ...center }
const ctx = canvas.getContext("2d");
const GROUND_RADIUS = 50;
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ground
ctx.beginPath();
ctx.arc(center.x, center.y, GROUND_RADIUS, 0, 2 * Math.PI);
ctx.stroke();
// point
ctx.beginPath();
ctx.arc(point.x, point.y, 10, 0, 2 * Math.PI);
ctx.fill();
requestAnimationFrame(render)
}
requestAnimationFrame(render)
canvas.addEventListener("mousemove", event => {
point.x = Math.max(Math.min(event.clientX, center.x GROUND_RADIUS), center.x - GROUND_RADIUS);
point.y = Math.max(Math.min(event.clientY, center.y GROUND_RADIUS), center.y - GROUND_RADIUS);
})
canvas {
border: 1px solid black;
}
<canvas id="canvas" width="150" height="150">
CodePudding user response:
The angle of the position from the center equals Math.tan(y/x)
. By using some trigonometry we can confine x
to radius * cos(alpha)
and same for y
.
const canvas = document.getElementById("canvas");
const status = document.getElementById("status");
const center = {
x: canvas.width / 2,
y: canvas.height / 2
}
const point = { ...center }
const ctx = canvas.getContext("2d");
const GROUND_RADIUS = 50;
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ground
ctx.beginPath();
ctx.arc(center.x, center.y, GROUND_RADIUS, 0, 2 * Math.PI);
ctx.stroke();
// point
ctx.beginPath();
ctx.arc(point.x, point.y, 10, 0, 2 * Math.PI);
ctx.fill();
requestAnimationFrame(render)
}
function getAngle(dy, dx) {
return (Math.atan2(dy, -dx) * 180 / Math.PI 360) % 360;
}
requestAnimationFrame(render)
canvas.addEventListener("mousemove", event => {
point.x = event.offsetX
point.y = event.offsetY
var dx = (center.x - point.x)
var dy = (center.y - point.y)
var alpha = getAngle(dy, dx);
status.innerText = dx ", " dy " and alpha = " alpha.toFixed(2);
var maxX = Math.abs(GROUND_RADIUS * Math.cos(alpha / 180 * Math.PI));
var maxY = Math.abs(GROUND_RADIUS * Math.sin(alpha / 180 * Math.PI));
dx = Math.min(Math.max(-maxX, dx), maxX)
dy = Math.min(Math.max(-maxY, dy), maxY)
point.x = -dx center.x
point.y = -dy center.y
})
canvas {
border: 1px solid black;
}
<div id="status"></div>
<canvas id="canvas" width="320" height="200">