Рисование соединительной линии между двумя элементами

Как я могу (или какие инструменты доступны) для рисования линии между двумя или более элементами, чтобы соединить их? Подойдет любая комбинация HTML/CSS/JavaScript/SVG/Canvas.

Если ваш ответ поддерживает какой-либо из них, упомяните его:

  • перетаскиваемые элементы
  • перетаскиваемые/редактируемые соединения
  • предотвращение перекрытия элементов

Этот вопрос был обновлен, чтобы объединить многочисленные варианты этого.

Ответ 1

jsPlumb - это доступная опция, которая поддерживает перетаскивание, что видно по многочисленным демонстрациям, включая демонстрацию блок-схем.

Он доступен в бесплатной версии Community и платной версии Toolkit.

Редакция Toolkit включает в себя редакцию Community с комплексным уровнем привязки данных, а также несколькими виджетами пользовательского интерфейса для создания приложений и интеграций для популярных библиотек и имеет коммерческую лицензию.

Ответ 2

Объединение строк с svgs стоило мне попробовать, и это сработало отлично... Прежде всего, Scalable Vector Graphics (SVG) - это векторный формат изображения на основе XML для двумерной графики с поддержкой интерактивности и анимации. Изображения SVG и их поведение определены в текстовых файлах XML. Вы можете создать SVG в HTML с помощью тега <svg>. Adobe Illustrator является одним из лучших программ, используемых для создания сложных svgs с использованием путей.

Процедура объединения двух div с использованием строки:

  1. создайте два элемента div и назначьте им любое нужное вам положение

    <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>
    

    (для пояснения я делаю некоторые встроенные стили, но всегда полезно создать отдельный CSS файл для стилизации)

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

    Тег Line позволяет нам провести линию между двумя указанными точками (x1, y1) и (x2, y2). (для ознакомительного посещения w3schools.) мы еще не указали их. потому что мы будем использовать jQuery для редактирования атрибутов (x1, y1, x2, y2) строкового тега.

  3. в теге <script> напишите

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

    Я использовал селекторы, чтобы выбрать два элемента div и строку...

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

    Метод jQuery position() позволяет нам получить текущую позицию элемента. Для получения дополнительной информации посетите https://api.jquery.com/position/ (вы также можете использовать метод offset())

Теперь, когда мы получили все нужные нам позиции, мы можем нарисовать линию следующим образом...

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() возвращает два значения, одно "левое", а другое "верхнее", мы можем легко получить к ним доступ, используя .top и .left, используя объекты (здесь pos1 и pos2)...

Теперь у линейного тега есть две разные координаты для рисования линии между двумя точками.

Подсказка: добавляйте прослушиватели событий по мере необходимости в divs

Совет: убедитесь, что вы импортировали библиотеку 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>

Ответ 3

У меня тоже было такое же требование несколько дней назад

Я использовал полную ширину и высоту 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);
});

Ответ 4

VisJS поддерживает это на примере стрелок, который поддерживает перетаскиваемые элементы.

Он также поддерживает редактируемые соединения с его примером Interaction Events.

Ответ 6

D3 содержит сотни примеров, некоторые из которых подходят для этого вопроса.

Примеры без перетаскивания, которые исправлены:

Примеры без перетаскивания, которые являются интерактивными:

Примеры с перетаскиванием:

This answer is based off of Glenn Dayton answer.

Ответ 8

Cytoscape поддерживает это с помощью своего примера архитектуры, который поддерживает перетаскивание элементов.

Для создания соединений существует расширение edgehandles. Он еще не поддерживает редактирование существующих подключений. Вопрос.

Для редактирования форм соединения есть расширение редактирования кромки. Demo.

Расширение edit-editation выглядит многообещающе, однако демоверсии пока нет.

Ответ 11

js-graph.it поддерживает этот вариант использования, что видно из руководства по началу работы, поддерживающего перетаскивание элементов без перекрытия соединений. Не похоже, что он поддерживает редактирование/создание соединений. Кажется, это больше не поддерживается.