[javascript] Draw a connecting line between two elements

How can I draw a line between two or more elements to connect them? Any combination of HTML/CSS/JavaScript/SVG/Canvas is fine.

If your answer supports any of these, then do mention it:

  • draggable elements
  • draggable/editable connections
  • element overlap avoidance

This question has been updated to consolidate the numerous variations of it.

This question is related to javascript html connection line jquery-ui-draggable

The answer is



Recently, I have tried to develop a simple web app that uses drag and drop components and has lines connecting them. I came across these two simple and amazing javascript libraries:

  1. Plain Draggable: simple and high performance library to allow HTML/SVG element to be dragged.
  2. Leader Line: Draw a leader line in your web page

Working example link (usage: click on add scene to create a draggable, click on add choice to draw a leader line between two different draggables)


mxGraph — used by draw.io — supports this use case, with its Grapheditor example. Documentation. Examples.

This answer is based off of Vainbhav Jain's answer.


VisJS supports this with its Arrows example, that supports draggable elements.

It also supports editable connections, with its Interaction Events example.


GoJS supports this, with its State Chart example, that supports dragging and dropping of elements, and editing of connections.

This answer is based off of Walter Northwoods' answer.


Cytoscape supports this with its Architecture example which supports dragging elements.

For creating connections, there is the edgehandles extension. It does not yet support editing existing connections. Question.

For editing connection shapes, there is the edge-editing extension. Demo.

The edit-editation extension seems promising, however there is no demo yet.


Joining lines with svgs was worth a shot for me, and it worked perfectly... first of all, Scalable Vector Graphics (SVG) is an XML-based vector image format for two-dimensional graphics with support for interactivity and animation. SVG images and their behaviors are defined in XML text files. you can create an svg in HTML using <svg> tag. Adobe Illustrator is one of the best software used to create an complex svgs using paths.

Procedure to join two divs using a line :

  1. create two divs and give them any position as you need

    <div id="div1" style="width: 100px; height: 100px; top:0; left:0; background:#e53935 ; position:absolute;"></div>
    <div id="div2" style="width: 100px; height: 100px; top:0; left:300px; background:#4527a0 ; position:absolute;"></div>
    

    (for the sake of explanation I am doing some inline styling but it is always good to make a separate css file for styling)

  2. <svg><line id="line1"/></svg>

    Line tag allows us to draw a line between two specified points(x1,y1) and (x2,y2). (for a reference visit w3schools.) we haven't specified them yet. because we will be using jQuery to edit the attributes (x1,y1,x2,y2) of line tag.

  3. in <script> tag write

    line1 = $('#line1');   
    div1 = $('#div1');   
    div2 = $('#div2');
    

    I used selectors to select the two divs and line...

    var pos1 = div1.position();
    var pos2 = div2.position();
    

    jQuery position() method allows us to obtain the current position of an element. For more information, visit https://api.jquery.com/position/ (you can use offset() method too)

Now as we have obtained all the positions we need we can draw line as follows...

line1
  .attr('x1', pos1.left)
  .attr('y1', pos1.top)
  .attr('x2', pos2.left)
  .attr('y2', pos2.top);

jQuery .attr() method is used to change attributes of the selected element.

All we did in above line is we changed attributes of line from

x1 = 0
y1 = 0
x2 = 0
y2 = 0

to

x1 = pos1.left
y1 = pos1.top
x2 = pos2.left
y2 = pos2.top

as position() returns two values, one 'left' and other 'top', we can easily access them using .top and .left using the objects (here pos1 and pos2) ...

Now line tag has two distinct co-ordinates to draw line between two points.

Tip: add event listeners as you need to divs

Tip: make sure you import jQuery library first before writing anything in script tag

After adding co-ordinates through JQuery ... It will look something like this

Following snippet is for demonstration purpose only, please follow steps above to get correct solution

_x000D_
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
<div id="div1" style="width: 100px; height: 100px; top:0; left:0; background:#e53935 ; position:absolute;"></div>_x000D_
<div id="div2" style="width: 100px; height: 100px; top:0; left:300px; background:#4527a0 ; position:absolute;"></div>_x000D_
<svg width="500" height="500"><line x1="50" y1="50" x2="350" y2="50" stroke="red"/></svg>
_x000D_
_x000D_
_x000D_


js-graph.it supports this use case, as seen by its getting started guide, supporting dragging elements without connection overlaps. Doesn't seem like it supports editing/creating connections. Doesn't seem it is maintained anymore.


Raphaël supports this, with its Graffle example.

This answer is based off of Awais Akhtar's answer, and Vaibhav Jain's answer.


JointJS/Rappid supports this use case with its Kitchensink example which supports dragging and dropping of elements, and repositioning of connections. It has many examples.

This answer is based off of Vainbhav Jain's answer.


I also had the same requirement few days back

I used an full width and height svg and added it below all my divs and added lines to these svg dynamically.

Checkout the how I did it here using svg

HTML

<div id="ui-browser"><div class="anchor"></div>
     <div id="control-library" class="library">
       <div class="name-title">Control Library</div>
       <ul>
         <li>Control A</li>
         <li>Control B</li>
         <li>Control C</li>
         <li>Control D</li>
       </ul>
     </div><!--
--></div><!--
--><div id="canvas">
     <svg id='connector_canvas'></svg>
     <div class="ui-item item-1"><div class="con_anchor"></div></div>
     <div class="ui-item item-2"><div class="con_anchor"></div></div>
     <div class="ui-item item-3"><div class="con_anchor"></div></div>
     <div class="ui-item item-1"><div class="con_anchor"></div></div>
     <div class="ui-item item-2"><div class="con_anchor"></div></div>
     <div class="ui-item item-3"><div class="con_anchor"></div></div>
   </div><!--
--><div id="property-browser"></div>

https://jsfiddle.net/kgfamo4b/

    $('.anchor').on('click',function(){
   var width = parseInt($(this).parent().css('width'));
   if(width==10){
     $(this).parent().css('width','20%');
     $('#canvas').css('width','60%');
   }else{
      $(this).parent().css('width','10px');
     $('#canvas').css('width','calc( 80% - 10px)');
   }
});

$('.ui-item').draggable({
  drag: function( event, ui ) {
           var lines = $(this).data('lines');
           var con_item =$(this).data('connected-item');
           var con_lines = $(this).data('connected-lines');

           if(lines) {
             lines.forEach(function(line,id){
                    $(line).attr('x1',$(this).position().left).attr('y1',$(this).position().top+1);  
             }.bind(this));
           }

           if(con_lines){
               con_lines.forEach(function(con_line,id){
                  $(con_line).attr('x2',$(this).position().left)
                        .attr('y2',$(this).position().top+(parseInt($(this).css('height'))/2)+(id*5));
               }.bind(this));

           }

       }
});

$('.ui-item').droppable({
  accept: '.con_anchor',
  drop: function(event,ui){
     var item = ui.draggable.closest('.ui-item');
     $(this).data('connected-item',item);
     ui.draggable.css({top:-2,left:-2});
     item.data('lines').push(item.data('line'));

     if($(this).data('connected-lines')){
        $(this).data('connected-lines').push(item.data('line'));

         var y2_ = parseInt(item.data('line').attr('y2'));
         item.data('line').attr('y2',y2_+$(this).data('connected-lines').length*5);

     }else $(this).data('connected-lines',[item.data('line')]);

     item.data('line',null);
    console.log('dropped');
  }
});


$('.con_anchor').draggable({drag: function( event, ui ) {
     var _end = $(event.target).parent().position();
     var end = $(event.target).position();
     if(_end&&end)  
     $(event.target).parent().data('line')
                                                    .attr('x2',end.left+_end.left+5).attr('y2',end.top+_end.top+2);
},stop: function(event,ui) {
        if(!ui.helper.closest('.ui-item').data('line')) return;
        ui.helper.css({top:-2,left:-2});
        ui.helper.closest('.ui-item').data('line').remove();
        ui.helper.closest('.ui-item').data('line',null);
        console.log('stopped');
      }
});


$('.con_anchor').on('mousedown',function(e){
    var cur_ui_item = $(this).closest('.ui-item');
    var connector = $('#connector_canvas');
    var cur_con;

  if(!$(cur_ui_item).data('lines')) $(cur_ui_item).data('lines',[]);

  if(!$(cur_ui_item).data('line')){
         cur_con = $(document.createElementNS('http://www.w3.org/2000/svg','line'));
         cur_ui_item.data('line',cur_con);
    } else cur_con = cur_ui_item.data('line');

    connector.append(cur_con);
    var start = cur_ui_item.position();
     cur_con.attr('x1',start.left).attr('y1',start.top+1);
     cur_con.attr('x2',start.left+1).attr('y2',start.top+1);
});

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to connection

Apache Server (xampp) doesn't run on Windows 10 (Port 80) "Proxy server connection failed" in google chrome Failed to connect to mysql at 127.0.0.1:3306 with user root access denied for user 'root'@'localhost'(using password:YES) "The underlying connection was closed: An unexpected error occurred on a send." With SSL Certificate Login to Microsoft SQL Server Error: 18456 How do I start Mongo DB from Windows? java.rmi.ConnectException: Connection refused to host: 127.0.1.1; mySQL Error 1040: Too Many Connection org.apache.http.conn.HttpHostConnectException: Connection to http://localhost refused in android What is the functionality of setSoTimeout and how it works?

Examples related to line

How do I compute the intersection point of two lines? Java Replace Line In Text File draw diagonal lines in div background with CSS How to make a new line or tab in <string> XML (eclipse/android)? How do you run a command for each line of a file? How can I format a list to print each element on a separate line in python? Remove lines that contain certain string How to paste text to end of every line? Sublime 2 Making PHP var_dump() values display one line per value How to do multiple line editing?

Examples related to jquery-ui-draggable

Draw a connecting line between two elements