在这个for循环之前,会构建一个包含每个对象路径可以连接的4个位置的单个数组。
var bb1 = obj1.getBBox(),
bb2 = obj2.getBBox(),
p = [{x: bb1.x + bb1.width / 2, y: bb1.y - 1},
{x: bb1.x + bb1.width / 2, y: bb1.y + bb1.height + 1},
{x: bb1.x - 1, y: bb1.y + bb1.height / 2},
{x: bb1.x + bb1.width + 1, y: bb1.y + bb1.height / 2},
{x: bb2.x + bb2.width / 2, y: bb2.y - 1},
{x: bb2.x + bb2.width / 2, y: bb2.y + bb2.height + 1},
{x: bb2.x - 1, y: bb2.y + bb2.height / 2},
{x: bb2.x + bb2.width + 1, y: bb2.y + bb2.height / 2}],
假设你有两个对象 obj1 和 obj2,你想用路径将它们连接在一起。路径必须绘制到对象边缘的四个可能点之一:
![path positions](https://istack.dev59.com/3VEAV.webp)
我已经根据它们在p中的索引标记了顶点。现在我们将循环遍历obj1上的点和obj2上的点,使用i表示obj1上的点的索引,使用j表示obj2上的点的索引。这样,我们测试每个obj1上的点与每个obj2上的点。我们的目标是仅测量适合连接的那些点之间的距离(有点像)。
for (var i = 0; i < 4; i++) {
for (var j = 4; j < 8; j++) {
var dx = Math.abs(p[i].x - p[j].x),
dy = Math.abs(p[i].y - p[j].y);
if ((i == j - 4) ||
(((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) {
dis.push(dx + dy);
d[dis[dis.length - 1]] = [i, j];
}
}
}
那么,为了分解这个大的if语句:
如果
或者
我们没有3和6,或者如果有,点3在点6的左边
((i != 3 && j != 6) || p[i].x < p[j].x) &&
我们没有2和7,或者如果有,点2在点6的右边
((i != 2 && j != 7) || p[i].x > p[j].x) &&
我们没有0和5,或者如果有,点0在点5的上面
((i != 0 && j != 5) || p[i].y > p[j].y) &&
我们没有1和4,或者如果有,点1在点4下面
((i != 1 && j != 4) || p[i].y < p[j].y)
那么
- 这条连接是有效的,在测量这些有效连接的距离(dy+dx)后将它们放入一个数组中。稍后我们将选择“最短”的距离。
![only if connections](https://istack.dev59.com/xDjBZ.webp)
如果被测试的点不是这些相对的一对,则我们仍然进行测量。这是为了防止路径在两个对象内部,如果可能的话。第一个测试以查看它们是否在同一侧是跳过所有这些相反测试代码的一种廉价方式。在我们测量了所有允许的点之后,我们选择最小的dy+dx并使用这些点绘制路径。