·悄然 - 2024-12-17 15:19
·悄然 - 2024-12-15 15:12
·悄然 - 2024-12-9 12:32
·飞飞 - 2024-12-9 12:31
·小希 - 2024-12-7 11:50
·飞飞 - 2024-12-5 15:53
·飞飞 - 2024-12-3 16:42
·悄然 - 2024-12-3 16:41
·飞飞 - 2024-12-1 18:27
判断不规则svg路径被点击点的路径长度
我们通过按像素遍历svg的path路径的长度,可以收集该路径上每一个像素点的XY坐标值,然后就可以在路径的点击事件中确定当前点击点在路径上离起点的距离。这个实现机制我们在曲线进度条播放器插件中已经投入使用,该插件没有开放自定义路径,是为了确保路径的每一个像素点的X坐标是不同的。但像下面的路径:
上面,红色直线与浅绿色路径存在三个交叉点,这三个点在路径上的X坐标一致、Y坐标不同,如果我们还是依据曲线进度条播放器插件所使用的方法去判断这三个点离路径起点的长度,显然行不通,我们需要额外的算法。
我们依然需要存储路径每一个像素的坐标点,不同于曲线进度条播放器插件,XY坐标值都存储到数组中去(设路径id为sPath):
let len = sPath.getTotalLength(); let posAr = []; for(j = 0; j < len; j ++) { posAr.push(sPath.getPointAtLength(j)); }
这样,当路径 sPath 被点击时,我们将被点击点的X坐标(ex)去和存储与数组中的路径上的X坐标(px)进行比对,二者值相等就将包括对应路径点的Y坐标减去被点击点的Y坐标和该点上的路径长度等信息一同保存在一个临时数组中,遍历完成后对临时数组进行处理,找到我们所需的路径上被点击点的长度。
sPath.onclick = (e) => { let yAr = []; //临时数组 let ex = Math.round(e.offsetX), ey = Math.round(e.offsetY); //被点击点XY坐标变量 for(j = 0; j < len; j ++) { let px = Math.round(posAr[j].x), /* 路径像素点数组中j像素长度的X坐标变量 */ py = Math.round(posAr[j].y); /* 路径像素点数组中j像素长度的Y坐标变量 */ if(px === ex) { //如果二者相等 let ar = [Math.abs(py - ey),j]; //构建一个数组元素,存储 py - ey 的绝对值和该路径点的像素长度j yAr.push(ar); //存入临时数组 } } //将临时数组交给自定义函数处理,得到被点击点的长度并计算占整个路径的百分比 let prg = getMinItem(yAr) / len * 100 + '%'; cap.style.setProperty('--prg', prg); //显示进度 };
自定义函数 getMinItem 则是这样:
let getMinItem = (ar) => { ar.sort((a,b) => a[0] - b[0]); return ar[0][1]; };
函数很简单,就是将传递过来的二维数组按数组元素的第一个数组元素进行升序排序,这样最小的排在前面,则它的第二个数组元素的值就是我们需要的路径被点击点离路径起点的长度。下面的二维数组样式,它们是排序后的结果,每一个数组元素的第一个数组元素是 py - ey 的绝对值,它有助于理解上面的描述:
[ [0,22], [1,38], [2,108], [142,156] ]
py-ey 的绝对值是我们判断被点击点是哪一点的依据,py是路径存储的 px=ex 那些点的Y坐标,px-py 值最小的那个就是我们点击的路径上的那个点。
效果如下:
评论列表 [1条]
#1 | 马黑 于 2023-9-23 00:07 发布: 这个不是完美方案,但已经相当不错了