+
+
+
+
+
+
+
+ {running ? "Running at about " + fps + " frames per second." : "Paused."}{" "}
+ Your screen's pixel ratio is {dpr}.
+
+
+ {reduce ? "Your system asks for reduced motion, so the animation started paused. " : ""}
+ {dpr > 1 ? "On this screen, turn “Match screen sharpness” off, and the ball looks blurry." : "On a high-resolution screen (pixel ratio above 1), turning “Match screen sharpness” off makes the drawing blurry."}
+
+
+ );
+}
+
+export function HitTestDemo() {
+ const canvasRef = useRef(null);
+ const circles = [
+ {name: "Red", x: 60, y: 75, r: 32, color: "#ef4444"},
+ {name: "Green", x: 150, y: 75, r: 32, color: "#22c55e"},
+ {name: "Blue", x: 240, y: 75, r: 32, color: "#3b82f6"},
+ ];
+ const [selected, setSelected] = useState(-1);
+ const [last, setLast] = useState("Nothing selected yet.");
+ useEffect(() => {
+ const canvas = canvasRef.current;
+ if (!canvas) return;
+ const ctx = canvas.getContext("2d");
+ ctx.clearRect(0, 0, 300, 150);
+ circles.forEach((circle, index) => {
+ ctx.fillStyle = circle.color;
+ ctx.beginPath();
+ ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2);
+ ctx.fill();
+ if (index === selected) {
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = "#0f172a";
+ ctx.stroke();
+ }
+ });
+ }, [selected]);
+ const pick = (event) => {
+ const canvas = canvasRef.current;
+ const box = canvas.getBoundingClientRect();
+ const scaleX = canvas.width / box.width;
+ const scaleY = canvas.height / box.height;
+ const x = (event.clientX - box.left) * scaleX;
+ const y = (event.clientY - box.top) * scaleY;
+ const hit = circles.findIndex((circle) => Math.hypot(x - circle.x, y - circle.y) <= circle.r);
+ setSelected(hit);
+ setLast("Click at (" + Math.round(x) + ", " + Math.round(y) + ") in canvas units: " + (hit >= 0 ? circles[hit].name + " circle selected." : "no circle there."));
+ };
+ return (
+
+
+
+
{last}
+
+ The canvas is drawn at 300 by 150 but shown larger, so the page converts the mouse position back into canvas units. Without that step, clicks land in the wrong place.
+
+
+ );
+}
+
+If SVG is a box of **shapes you can pick up and move**, canvas is a **blank painting that you paint on with code.** You give it a size, you ask it to draw a circle here and a line there, and it paints the pixels. Once painted, the circle is not an object any more, just coloured dots. To move it, you wipe the area and paint again.
+
+That makes canvas excellent for **games, animation, visual effects, image editing, and anything with a very large number of moving parts**. It also means you take on more work for accessibility, scaling, and clicks, which is the main subject of this lesson.
+
+