将两个元素之间画一条连接线

150

如何在两个或多个元素之间绘制一条连接线?可以使用HTML/CSS/JavaScript/SVG/Canvas的任意组合。

如果你的答案支持以下任何一种,请注明:

  • 可拖动元素
  • 可拖动/可编辑连接
  • 避免元素重叠

该问题已更新以合并众多变体

12个回答

175

jsPlumb 是一种支持拖放功能的选项,如其众多演示所示,包括流程图演示

它提供了免费社区版和付费工具包版。

工具包版将社区版封装了一个全面的数据绑定层,并提供了几个 UI 小部件用于构建应用程序和与流行库的集成,并获得商业许可。


20
工具包很棒,但需要注意:它不是免费的!如果您打算公开托管或在自己的产品中销售,他们会要求您购买许可证(请参见https://jsplumbtoolkit.com/purchase)。 - Chris
4
截至今天,也存在一个社区版:https://jsplumbtoolkit.com/community,它是开源的。 - superjos
1
不是免费的!使用SVG的解决方案更简单。 - Mimouni
jsPlumb还提供社区版 [GitHub网址:https://github.com/jsplumb/jsplumb] [文档:https://docs.jsplumbtoolkit.com/community/6.x/] [示例代码片段使用Jquery + Angular + jsPlumb 6.x: https://gist.github.com/SciTechEnthusiast/5698c56265960fe038717405b7aa697f] - Yogesh Jog

79

对我来说,使用SVG连接线是值得一试的,而且它完美地起作用了...首先,可缩放矢量图形(SVG)是一种基于XML的二维图形矢量图像格式,支持交互和动画。SVG图像及其行为在XML文本文件中定义。您可以使用<svg>标签在HTML中创建SVG。Adobe Illustrator是用于使用路径创建复杂SVG的最佳软件之一。

连接两个div以形成一条线的过程:

  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)

现在,我们已经获得了所有需要的位置,可以按照以下方式绘制线条...
line1
  .attr('x1', pos1.left)
  .attr('y1', pos1.top)
  .attr('x2', pos2.left)
  .attr('y2', pos2.top);

jQuery的.attr()方法用于更改所选元素的属性。

我们在上述行中所做的所有事情都是从一行中更改属性。

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

为了

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

由于position()返回两个值,一个是'left'(左边),另一个是'top'(顶部),我们可以使用对象(此处为pos1和pos2)轻松访问它们的.top和.left属性...

现在,线标记具有绘制两个点之间的线所需的两个不同坐标。

提示:根据需要向div添加事件侦听器

提示:确保在编写script标记中的任何内容之前首先导入jQuery库

通过JQuery添加坐标后...它看起来像这样

以下代码片段仅用于演示目的,请按照以上步骤获取正确的解决方案。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<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>
<svg width="500" height="500"><line x1="50" y1="50" x2="350" y2="50" stroke="red"/></svg>


4
请不要将相同的答案复制粘贴到多个问题中。相反,根据每个问题定制答案。 - Andy
2
我需要将SVG以宽度和高度100%的形式放置在背景中,使用z-index -1,但它非常有效。 - steven
5
这个答案是从 https://dev59.com/TWIk5IYBdhLWcg3wUsvv 复制的。 - Damjan Pavlica
55
给出负评的人,请注明原因……我在两个问题中发布了相同的答案,因为我确信这个答案适用于两个问题……如果两个问题相关,则它们的答案也可能相关……我没有做错任何事情…… - Ani
无法用于动态添加的div / svg。 - Cybernetic
显示剩余3条评论

78

最近,我尝试开发一个简单的Web应用程序,使用拖放组件,并连接它们之间的线条。我找到了这两个简单而神奇的JavaScript库:

  1. Plain Draggable:允许HTML/SVG元素被拖动的简单高性能库。
  2. Leader Line:在您的网页中绘制一条引导线。

工作示例链接(用法:点击添加场景以创建可拖动元素,点击添加选择以在两个不同的可拖动元素之间绘制引导线)


8

几天前,我也有同样的需求

我使用了一个全宽和全高的svg,并在所有div下方添加了它,动态地向这些svg添加了线条。

查看我如何使用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);
});

似乎在Safari版本12.0.1(14606.2.104.1.1)上无法工作。 - balupton

3

2

完美的解决方案...感谢@balupton - Rohit Chauhan

2

1


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接