I am trying to generate a group where some elements should stick at their same size AND position (as seen from the groups's edgs).
I figured the size issue. However, I am failing to get a fully working solution for keeping the positions the same. Here is my current approach:
http://jsfiddle.net/on7kujhs/111/
let originalX = e.originalLeft + e.width / 2, // my true left of my center, relative to group
percentageX = 0.5 + originalX / target.width, // how much I will change my position in percent. zero if originalX is exactly the same as half the width, one if im at right edge
totalChangeX = (target.scaleX - 1) * target.width / 2, // how much the center shifts
myMovX = percentageX * totalChangeX; // how much I moved to the right
if (e.groupedScaleOriginX === 'left') {
e.left = e.originalLeft - myMovX;
} else if (e.groupedScaleOriginX === 'right') {
e.left = e.originalLeft + totalChangeX * (1 - percentageX);
}
I think I figured it out.
http://jsfiddle.net/y3o7Lwn6/27/
The key is saving all objects positions relative to the groups borders and modifying them on scaling, as well as saving the true top/left positions relative to the groups top left border:
let dX = (tr.scaleX - 1) / tr.scaleX;
let dY = (tr.scaleY - 1) / tr.scaleY;
if (e.groupedScaleOriginX == 'left') {
e.left = e.originalLeft - dX * e.trueLeft;
} else if (e.groupedScaleOriginX == 'right') {
e.left = e.originalLeft - dX * e.trueRight;
}
if (e.groupedScaleOriginY == 'top') {
e.top = e.originalTop - dY * e.trueTop;
} else if (e.groupedScaleOriginY == 'bottom') {
e.top = e.originalTop - dY * e.trueBottom;
}
Related
Writing a pure JS tooltip library and have made it work really, really well. No big bells and whistles, just a super lightweight super utilitarian easy-to-customize tooltip. That said, I'm having an issue with updating the position; specifically when the tooltip is detected to be out of bounds.
And it works! It does. Issue is that when I'm hovered over the target element, which is against the right side of the page which causes the tooltip to be out of bounds, it will flicker between the default bottom-right position and the correct bottom-left position. Upon further inspection, it seems to only register out of bounds on every other hair I move the cursor. For instance, when I enter the element, it will display properly; move the cursor a hair in any direction and it will seemingly reset to bottom-right, not seeing that it's out of bounds. Move it one hair further and it will figure out it's out of bounds again, correcting itself to bottom-left. I'm not sure what assumptions to make here, but I'll let you guys be the judge of it.
updateTooltip(event) {
const mouseX = event.pageX,
mouseY = event.pageY;
const adjustment = 15;
let position = (this.element.getAttribute(this.selector + '-pos') || '').split(' ');
if (position.length !== 2) position = [ 'bottom', 'right' ];
var isOut = this.checkBounds();
if (isOut.top) { position[0] = 'bottom'; }
if (isOut.left) { position[1] = 'right'; }
if (isOut.bottom) { position[0] = 'top'; }
if (isOut.right) { position[1] = 'left'; }
let vertical, horizontal;
switch (position[0]) {
case 'top':
vertical = -adjustment - this.tooltip.offsetHeight;
break;
case 'center':
vertical = 0 - (this.tooltip.offsetHeight / 2);
break;
default:
vertical = adjustment;
}
switch (position[1]) {
case 'left':
horizontal = -adjustment - this.tooltip.offsetWidth;
break;
case 'center':
horizontal = 0 - (this.tooltip.offsetWidth / 2);
break;
default:
horizontal = adjustment;
}
this.tooltip.style.top = mouseY + vertical + 'px';
this.tooltip.style.left = mouseX + horizontal + 'px';
}
checkBounds() {
if (!this.tooltip) return;
const bounds = this.tooltip.getBoundingClientRect();
let out = {};
out.top = bounds.top < 0;
out.left = bounds.left < 0;
out.bottom = bounds.bottom > (window.innerHeight || document.documentElement.clientHeight);
out.right = bounds.right > (window.innerWidth || document.documentElement.clientWidth);
out.any = out.top || out.left || out.bottom || out.right;
out.all = out.top && out.left && out.bottom && out.right;
return out;
}
i want to move an div to 70% left and 10% top of my viewport when i scroll. My Code for that is here:
Flower.prototype.animateToKeyframe = function() {
var scroll = window.pageYOffset / window.innerHeight * 100;
// check if next keyframe needs to be loaded
if (!this.animationDone) {
// var formula = (this.initialPos.top - this.keyframe['top'] * percentHeight) / (this.initialPos.left - this.keyframe['left'] * percentWidth) * (scroll * 5);
/*
* Animating top position
*/
if (this.pos.top > percentHeight * this.keyframe['top']) {
this.domEl.css('top', (this.initialPos.top - (scroll * this.speed)) + 'px');
} else if (this.pos.top < percentHeight * this.keyframe['top']) {
this.domEl.css('top', (this.initialPos.top + (scroll * this.speed)) + 'px');
}
/*
* Animating left position
*/
if (this.pos.left < percentWidth * this.keyframe['left']) {
this.domEl.css('left', (this.initialPos.left + (scroll * this.speed)) + 'px');
} else if (this.pos.left > percentWidth * this.keyframe['left']) {
this.domEl.css('left', (this.initialPos.left - (scroll * this.speed)) + 'px');
}
/*
* Animating rotation
*/
this.domEl.css('transform', 'rotateZ(' + (this.rotation + (scroll * this.speed)) + 'deg)');
this.domEl.css('-webkit-transform', 'rotateZ(' + (this.rotation + (scroll * this.speed)) + 'deg)');
/*
* updating and checking position
*/
this.pos = this.domEl.position();
var leftDone = this.pos.left > (percentWidth * this.keyframe['left'] - 5) && this.pos.left < (percentWidth * this.keyframe['left'] + 5);
var topDone = this.pos.top > (percentHeight * this.keyframe['top'] - 5) && this.pos.top < (percentHeight * this.keyframe['top'] + 5);
if (topDone && leftDone) {
alert('fertig!' + this.num);
this.animationDone = true;
}
} else {
this.getKeyframe();
}
this.keyframe is an object: {left: 70, top: 10, rotation: 100}. But when i scroll, the element is moving along the x and y axis equally. However i want both css-styles to move that way that they both reach the target (this.keyframe) at the same time. Otherwise it arrives first on the y-axis and later on the x-axis.
I tried to realize that with linear equation as you can see here:
// var formula = (this.initialPos.top - this.keyframe['top'] * percentHeight) / (this.initialPos.left - this.keyframe['left'] * percentWidth) * (scroll * 5);
However i can't put that into the code changing the top position AND the left position because it would move equally again then.
Do you have any Idea for me?
It's not the same effect - the movement is not linear - but when I have to move an object to a target position, I use continuous linear interpolation, like:
for( ;; /* every frame */ ) {
if( Math.abs( current.x - target.x ) < 0.1 ) {
done();
} else {
current.x = current.x * 0.9 + target.x * 0.1;
current.y = current.y * 0.9 + target.y * 0.1;
current.a = current.a * 0.9 + target.a * 0.1;
}
}
It will reach the destination at the same time on both axes.
If you still want linear movement, your approach is ok, but you have to calculate the speed for every variable (every axis).
I did this with lerp-ing now. Thanks however!
var stopPosition = (1 / this.keyframe['stop'] * scroll) - (this.keyframeIndex - 1);
// lerp-ing through position animation
var formulaX = this.initialPos.left + stopPosition * (xTarget - this.initialPos.left);
var formulaY = this.initialPos.top + stopPosition * (yTarget - this.initialPos.top);
/*
* Animating positions
*/
this.domEl.css('top', (formulaY) + 'px');
this.domEl.css('left', (formulaX) + 'px');
I managed to manipulate Fabric.js to add a snap and scale to grid functionality by:
var grid = 100;
//Snap to Grid
canvas.on('object:moving', function (options) {
options.target.set({
left: Math.round(options.target.left / grid) * grid,
top: Math.round(options.target.top / grid) * grid
});
});
canvas.on('object:scaling', function (options) {
options.target.set({
left: Math.round(options.target.left / grid) * grid,
top: Math.round(options.target.top / grid) * grid
});
});
Now I want to add snap to objects functionality. My idea was to check intersection of two objects and then lock somehow the movement. I know its not the best attempt, but at least it snaps to it, but does not allow to move the object away anymore. And: right now it is not implemented well. See: http://jsfiddle.net/gcollect/y9kyq/
I have three issues:
The "snap" doesn't work well, because the object left attribute depends on the pointer somehow. Replication by dragging object and watching my controls output. For example when moving the red rectangle to position left:62, the rectangle isn't intersected with the blue rectangle and can still moved away. How can I reload the actual left value of the rectangle. Because of my snap to grid lines, it is at left:100 and not at left:62.
Any idea how I can add a snap to object functionality? And prohibit intersection?
How can I check this for n objects and not only for two?
Thanks for your comments.
PS:
The jsfiddle example doesn't show the scale to grid functionality, because it needed Fabric.js manipulation in line: 11100
var distroundedforgrid = Math.round(dist/100)*100;
transform.newScaleX = Math.round((transform.original.scaleX * distroundedforgrid / lastDist)*10)/10;
transform.newScaleY = Math.round((transform.original.scaleY * distroundedforgrid / lastDist)*10)/10;
target.set('scaleX', transform.newScaleX);
target.set('scaleY', transform.newScaleY);
}
For those who are still interested in the solution:
I solved it here: https://stackoverflow.com/a/22649022/3207478
See jsfiddle: http://jsfiddle.net/gcollect/FD53A/
Working with .oCoords.tl .tr .bl. and .br solved it.
For rescaling based on the grid see this JSfiddle
function snapScaling(options) {
var target = options.target;
var type = canvas.getActiveObject().get('type');
var corner = target.__corner;
var w = target.getWidth();
var h = target.getHeight();
var snap = { // Closest snapping points
top: Math.round(target.top / grid) * grid,
left: Math.round(target.left / grid) * grid,
bottom: Math.round((target.top + h) / grid) * grid,
right: Math.round((target.left + w) / grid) * grid,
};
snap.height = snap.top - snap.bottom;
if(snap.height < 0) {
snap.height *= - 1;
}
snap.width = snap.left - snap.right;
if(snap.width < 0) {
snap.width *= - 1;
}
switch (corner) {
case 'mt':
case 'mb':
target.top = snap.top;
target.height = snap.height;
target.scaleY = 1;
break;
case 'ml':
case 'mr':
target.left = snap.left;
target.width = snap.width;
target.scaleX = 1;
break;
case 'tl':
case 'bl':
case 'tr':
case 'br':
target.top = snap.top;
target.left = snap.left;
target.height = snap.height;
target.width = snap.width;
target.scaleY = 1;
target.scaleX = 1;
}
if(type == 'ellipse') {
target.rx = (target.width / 2);
target.ry = (target.height / 2);
}
}
I figured it out to solve the snap to objects on x-axis and will work on a solution for the y-axis. See JSfiddle here.
I did this by setting a new "left"-value for the active object, when I detect an intersection.
if (options.target.isContainedWithinObject(obj)||options.target.intersectsWithObject(obj)||obj.isContainedWithinObject(options.target)) {
var distx = ((obj.left + obj.width)/2) - ((options.target.left + options.target.width)/2);
var disty = ((obj.top + obj.height)/2) - ((options.target.top + options.target.height)/2);
if (distx > 0){
options.target.left = obj.left - options.target.width;
} else {
options.target.left = obj.left + obj.width;
}
}
I have a web app where I would like the user to draw a line in the following way: When he clicks on Point1 and he moves the mouse, draw the line from Point1 to the current mouse position and, when clicks to Point2 draw the final line from Point1 to Point2.
How can I do it using jQuery and/or one of its plugins?
Challenge accepted.
I tried to do it with CSS transforms and a bunch of Math in Javascript - after half an hour I have this:
http://jsfiddle.net/VnDrb/2/
Make 2 clicks into the gray square and a line should be drawn.
There is still a small bug that draws the line wrong when the angle is > 45 degree. Maybe someone else knows how to fix that. Maybe instead of using Math.asin (arcsinus), use a other trigonometrical function, but I'm really not good at it.
I thought I'd post it even there is a small bug, I think it's a good start for you.
I've tried a number of different approaches this weekend and the solution that worked best for me is from Adam Sanderson: http://monkeyandcrow.com/blog/drawing_lines_with_css3/
His demo is here: http://monkeyandcrow.com/samples/css_lines/
The core of it is very simple, which is always good.
div.line{
transform-origin: 0 100%;
height: 3px; /* Line width of 3 */
background: #000; /* Black fill */
}
function createLine(x1,y1, x2,y2){
var length = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
var transform = 'rotate('+angle+'deg)';
var line = $('<div>')
.appendTo('#page')
.addClass('line')
.css({
'position': 'absolute',
'transform': transform
})
.width(length)
.offset({left: x1, top: y1});
return line;
}
You can not do it with jQuery and classic HTML.
You can do it using SVG (+svgweb for IE8- http://code.google.com/p/svgweb/ )
SVG can be dynamically created. jQuery + svgweb are working perfectly, you just need to know how to create SVG nodes and you need only jquerify this nodes. After jquerifiing in most cases used only one method attr()
You can do it using Raphael http://raphaeljs.com/ (based on SVG and VML)
You can do it using Canvas ( http://flashcanvas.net/ for IE8- )
For SVG programming will be this way:
Moment of creating first point: you create empty line var Line (also this points coordinates will be x1 and y1)
Then you bind on mousemove repaint of x2, y2 properties of Line
On mousedown after mousemove you freeze last line position.
UPDATE
You can do it with CSS/JS, but main problem is in calculations for IE8-, that has only Matrix filter for transformations.
Been using a modified version of this for a while now. Works well.
http://www.ofdream.com/code/css/xline2.php
So on first click, drop and object there as a placeholder div, maybe a little circle, then either keep redrawing a line as they move their mouse, or draw it when they click the second time, using the original placeholder as a guide.
I recently made another helper function for this, because my tool involves moving lines around:
function setLinePos(x1, y1, x2, y2, id) {
if (x2 < x1) {
var temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
}
var line = $('#line' + id);
var length = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
line.css('width', length + "px");
var angle = Math.atan((y2 - y1) / (x2 - x1));
line.css('top', y1 + 0.5 * length * Math.sin(angle) + "px");
line.css('left', x1 - 0.5 * length * (1 - Math.cos(angle)) + "px");
line.css('-moz-transform', "rotate(" + angle + "rad)");
line.css('-webkit-transform', "rotate(" + angle + "rad)");
line.css('-o-transform', "rotate(" + angle + "rad)");
}
That is the jquery version, and in this iteration I have no IE requirement so I ignore it. I could be adapted from the original function pretty easily.
The class
function getXY(evt, element) {
var rect = element.getBoundingClientRect();
var scrollTop = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft;
var elementLeft = rect.left + scrollLeft;
var elementTop = rect.top + scrollTop;
x = evt.pageX - elementLeft;
y = evt.pageY - elementTop;
return { x: x, y: y };
}
var LineDrawer = {
LineHTML: `<div style="cursor: pointer;transform-origin:center; position:absolute;width:200px;height:2px; background-color:blue"></div>`,
isDown: false,
pStart: {},
pCurrent :{},
containerID: "",
JLine: {},
angle: 0,
afterLineCallback: null,
Init: function (containerID, afterLineCallback) {
LineDrawer.containerID = containerID;
LineDrawer.afterLineCallback = afterLineCallback;
LineDrawer.JLine = $(LineDrawer.LineHTML).appendTo("#" + LineDrawer.containerID);
LineDrawer.JLine.css("transform-origin", "top left");
LineDrawer.JLine.hide();
//LineDrawer.JLine.draggable({ containment: "#" + LineDrawer.containerID });
$("#" + LineDrawer.containerID).mousedown(LineDrawer.LineDrawer_mousedown);
$("#" + LineDrawer.containerID).mousemove(LineDrawer.LineDrawer_mousemove);
$("#" + LineDrawer.containerID).mouseup(LineDrawer.LineDrawer_mouseup);
},
LineDrawer_mousedown: function (e) {
if (e.target === LineDrawer.JLine[0]) return false;
LineDrawer.isDown = true;
let p = LineDrawer.pStart = getXY(e, e.target);
LineDrawer.JLine.css({ "left": p.x, "top": p.y, "width": 1});
LineDrawer.JLine.show();
},
LineDrawer_mousemove: function (e) {
if (!LineDrawer.isDown) return;
LineDrawer.pCurrent = getXY(e, document.getElementById("jim"));
let w = Math.sqrt(((LineDrawer.pStart.x - LineDrawer.pCurrent.x) * (LineDrawer.pStart.x - LineDrawer.pCurrent.x)) + ((LineDrawer.pStart.y - LineDrawer.pCurrent.y) * (LineDrawer.pStart.y - LineDrawer.pCurrent.y)));
LineDrawer.JLine.css("width", w - 2);
LineDrawer.angle = Math.atan2((LineDrawer.pStart.y - LineDrawer.pCurrent.y), (LineDrawer.pStart.x - LineDrawer.pCurrent.x)) * (180.0 / Math.PI);
//the below ensures that angle moves from 0 to -360
if (LineDrawer.angle < 0) {
LineDrawer.angle *= -1;
LineDrawer.angle += 180;
}
else LineDrawer.angle = 180 - LineDrawer.angle;
LineDrawer.angle *= -1;
LineDrawer.JLine.css("transform", "rotate(" + LineDrawer.angle + "deg");
},
LineDrawer_mouseup: function (e) {
LineDrawer.isDown = false;
if (LineDrawer.afterLineCallback == null || LineDrawer.afterLineCallback == undefined) return;
LineDrawer.afterLine(LineDrawer.angle, LineDrawer.pStart, LineDrawer.pCurrent);
},
};
Usage:
var ECApp = {
start_action: function () {
LineDrawer.Init("jim", ECApp.afterLine);
},
afterLine(angle, pStart, pEnd) {
//$("#angle").text("angle : " + angle);
let disp = "angle = " + angle;
disp += " Start = " + JSON.stringify(pStart) + " End = " + JSON.stringify(pEnd);
//alert(disp);
$("#angle").text("angle : " + disp);
}
}
$(document).ready(ECApp.start_action);
HTML
<div class="row">
<div class="col">
<div id="jim" style="position:relative;width:1200px;height:800px;background-color:lightblue;">
</div>
</div>
I am building prototype tool to draw simple diagrams.
I need to draw an arrow between two boxes, the problem is i have to find edges of two boxes so that the arrow line does not intersect with the box.
This is the drawing that visualize my problem:
How to find x1,y1 and x2,y2 ?
-- UPDATE --
After 2 days finding solution, this is example & function that i use:
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];
}
}
tl;dr -> Look at the jsbin code-example
It is our goal to draw a line from the edges of two Rectangles A & B that would be drawn through their centers.
Therefore we'll have to determine where the line pierces through the edge of a Rect.
We can assume that our Rect is an object containing x and y as offset from the upper left edge and width and height as dimension offset.
This can be done by the following code. The Method you should look at closely is 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);
};
I wrote a jsbin, you can use to test with some boxes (lower part, in the ready method):
You might want to take a look at a little Geometry helper I wrote some time ago on top of prototype.js
I really hope, that this helps you with your problem ;)
To draw a line between those boxes, you'd first have to define where you want the line to be.
Apparently you want to draw the lines/arrows from the right edge of Rect A to the left edge of
Rect B, somewhat like this:
Assuming your know the origin (upper left Point as { x, y } of a Rect) and its Size (width and height), you first want to determine the position of the center of the edges:
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
}
The more interesting question would be how to determine, from which edge to which other edge you might want to draw the lines in a more dynamic scenario.
If your boxes just pile up from left to right the given solution will fit,
but you might want to check for minimum distances of the edges, to determine a possible best arrow.