我需要检查两个SVG Path元素是否相交。检查边界框与.getBBox()
的交集是不准确的。
我目前正在做的是用.getTotalLength()
迭代两个路径,然后检查两个点.getPointAtLength()
是否相等。
下面是一个片段,但正如您所看到的,这非常慢并且会阻止浏览器选项卡。
必须有一种更有效的方法来检查两条路径之间的交叉点。
var path1 = document.getElementById("p1");
var path2 = document.getElementById("p2");
var time = document.getElementById("time");
var btn = document.getElementById("start");
btn.addEventListener("click", getIntersection);
function getIntersection() {
var start = Date.now();
for (var i = 0; i < path1.getTotalLength(); i++) {
for (var j = 0; j < path2.getTotalLength(); j++) {
var point1 = path1.getPointAtLength(i);
var point2 = path2.getPointAtLength(j);
if (pointIntersect(point1, point2)) {
var end = Date.now();
time.innerHTML = (end - start) / 1000 + "s";
return;
}
}
}
}
function pointIntersect(p1, p2) {
p1.x = Math.round(p1.x);
p1.y = Math.round(p1.y);
p2.x = Math.round(p2.x);
p2.y = Math.round(p2.y);
return p1.x === p2.x && p1.y === p2.y;
}
svg {
fill: none;
stroke: black;
}
#start {
border: 1px solid;
display: inline-block;
position: absolute;
}
<div id="start">Start
</div>
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 10 c 120 120 120 120 120 20 z" id="p1"></path>
<path d="M 150 10 c 120 120 120 120 120 20 z" id="p2"></path>
</svg>
<div id="time"></div>
答案 0 :(得分:1)
我不确定但如果你能从路径中提取矢量和曲线,那么可以用数学方法解决这个问题。但是,您可以通过缓存来自一条路径的点来优化您的功能,并减少对getTotalLength
和getPointAtLength
的调用次数。
function getIntersection() {
var start = Date.now(),
path1Length = path1.getTotalLength(),
path2Length = path2.getTotalLength(),
path2Points = [];
for (var j = 0; j < path2Length; j++) {
path2Points.push(path2.getPointAtLength(j));
}
for (var i = 0; i < path1Length; i++) {
var point1 = path1.getPointAtLength(i);
for (var j = 0; j < path2Points.length; j++) {
if (pointIntersect(point1, path2Points[j])) {
var end = Date.now();
time.innerHTML = (end - start) / 1000 + "s";
return;
}
}
}
}
这可以在0.07秒而不是4-5秒内计算示例路径。
答案 1 :(得分:1)
时间 0.027s
function getIntersection2() {
function Intersect(p1, p2) {
return p1.z!==p2.z && p1.x === p2.x && p1.y === p2.y;
}
var paths = [path1,path2];
var start = Date.now(),
pathLength = [path1.getTotalLength(),path2.getTotalLength()],
pathPoints = [],
inters = [];
for (var i = 0; i < 2; i++) {
for (var j = 0; j < pathLength[i]; j++) {
var p = paths[i].getPointAtLength(j);
p.z=i;
p.x=Math.round(p.x);
p.y=Math.round(p.y);
pathPoints.push(p);
}
}
pathPoints.sort((a,b)=>a.x!=b.x?a.x-b.x:a.y!=b.y?a.y-b.y:0)
// todos os pontos
.forEach((a,i,m)=>i&&Intersect(m[i-1],a)?inters.push([a.x,a.y]):0)
// somente o primeiro
//.some((a,i,m)=>i&&Intersect(m[i-1],a)?inters.push([a.x,a.y]):0);
result.innerHTML = inters;
var end = Date.now();
time.innerHTML = (end - start) / 1000 + "s";
return;
}
答案 2 :(得分:0)
您可以使用现有的库来执行此操作:https://github.com/signavio/svg-intersections
它以数学方式而不是迭代方式计算相交,因此在长路径下性能不应降低。