马黑PHP整站系统

canvas画布判断鼠标指针是否在圆和矩形内

位置: 首页 > 前端三套件[ 发布时间: 2024.4.1  作者: 马黑  阅读: 245 ]

为了追求性能,canvas绘制的图像不具备DOM属性,图像不像HTML、svg的子节点那样可以直接进行点击交互。但很多应用场景需要与用户进行细致的交互,比如游戏、音视频播放控制器。谷歌非常重视对画布的应用,其浏览器正在尝试在画布上实现热点功能,所创建的热点API目前处于实验室阶段,需要Root权限方能使用,且非Chromium内核的浏览器尚未支持。所以,就目前而言,要在canvas画布上实现与用户的交互,需要自己解决。本文讨论如何在画布中判断鼠标指针是否在圆内和矩形内,这是一个简单的命题,静态情况下可以轻松实现。

我们先讨论矩形。

canvas画布是一个HTML标签,鼠标指针在其上活动时,我们可以通过 e.offsetX/Y 获取鼠标指针离画布左边缘、上边缘的偏移量,且因canvas画布没有子节点的干扰,e.offsetX/y 总是指向该画布,不会因受到子节点的干扰而产生混乱。而canvas画布在绘制矩形时,已知的数据有矩形的左上角(x,y)坐标、矩形的宽高。现在,已知条件共有六个:

鼠标指针在画布上偏移画布左边缘、上边缘的距离,记为 ① ex,② ey
矩形的左上角(x,y)坐标值,记为 ③ rx,④ ry
矩形的宽高,记为 ⑤ rw,⑥ rh

这六个已知条件足以让我们判断鼠标指针是否在矩形内,判断流程如下:

如果同时满足以下条件——

第一,ex >= rx
第二,ey >= ry
第三,ex <= rx + rw
第四,ey <= ry + rh

——那么,鼠标指针在矩形之内。

以上对矩形的判断流程应该是好理解的。圆略为复杂一点儿,我们接着来讨论处理方法。这个需要用到勾股定理:圆心已知,xy坐标值分别记作 cx 和 cy,半径已知,记作 r 。设鼠标指针所在点 A 是圆内或圆外的任意一个点,xy坐标值分别记作 ex 和 ey。现在,画 OA 连线,即从圆心 O(cx,cy)画连线到 A(ex,ey),再从 O 出发画指向三点钟方向的水平线 OX,最后从 A 点出发画垂直于 OX 的直线 OQ,OQ 与 OX 相交于 B 点。那么,三角形 OAB 是一个直角三角形,因此,AB2 + OB2 = OA2,此时,我们只需判断 OA 是否大于圆的半径便可。这就简单了,因为三角形的每一个点坐标都是已知的条件—— B 的坐标点,x 为 A 的 ex, y 为圆心 O 的 cy。看下面的推导:

点击点 A 的坐标 :ex, ey
圆心 O 坐标 :cx, cy
B 坐标: ex, cy

OB = ex - cx
AB = ey - cy
OA2 = AB2 + OB2 → OA2 = (ey - cy)2 + (ex - cx)2

拿到点击点到圆心的距离OA,然后和圆的半径 r 比较,问题解决。

下面的演示是根据以上推导逻辑实现,点击画布任意地方,示例均在信息框显示点击处:

点哪儿:尚未点击

示例完整代码:

<script>   let ctx = canv.getContext('2d'); ctx.fillStyle = 'tan'; ctx.strokeStyle = 'gray'; //画圆函数 let drawCircle = (cx,cy,r) => {     ctx.save();     ctx.beginPath();     ctx.arc(cx, cy, r, 0, 360 * Math.PI/180);     ctx.fill();     ctx.restore(); }; //画矩形函数 let drawRect = (x,y,w,h) => {     ctx.save();     ctx.fillRect(x,y,w,h);     ctx.restore(); }; //判断是否在圆内函数 let innerCircle = (ex,ey,cx,cy,r) => Math.sqrt((ex - cx) ** 2 + (ey - cy) ** 2) <= r; //判断是否在矩形内函数 let innerRect = (ex,ey,rx,ry,rw,rh) => ex > rx && ey >= ry && ex <= rx + rw && ey < ry + rh; drawCircle(100, 100, 50); //画圆 drawRect(240, 90, 120, 60); //画矩形 //鼠标点击画布事件 canv.onclick = (e) => {     let msg = innerCircle(e.offsetX, e.offsetY, 100, 100, 50)         ? '圆内'         : innerRect(e.offsetX, e.offsetY, 240, 90, 120, 60) ? '矩形内' : '画布空白处'     ;     clickMsg.innerText = '点哪儿:' + msg; };   </script>

前一篇: 如何在canvas画布中旋转图像
下一篇: CSS+JS实现单图片模拟背景循环无缝滚动

发表评论:

       

评论列表 [1条]

#1 | 悄然 于 2024-4-1 12:53 发布: 这个太智能了。。原来只会想着,呀,这个演示好聪明啊。。点哪里它显示哪里。。现在老师一步步揭示智能背后原来有这么大量而严谨的计算~~。数理化好重要。。。^_^

Copyright © 2023 All Right Reserved 马黑PHP文章管理整站系统v1.8
联系我们: gxblk@163.com