40

I'm currently trying to draw a diagonal line between the bottom right corner of one div to the top right corner of another. If possible, I would like to do it without jQuery. Is this possible?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • What browsers do you want to support? Where are these divs positioned in relation to one another? – gilly3 Dec 29 '11 at 19:29
  • do you any specific issues you are having trouble with? if not, I'll refer you to http://stackoverflow.com/questions/6278152/drawing-a-line-between-two-draggable-divs which seems like the same question with the addition of draggable elements, which you can ignore. – lincolnk Dec 29 '11 at 19:50
  • 1
    Use SVG to draw lines ... It is much easier ... http://stackoverflow.com/a/35493651/5947203 – Ani Feb 07 '17 at 16:43
  • Possible duplicate of [Drawing a line between two divs](https://stackoverflow.com/questions/6278152/drawing-a-line-between-two-divs) – balupton Nov 05 '18 at 21:02

2 Answers2

68

http://jsfiddle.net/cnmsc1tm/

This won't work with IE8 or below because of CSS limitations.

function getOffset( el ) {
    var rect = el.getBoundingClientRect();
    return {
        left: rect.left + window.pageXOffset,
        top: rect.top + window.pageYOffset,
        width: rect.width || el.offsetWidth,
        height: rect.height || el.offsetHeight
    };
}

function connect(div1, div2, color, thickness) { // draw a line connecting elements
    var off1 = getOffset(div1);
    var off2 = getOffset(div2);
    // bottom right
    var x1 = off1.left + off1.width;
    var y1 = off1.top + off1.height;
    // top right
    var x2 = off2.left + off2.width;
    var y2 = off2.top;
    // distance
    var length = Math.sqrt(((x2-x1) * (x2-x1)) + ((y2-y1) * (y2-y1)));
    // center
    var cx = ((x1 + x2) / 2) - (length / 2);
    var cy = ((y1 + y2) / 2) - (thickness / 2);
    // angle
    var angle = Math.atan2((y1-y2),(x1-x2))*(180/Math.PI);
    // make hr
    var htmlLine = "<div style='padding:0px; margin:0px; height:" + thickness + "px; background-color:" + color + "; line-height:1px; position:absolute; left:" + cx + "px; top:" + cy + "px; width:" + length + "px; -moz-transform:rotate(" + angle + "deg); -webkit-transform:rotate(" + angle + "deg); -o-transform:rotate(" + angle + "deg); -ms-transform:rotate(" + angle + "deg); transform:rotate(" + angle + "deg);' />";
    //
    // alert(htmlLine);
    document.body.innerHTML += htmlLine;
}
  • The Distance Formula
  • Finding the Center Of Two Points
  • Finding the Angle Between Two Points
  • CSS Transform:Rotate
  • HTML Element offset[Width|Height|Top|Left] properties

Edit (for others with the same problem):

If you need to, for example, create a line from two corners that are not the top right and bottom right divs, go to this section of the code:

// bottom right
var x1 = off1.left + off1.width;
var y1 = off1.top + off1.height;
// top right
var x2 = off2.left + off2.width;
var y2 = off2.top;

where you see + off1.width and + off1.height, that means that the code is calculating the position of the bottom or the right of the div. Remove the + off1.width or the + off1.height to get the left or the top of the div.

EDIT updated to a more standard getOffset function. If you want to get really anal you'd probably also have to add document.documentElement.client[Left/Top] and walk the offsetParent tree, but I think getBoundingClientRect() and window.page[X/Y]Offset are sufficient for an example like this.

Louis Ricci
  • 20,804
  • 5
  • 48
  • 62
  • 1
    that's a neat solution to avoid libraries completely, although it's too bad it won't work in IE. – lincolnk Dec 29 '11 at 21:07
  • 1
    The getOffset function seems to be flawed as it didn't work in with a bunch of overlapping absolutely positioned divs. I replaced get offset with the jQuery offset/height/width functions and this worked. return { top: $(el).offset().top, left:$(el).offset().left, width: $(el).width(), height: $(el).height() }; – William Neely Sep 04 '14 at 16:15
  • Awasome answer thanks. Note if you are using jQuery, $("body").append(htmlLine) should be used instead of "document.body.innerHTML += htmlLine;" at the end of the function to avoid canvas issues (like with flot). – jpaoletti Sep 01 '16 at 15:04
  • @louisricci thanks for the post and sharing your calc function. I would love to adopt it for my project, but whenever I try to call `connect()` I receive an error: `el.getBoundingClientRect() is not a function`. Can you help me out? – Marian Rick Jan 07 '17 at 12:33
  • @MarianRick - Use the JSFiddle link at the top of the answer and look at how the *connect()* function is being called *window.testIt = function()*. The error you are getting suggests you are not passing valid HTML elements as the first two parameters to *connect*. If you are using *document.getElementById* to get the elements you may have mistyped the *ID* attribute or perhaps your JavaScript is executing in the *HEAD* of your page before the *BODY* (and it's HTML elements have rendered). Hope you can figure it out, good luck. – Louis Ricci Jan 10 '17 at 13:29
  • 2
    Works nicely, *except* that last line: document.body.innerHTML += htmlLine; which seems to mess up other handlers. Instead let div = document.createElement("div"); div.style.cssText = all the style stuff; document.body.appendChild(div) seems OK – havlock Apr 09 '19 at 16:49
1

There is a way to do it without jQ.

  1. Find the position of your divs using offset.
  2. Find the slope
  3. draw 1x1px points from start to end position using the slope in your loop.
Wouter J
  • 41,455
  • 15
  • 107
  • 112