我正在构建原型工具来绘制简单的图表。
我需要在两个方框之间画一个箭头,问题是我必须找到两个方框的边缘,这样箭头线就不会与方框相交。
这是可视化我的问题的图纸:
如何找到x1,y1和x2,y2?
- 更新 -
找到解决方案2天后,这是一个例子&我使用的功能:
var box1 = { x:1,y:10,w:30,h:30 };
var box2 = { x:100,y:110,w:30,h:30 };
var edge1 = findBoxEdge(box1,box2,1,0);
var edge2 = findBoxEdge(box1,box2,2,0);
function findBoxEdge(box1,box2,box,distant) {
var c1 = box1.x + box1.w/2;
var d1 = box1.y + box1.h/2;
var c2 = box2.x + box2.w/2;
var d2 = box2.y + box2.h/2;
var w,h,delta_x,delta_y,s,c,e,ox,oy,d;
if (box == 1) {
w = box1.w/2;
h = box1.h/2;
} else {
w = box2.w/2;
h = box2.h/2;
}
if (box == 1) {
delta_x = c2-c1;
delta_y = d2-d1;
} else {
delta_x = c1-c2;
delta_y = d1-d2;
}
w+=5;
h+=5;
//intersection is on the top or bottom
if (w*Math.abs(delta_y) > h * Math.abs(delta_x)) {
if (delta_y > 0) {
s = [h*delta_x/delta_y,h];
c = "top";
}
else {
s = [-1*h*delta_x/delta_y,-1*h];
c = "bottom";
}
}
else {
//intersection is on the left or right
if (delta_x > 0) {
s = [w,w*delta_y/delta_x];
c = "right";
}
else {
s = [-1*w,-1*delta_y/delta_x];
c = "left";
}
}
if (typeof(distant) != "undefined") {
//for 2 paralel distant of 2e
e = distant;
if (delta_y == 0) ox = 0;
else ox = e*Math.sqrt(1+Math.pow(delta_x/delta_y,2))
if (delta_x == 0) oy = 0;
else oy = e*Math.sqrt(1+Math.pow(delta_y/delta_x,2))
if (delta_y != 0 && Math.abs(ox + h * (delta_x/delta_y)) <= w) {
d = [sgn(delta_y)*(ox + h * (delta_x/delta_y)),sgn(delta_y)*h];
}
else if (Math.abs(-1*oy + (w * delta_y/delta_x)) <= h) {
d = [sgn(delta_x)*w,sgn(delta_x)*(-1*oy + w * (delta_y/delta_x))];
}
if (delta_y != 0 && Math.abs(-1*ox+(h * (delta_x/delta_y))) <= w) {
d = [sgn(delta_y)*(-1*ox + h * (delta_x/delta_y)),sgn(delta_y)*h];
}
else if (Math.abs(oy + (w * delta_y/delta_x)) <= h) {
d = [sgn(delta_x)*w,sgn(delta_x)*(oy + w * (delta_y/delta_x))];
}
if (box == 1) {
return [Math.round(c1 +d[0]),Math.round(d1 +d[1]),c];
} else {
return [Math.round(c2 +d[0]),Math.round(d2 +d[1]),c];
}
} else {
if (box == 1) {
return [Math.round(c1 +s[0]),Math.round(d1 +s[1]),c];
} else {
return [Math.round(c2 +s[0]),Math.round(d2 +s[1]),c];
}
}
答案 0 :(得分:3)
tl;dr -> Look at the jsbin code-example
我们的目标是从两个矩形A&amp;的边缘画一条线。 B将通过他们的中心画出来。
因此,我们必须确定穿过Rect的边缘穿过的位置。
我们可以假设我们的Rect
是一个包含x
和y
的对象,偏离左上角,width
和height
作为维度偏移。
这可以通过以下代码完成。您应密切关注的方法是pointOnEdge
。
// starting with Point and Rectangle Types, as they ease calculation
var Point = function(x, y) {
return { x: x, y: y };
};
var Rect = function(x, y, w, h) {
return { x: x, y: y, width: w, height: h };
};
var isLeftOf = function(pt1, pt2) { return pt1.x < pt2.x; };
var isAbove = function(pt1, pt2) { return pt1.y < pt2.y; };
var centerOf = function(rect) {
return Point(
rect.x + rect.width / 2,
rect.y + rect.height / 2
);
};
var gradient = function(pt1, pt2) {
return (pt2.y - pt1.y) / (pt2.x - pt1.x);
};
var aspectRatio = function(rect) { return rect.height / rect.width; };
// now, this is where the fun takes place
var pointOnEdge = function(fromRect, toRect) {
var centerA = centerOf(fromRect),
centerB = centerOf(toRect),
// calculate the gradient from rectA to rectB
gradA2B = gradient(centerA, centerB),
// grab the aspectRatio of rectA
// as we want any dimensions to work with the script
aspectA = aspectRatio(fromRect),
// grab the half values, as they are used for the additional point
h05 = fromRect.width / 2,
w05 = fromRect.height / 2,
// the norm is the normalized gradient honoring the aspect Ratio of rectA
normA2B = Math.abs(gradA2B / aspectA),
// the additional point
add = Point(
// when the rectA is left of rectB we move right, else left
(isLeftOf(centerA, centerB) ? 1 : -1) * h05,
// when the rectA is below
(isAbove(centerA, centerB) ? 1 : -1) * w05
);
// norm values are absolute, thus we can compare whether they are
// greater or less than 1
if (normA2B < 1) {
// when they are less then 1 multiply the y component with the norm
add.y *= normA2B;
} else {
// otherwise divide the x component by the norm
add.x /= normA2B;
}
// this way we will stay on the edge with at least one component of the result
// while the other component is shifted towards the center
return Point(centerA.x + add.x, centerA.y + add.y);
};
我写了一个jsbin,你可以用一些盒子测试(下部,在ready方法中):
你可能想看看a little Geometry helper我前段时间在prototype.js
之上写的{{3}}我真的希望,这可以帮助你解决问题;)
答案 1 :(得分:1)
要在这些框之间画一条线,首先必须定义所需线的位置。
显然,您想要从Rect A的右边缘到左边缘绘制线条/箭头 Rect B,有点像这样:
假设您知道原点(左上Point
为Rect
的{x,y})及其Size
(宽度和高度),首先要确定位置边缘的中心:
var rectA, rectB; // I assume you have those data
var rectARightEdgeCenter = {
// x is simply the origin's x plus the width
x: rectA.origin.x + rectA.size.width,
// for y you need to add only half the height to origin.y
y: rectA.origin.y + rectA.size.height / 2.0
}
var rectBLeftEdgeCenter = {
// x will be simply the origin's x
x: rectB.origin.x,
// y is half the height added to the origin's y, just as before
y: rectB.origin.y + rectB.size.height / 2.0
}
更有趣的问题是如何确定,在更动态的场景中,您可能想要从哪条边缘到哪条边线绘制线条。
如果您的盒子从左到右堆积,给定的解决方案将适合, 但您可能需要检查边缘的最小距离,以确定可能的最佳箭头。