如何检测Canvas上的鼠标点击是否命中圆形?
Canvas圆形点击检测实现方案
我不确定如何实现Canvas上鼠标点击圆形的检测功能,自行查找的解决方案既不兼容现有代码,也不符合我的需求。我仅需实现点击是否命中圆形的检测逻辑,以下是我的现有代码,若需更多细节请告知。
//variable declarations const cavna = document.getElementById("gameC"); const mainContext = cavna.getContext("2d"); var counter = 0; var maxCanvas = { height: cavna.height, width: cavna.width, } //TODO: let amountOfCirclesOnScreen = 0; //generate a random number between the specified values function ran(min, max) { return (Math.random() * (max - min) + min); } //generates a random color hex code function GenerateRandomColor() { return Math.floor(Math.random() * 16777215).toString(16); } //makes a new circle function GenerateNewCircle() { if (amountOfCirclesOnScreen < 1) { amountOfCirclesOnScreen++; //maybe figure out how to draw a circle (completed) mainContext.beginPath(); //mainContext.moveTo(ran(0, maxCanvas.width), ran(0, maxCanvas.height)); mainContext.fillStyle = 'hsl(' + 360 * Math.random() + ', 100%, 50%)'; mainContext.arc(ran(0, maxCanvas.width), ran(0, maxCanvas.height), 50, 0, 2 * Math.PI); mainContext.stroke(); mainContext.fill(); } } //clears tjhe canvas function clearCanvas() { amountOfCirclesOnScreen = 0; mainContext.clearRect(0, 0, maxCanvas.width, maxCanvas.height); } //checks where u click //TODO: check to see if click is on a circle, if yes, clear the canvas function getMousePosition(event) { let x = maxCanvas.width - event.clientX; let y = maxCanvas.height - event.clientY; alert("Coordinate x: " + x + " | Coordinate y: " + y); } cavna.addEventListener("mousedown", function(e) { getMousePosition(e); }); GenerateNewCircle(); setInterval(() => { document.getElementById("counter").innerText = amountOfCirclesOnScreen; }, 40);
解决方案
要实现点击命中圆形的检测,核心是保存圆形的坐标和半径数据,然后通过计算点击点与圆心的距离来判断是否命中。以下是对现有代码的修改:
1. 新增变量存储当前圆形信息
在全局变量区域添加:
// 存储当前显示的圆形的坐标和半径 let currentCircle = null;
2. 修改GenerateNewCircle函数,保存圆形数据
生成圆时,把圆心坐标和半径存入currentCircle:
function GenerateNewCircle() { if (amountOfCirclesOnScreen < 1) { amountOfCirclesOnScreen++; const circleX = ran(0, maxCanvas.width); const circleY = ran(0, maxCanvas.height); const circleRadius = 50; // 保存圆形数据 currentCircle = { x: circleX, y: circleY, radius: circleRadius }; mainContext.beginPath(); mainContext.fillStyle = 'hsl(' + 360 * Math.random() + ', 100%, 50%)'; mainContext.arc(circleX, circleY, circleRadius, 0, 2 * Math.PI); mainContext.stroke(); mainContext.fill(); } }
3. 修正鼠标坐标计算逻辑
之前的坐标计算是错误的,需要将视口坐标转换为Canvas内部坐标:
function getMousePosition(event) { // 获取Canvas在页面中的位置偏移 const rect = cavna.getBoundingClientRect(); // 计算相对于Canvas左上角的坐标 const x = event.clientX - rect.left; const y = event.clientY - rect.top; // 检测是否命中圆形 if (currentCircle) { // 计算点击点到圆心的距离(勾股定理) const dx = x - currentCircle.x; const dy = y - currentCircle.y; const distance = Math.sqrt(dx * dx + dy * dy); // 距离小于等于半径则命中 if (distance <= currentCircle.radius) { clearCanvas(); GenerateNewCircle(); // 命中后可重新生成新圆 } } }
完整修改后的代码
//variable declarations const cavna = document.getElementById("gameC"); const mainContext = cavna.getContext("2d"); var counter = 0; var maxCanvas = { height: cavna.height, width: cavna.width, } //TODO: let amountOfCirclesOnScreen = 0; // 存储当前显示的圆形的坐标和半径 let currentCircle = null; //generate a random number between the specified values function ran(min, max) { return (Math.random() * (max - min) + min); } //generates a random color hex code function GenerateRandomColor() { return Math.floor(Math.random() * 16777215).toString(16); } //makes a new circle function GenerateNewCircle() { if (amountOfCirclesOnScreen < 1) { amountOfCirclesOnScreen++; const circleX = ran(0, maxCanvas.width); const circleY = ran(0, maxCanvas.height); const circleRadius = 50; // 保存圆形数据 currentCircle = { x: circleX, y: circleY, radius: circleRadius }; mainContext.beginPath(); mainContext.fillStyle = 'hsl(' + 360 * Math.random() + ', 100%, 50%)'; mainContext.arc(circleX, circleY, circleRadius, 0, 2 * Math.PI); mainContext.stroke(); mainContext.fill(); } } //clears the canvas function clearCanvas() { amountOfCirclesOnScreen = 0; currentCircle = null; // 清空圆形数据 mainContext.clearRect(0, 0, maxCanvas.width, maxCanvas.height); } //checks where u click function getMousePosition(event) { // 获取Canvas在页面中的位置偏移 const rect = cavna.getBoundingClientRect(); // 计算相对于Canvas左上角的坐标 const x = event.clientX - rect.left; const y = event.clientY - rect.top; // 检测是否命中圆形 if (currentCircle) { // 计算点击点到圆心的距离(勾股定理) const dx = x - currentCircle.x; const dy = y - currentCircle.y; const distance = Math.sqrt(dx * dx + dy * dy); // 距离小于等于半径则命中,清空画布并生成新圆 if (distance <= currentCircle.radius) { clearCanvas(); GenerateNewCircle(); } } } cavna.addEventListener("mousedown", function(e) { getMousePosition(e); }); GenerateNewCircle(); setInterval(() => { document.getElementById("counter").innerText = amountOfCirclesOnScreen; }, 40);
关键逻辑说明
- 存储圆形数据:必须保存每个圆形的圆心坐标和半径,否则无法进行后续的碰撞计算。
- 坐标转换:
event.clientX/Y是相对于浏览器视口的坐标,需要减去Canvas的页面偏移量,才能得到Canvas内部的正确坐标。 - 距离检测:使用勾股定理计算点击点到圆心的直线距离,若距离小于等于圆形半径,即判定为点击命中。
内容的提问来源于stack exchange,提问作者user22616583
相关产品推荐
相关产品推荐

