Vẽ đường kết nối giữa hai phần tử [đã đóng]


105

Làm cách nào để vẽ một đường thẳng giữa hai hoặc nhiều phần tử để kết nối chúng? Bất kỳ kết hợp HTML / CSS / JavaScript / SVG / Canvas nào cũng được.

Nếu câu trả lời của bạn hỗ trợ bất kỳ điều nào trong số này, thì hãy đề cập đến nó:

  • các yếu tố có thể kéo được
  • kết nối có thể kéo / có thể chỉnh sửa
  • tránh chồng chéo yếu tố

Câu hỏi này đã được cập nhật để hợp nhất nhiều biến thể của nó.

Câu trả lời:


164

jsPlumb là một tùy chọn có sẵn hỗ trợ kéo và thả, như đã thấy qua nhiều bản trình diễn của nó , bao gồm cả bản trình diễn Lưu đồ .

Nó có sẵn trong một phiên bản Cộng đồng miễn phí và một phiên bản Bộ công cụ trả phí.

Ấn bản Bộ công cụ bao bọc ấn bản Cộng đồng bằng một lớp liên kết dữ liệu toàn diện, cũng như một số tiện ích giao diện người dùng để xây dựng các ứng dụng và tích hợp cho các thư viện phổ biến và được cấp phép thương mại.


4
Bộ công cụ tuyệt vời nhưng được cảnh báo: nó không miễn phí! Họ muốn bạn mua giấy phép nếu bạn có ý định lưu trữ công khai hoặc bán trong các sản phẩm của riêng bạn (xem jsplumbtoolkit.com/purchase ).
Chris,

50

Nối các dòng với svgs rất đáng để thử đối với tôi, và nó hoạt động hoàn hảo ... trước hết, Đồ họa Vectơ có thể mở rộng (SVG) là một định dạng hình ảnh vectơ dựa trên XML cho đồ họa hai chiều với hỗ trợ tương tác và hoạt ảnh. Hình ảnh SVG và các hành vi của chúng được định nghĩa trong các tệp văn bản XML. bạn có thể tạo svg trong HTML bằng <svg>thẻ. Adobe Illustrator là một trong những phần mềm tốt nhất được sử dụng để tạo svgs phức tạp bằng cách sử dụng đường dẫn.

Quy trình nối hai div bằng cách sử dụng một dòng:

  1. tạo hai div và cung cấp cho chúng bất kỳ vị trí nào khi bạn cần

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

    (để giải thích, tôi đang thực hiện một số tạo kiểu nội tuyến nhưng tốt nhất là tạo một tệp css riêng để tạo kiểu)

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

    Thẻ dòng cho phép chúng ta vẽ một đường thẳng giữa hai điểm xác định (x1, y1) và (x2, y2). (để tham khảo, hãy truy cập w3schools.) chúng tôi chưa chỉ định chúng. bởi vì chúng tôi sẽ sử dụng jQuery để chỉnh sửa các thuộc tính (x1, y1, x2, y2) của thẻ dòng.

  3. trong <script>thẻ viết

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

    Tôi đã sử dụng bộ chọn để chọn hai div và dòng ...

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

    position()Phương thức jQuery cho phép chúng ta có được vị trí hiện tại của một phần tử. Để biết thêm thông tin, hãy truy cập https://api.jquery.com/position/ (bạn cũng có thể sử dụng offset()phương pháp này)

Bây giờ khi chúng ta đã có được tất cả các vị trí cần thiết, chúng ta có thể vẽ đường như sau ...

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

.attr()Phương thức jQuery được sử dụng để thay đổi các thuộc tính của phần tử được chọn.

Tất cả những gì chúng tôi đã làm ở dòng trên là chúng tôi thay đổi các thuộc tính của dòng từ

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

đến

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

khi position()trả về hai giá trị, một 'left' và 'top' khác, chúng ta có thể dễ dàng truy cập chúng bằng cách sử dụng .top và .left bằng cách sử dụng các đối tượng (ở đây là pos1 và pos2) ...

Bây giờ thẻ dòng có hai tọa độ riêng biệt để vẽ đường thẳng giữa hai điểm.

Mẹo: thêm người nghe sự kiện khi bạn cần div

Mẹo: hãy đảm bảo bạn nhập thư viện jQuery trước khi viết bất kỳ thứ gì vào thẻ script

Sau khi thêm các tọa độ thông qua JQuery ... Nó sẽ trông giống như thế này

Đoạn mã sau chỉ dành cho mục đích trình diễn, vui lòng làm theo các bước ở trên để có giải pháp chính xác

<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
Vui lòng không sao chép và dán cùng một câu trả lời cho nhiều câu hỏi. Thay vào đó, hãy tùy chỉnh câu trả lời cho các câu hỏi riêng lẻ.
Andy

2
Tôi cần đặt svg ở chiều rộng và chiều cao 100% trong nền bằng cách sử dụng z-index -1 nhưng nó hoạt động giống như một sự quyến rũ.
steven

4
Câu trả lời này được sao chép từ stackoverflow.com/questions/19382872/...
Damjan Pavlica

31
Những người phản đối, vui lòng bình luận lý do làm như vậy ... Tôi đã đăng các câu trả lời giống nhau cho cả hai câu hỏi vì tôi chắc chắn rằng câu trả lời này có thể áp dụng cho cả hai câu hỏi ... Nếu hai câu hỏi có liên quan thì câu trả lời của họ cũng có thể phù hợp .. . Tôi không làm gì sai ...
Ani

6

Tôi cũng có yêu cầu tương tự vài ngày trước

Tôi đã sử dụng svg chiều rộngchiều cao đầy đủ và thêm nó vào bên dưới tất cả các div của tôi và thêm các dòng vào svg này một cách động.

Kiểm tra cách tôi đã làm điều đó ở đây bằng 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);
});

Dường như không hoạt động trên Safari Phiên bản 12.0.1 (14606.2.104.1.1)
balupton



2

Gần đây, tôi đã cố gắng phát triển một ứng dụng web đơn giản sử dụng các thành phần kéo và thả và có các đường kết nối chúng. Tôi đã xem qua hai thư viện javascript đơn giản và tuyệt vời này:

  1. Plain Draggable : thư viện đơn giản và hiệu suất cao để cho phép kéo phần tử HTML / SVG.
  2. Dòng dẫn : Vẽ một dòng dẫn trong trang web của bạn


1


1

Cytoscape hỗ trợ điều này với ví dụ Kiến trúc của nó hỗ trợ kéo các phần tử.

Đối với việc tạo kết nối, có phần mở rộng edgehandles . Nó chưa hỗ trợ chỉnh sửa các kết nối hiện có. Câu hỏi.

Để chỉnh sửa hình dạng kết nối, có phần mở rộng chỉnh sửa cạnh . Bản giới thiệu.

Các chỉnh sửa-editation mở rộng dường như hứa hẹn, tuy nhiên không có bản demo được nêu ra.


1

js-graph.it hỗ trợ trường hợp sử dụng này, như đã thấy trong hướng dẫn bắt đầu , hỗ trợ kéo các phần tử mà không có sự chồng chéo kết nối. Có vẻ như nó không hỗ trợ chỉnh sửa / tạo kết nối. Có vẻ như nó không còn được duy trì nữa.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.