I tried to understand this demo's work: http://raphaeljs.com/graffle.html But I cannot understand this loop in graffle.js source code:
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];
}
}
}
Can anybody explain to me what it does and how it works? Thanks.
Before this for loop, a single array is constructed, which contains the 4 positions for each object that the path can join from and to.
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}],
So you have 2 objects obj1 and obj2 that you want to join together with a path. The path has to be drawn to any one of the 4 possible points on the edge of the object:
Where I have labelled the vertices based on their index in p. Now we are going to loop over the points on obj1 and the points on obj2, using i for the index of the points on obj1 and j for the points on obj2. This way we test each point on obj1 against each point on obj2. What we are aiming to do is to measure (sort of) the distance between only those points which we find suitable for connecting.
// For each pair of adjacent points
for (var i = 0; i < 4; i++) {
for (var j = 4; j < 8; j++) {
// Calculate the difference in the X and Y direction (dy and dx)
var dx = Math.abs(p[i].x - p[j].x),
dy = Math.abs(p[i].y - p[j].y);
// If the points are on the same side OR
if ((i == j - 4) ||
// If the points are **not** opposites (3 and 6) or (2 and 7) or (0 and 5) or (1 and 4)
// or, if we have 3 and 6, and the obj1 is to the left side of obj2
// or, if we have 2 and 7, and the obj1 is to the right side of obj2
// or, if we have 0 and 5, and the obj1 is higher than obj2
// or, if we have 1 and 4, and the obj1 is lower than obj2
(((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))) {
// push the sum of dx and dy onto out distance list
// and push the associated pair of points onto the d list.
// This is so we can pick the sort-of-closest pair of points.
dis.push(dx + dy);
d[dis[dis.length - 1]] = [i, j];
}
}
}
So to break down that big if statement
IF
we have two points on the same side
(i == j - 4)
OR
we don't have 3 and 6, or if we do point 3 lies to the left of point 6
((i != 3 && j != 6) || p[i].x < p[j].x) &&
we don't have 2 and 7, or if we do point 2 lies to the right of point 6
((i != 2 && j != 7) || p[i].x > p[j].x) &&
we don't have 0 and 5, or if we do point 0 lies above point 5
((i != 0 && j != 5) || p[i].y > p[j].y) &&
we don't have 1 and 4, or if we do point 1 lies below point 4
((i != 1 && j != 4) || p[i].y < p[j].y)
THEN
If the points being tested are not one of these opposite pairs, then we measure it still. This is all to stop the path from being inside the 2 objects if we can help it. The first test to see if they are on the same side is a cheap way to skip all of this opposite testing code. After we have measured all of the points which are allowed, we pick the smallest dy+dx and use those points to draw the path.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With