基于Paper.js实现简单图形上A、B两点间路径高亮的最优方案问询
在Paper.js中高效高亮图形上两点间路径的方法
针对不同类型的基础图形,我们可以利用它们的几何特性和Paper.js内置API直接计算目标路径,替代暴力追踪的低效方案,具体实现如下:
1. 直线(Line)
直线上的A、B两点本身构成线段,直接提取即可:
// 假设原直线为line,A、B为两个Point对象 const highlightPath = new Path.Line({ from: A, to: B, strokeColor: 'red', strokeWidth: 3 });
2. 圆形(Circle)
圆形上两点间有两条弧,按需选择短弧或长弧:
// 假设原圆形为circle,A、B为圆上的Point const center = circle.position; const radius = circle.radius; // 计算两点相对圆心的角度 const angleA = (A - center).getAngle(); const angleB = (B - center).getAngle(); // 创建弧路径(默认短弧,需长弧可添加{clockwise: false}参数) const highlightPath = new Path.Arc({ from: A, through: center.add(new Point({ length: radius, angle: (angleA + angleB)/2 })), to: B, strokeColor: 'red', strokeWidth: 3 });
3. 多边形(三角形、矩形等)
先定位A、B所在的边,再根据位置生成路径:
// 假设原多边形为polygon,A、B为多边形上的Point const segments = polygon.segments; let startIndex = -1, endIndex = -1; let startOffset = 0, endOffset = 0; // 遍历线段,找到A、B所在的边和偏移量 for (let i = 0; i < segments.length; i++) { const seg1 = segments[i]; const seg2 = segments[(i+1)%segments.length]; const line = new Path.Line(seg1.point, seg2.point); if (line.getDistance(A) < 0.1) { startIndex = i; startOffset = line.getLocationOf(A).offset; } if (line.getDistance(B) < 0.1) { endIndex = i; endOffset = line.getLocationOf(B).offset; } } const highlightPath = new Path(); // 两点在同一条边的情况 if (startIndex === endIndex) { const seg1 = segments[startIndex]; const seg2 = segments[(startIndex+1)%segments.length]; const line = new Path.Line(seg1.point, seg2.point); highlightPath.add(line.getPointAt(startOffset), line.getPointAt(endOffset)); } else { // 跨边情况,按顺序拼接路径片段 let i = startIndex; while (true) { const seg = segments[i]; const nextSeg = segments[(i+1)%segments.length]; if (i === startIndex) { highlightPath.add(A, nextSeg.point); } else if (i === endIndex) { highlightPath.add(seg.point, B); break; } else { highlightPath.add(seg.point, nextSeg.point); } i = (i+1)%segments.length; } } highlightPath.strokeColor = 'red'; highlightPath.strokeWidth = 3;
4. 椭圆(Ellipse)
通过椭圆参数方程转换坐标,生成精准弧路径:
// 假设原椭圆为ellipse,A、B为椭圆上的Point const center = ellipse.position; const size = ellipse.size; const rotation = ellipse.rotation; // 转换到椭圆局部坐标系 const localA = A.subtract(center).rotate(-rotation); const localB = B.subtract(center).rotate(-rotation); // 计算椭圆参数角度 const angleA = Math.atan2(localA.y / size.height * 2, localA.x / size.width * 2); const angleB = Math.atan2(localB.y / size.height * 2, localB.x / size.width * 2); // 生成弧路径 const highlightPath = new Path(); highlightPath.add(A); const step = 0.1; // 弧度步长,控制路径精度 let currentAngle = angleA; const direction = Math.sign(angleB - angleA); while (Math.abs(currentAngle - angleB) > step) { currentAngle += direction * step; // 转换回全局坐标系的点 const x = center.x + (size.width/2)*Math.cos(currentAngle)*Math.cos(rotation) - (size.height/2)*Math.sin(currentAngle)*Math.sin(rotation); const y = center.y + (size.width/2)*Math.cos(currentAngle)*Math.sin(rotation) + (size.height/2)*Math.sin(currentAngle)*Math.cos(rotation); highlightPath.add(new Point(x, y)); } highlightPath.add(B); highlightPath.strokeColor = 'red'; highlightPath.strokeWidth = 3;
内容的提问来源于stack exchange,提问作者nosuchoverflow
相关产品推荐
相关产品推荐

