|
|
请马上登录,朋友们都在花潮里等着你哦:)
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 马黑黑 于 2022-9-6 21:27 编辑
在svg中检测鼠标指针经过圆与圆环 | 马黑黑
我们在《在svg中检测鼠标指针经过圆》帖子中,解决了对鼠标指针滑过圆的监测问题,在此基础上,我们可以实现对圆环的检测。
svg的圆环同样用 circle 指令绘制。试比较如下画圆的语句,第一句画的是圆(前文绘制,用 fill 方法上色),第二句画的是圆环:
<circle cx="100" cy="100" r="50" fill="lightblue" />
<circle cx="100" cy="100" r="50" fill="none" stroke-width="10" stroke="lightblue" />
绘制圆环,如果不设置 fill="none",则圆环之内会用默认颜色填充环内的内圆。绘制圆环同时应定义环的厚度 stroke-width 和描边的颜色 stroke,这样便可以在 svg 中画出漂亮的圆环。
以上只是做圆和圆环画法的比较。我们重新开启炉灶,单纯绘制圆环,并给圆环一个 id 以便后续工作可以对它进行操作,我们还添加一个 text 标签,用以记录鼠标指针的位置信息,帮助我们测试效果:
<svg id="sc" width="200" height="200" style="background: gray">
<circle id="track" cx="100" cy="100" r="50" fill="none" stroke-width="10" stroke="lightblue" />
<text id="movemsg" x="10" y="30" fill="white">位置信息</text>
</svg>
这里,与前文的圆相比,圆环的圆心、半径与之一致,但有一个 10 像素的 stroke-width 值(环的厚度),情形还是发生了变化,不过我们之前根据勾股定理编写的检测函数依然可以用上:
function isCircle(cx, cy, r, ex, ey) {
return Math.pow(ex - cx, 2) + Math.pow(ey - cy, 2) <= Math.pow(r, 2);
}
它依然是我们检测鼠标指针是否经过圆的工具函数,我们要处理的是调用时参数带入的问题。设想是,将圆环视为两个圆:包含圆环在内的圆是大圆,不包含圆环的、被圆环包裹的内圆是小圆,则,如果鼠标指针在大圆之内,再检测鼠标指针是否在小圆内,如果在,就可以获知鼠标指针不在环内,否则鼠标指针在环内。
这样的话,剩下的工作就是弄清大圆和小圆的半径了。stroke-width 值为 10,它就是环的厚度,经检测发现,环的一半往圆外扩展,另一半往圆内伸展,也就是环在 fill 绘制的圆的内外都要一半的地盘。这样,我们就可以确定大圆的半径为 r + stroke-width / 2,小圆的半径为 r - stroke-width / 2,这就OK了。为了调用便捷也为了可能需要的通用性,我们需要建立一个实例化对象,用以装载圆心坐标、半径、环厚度等值,js内置的 element.getAttribute() 方法可以帮助我们获取这些值:
let cc = {
x: 1*track.getAttribute('cx'),
y: 1*track.getAttribute('cy'),
r: 1*track.getAttribute('r'),
sw: 1*track.getAttribute('stroke-width'),
};
track 是我们前面画的圆,我们用 getAttribute() 方法分别获取了圆的圆心坐标、半径和厚度。这些值都乘以 1 的作用在于确保所得到的值均为数值型类型,因为 element.getAttribute() 方法提供的值是字符串类型。下一步,也是最后一步,就是检测 svg 画布 sc 的鼠标经过
sc.onmousemove = (e) => {
if(isCircle(cc.x, cc.y, cc.r + cc.sw/2, e.offsetX, e.offsetY)) { //环及环内的圆
sc.style.cursor = 'pointer';
if(isCircle(cc.x, cc.y, cc.r - cc.sw/2, e.offsetX, e.offsetY)) {
movemsg.textContent = '内圆';
} else {
movemsg.textContent = '环';
}
} else { //环外区域
sc.style.cursor = 'default';
movemsg.textContent = '环外'
}
}
附完整代码:
- <svg id="sc" width="200" height="200" style="background: gray">
- <circle id="track" cx="100" cy="100" r="50" fill="none" stroke-width="10" stroke="lightblue" />
- <text id="movemsg" x="10" y="30" fill="white">位置信息</text>
- </svg>
- <script>
- let cc = {
- x: 1*track.getAttribute('cx'),
- y: 1*track.getAttribute('cy'),
- r: 1*track.getAttribute('r'),
- sw: 1*track.getAttribute('stroke-width'),
- };
- sc.onmousemove = (e) => {
- if(isCircle(cc.x, cc.y, cc.r + cc.sw/2, e.offsetX, e.offsetY)) { //环及环内的圆
- sc.style.cursor = 'pointer';
- if(isCircle(cc.x, cc.y, cc.r - cc.sw/2, e.offsetX, e.offsetY)) {
- movemsg.textContent = '内圆';
- } else {
- movemsg.textContent = '环';
- }
- } else { //环外区域
- sc.style.cursor = 'default';
- movemsg.textContent = '环外'
- }
- }
- function isCircle(cx, cy, r, ex, ey) {
- return Math.pow(ex - cx, 2) + Math.pow(ey - cy, 2) <= Math.pow(r, 2);
- }
- </script>
复制代码
|
评分
-
| 参与人数 2 | 威望 +80 |
金钱 +160 |
经验 +80 |
收起
理由
|
加林森
| + 30 |
+ 60 |
+ 30 |
很给力! |
红影
| + 50 |
+ 100 |
+ 50 |
赞一个! |
查看全部评分
|