การวาดเส้นเชื่อมระหว่างสององค์ประกอบ [ปิด]


106

ฉันจะลากเส้นระหว่างสององค์ประกอบขึ้นไปเพื่อเชื่อมต่อได้อย่างไร การผสม HTML / CSS / JavaScript / SVG / Canvas ใด ๆ ก็ใช้ได้

หากคำตอบของคุณสนับสนุนสิ่งเหล่านี้ให้กล่าวถึง:

  • องค์ประกอบที่ลากได้
  • การเชื่อมต่อที่ลากได้ / แก้ไขได้
  • การหลีกเลี่ยงองค์ประกอบที่ทับซ้อนกัน

คำถามนี้ได้รับการอัปเดตเพื่อรวบรวมความหลากหลายของคำถามนี้

คำตอบ:


164

jsPlumbเป็นตัวเลือกที่สามารถใช้ได้ที่สนับสนุนการลากและวางเมื่อเห็นของประชาชนจำนวนมากรวมทั้งการสาธิตผัง

มีให้บริการในรุ่นชุมชนฟรีและรุ่น Toolkit แบบชำระเงิน

Toolkit edition ครอบคลุมรุ่น Community ด้วยชั้นการผูกข้อมูลที่ครอบคลุมตลอดจนวิดเจ็ต UI หลายตัวสำหรับการสร้างแอปพลิเคชันและการผสานรวมสำหรับไลบรารียอดนิยมและได้รับอนุญาตในเชิงพาณิชย์


5
ชุดเครื่องมือที่น่าทึ่ง แต่ขอเตือนว่ามันไม่ฟรี! พวกเขาต้องการให้คุณซื้อใบอนุญาตหากคุณตั้งใจจะโฮสต์ต่อสาธารณะหรือขายภายในผลิตภัณฑ์ของคุณเอง (ดูjsplumbtoolkit.com/purchase )
Chris

53

การเข้าร่วมบรรทัดกับ 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>

    แท็กเส้นช่วยให้เราสามารถลากเส้นระหว่างจุดที่ระบุสองจุด (x1, y1) และ (x2, y2) (สำหรับการเยี่ยมชม w3schools อ้างอิง) เรายังไม่ได้ระบุ เพราะเราจะใช้ jQuery เพื่อแก้ไขแอตทริบิวต์ (x1, y1, x2, y2) ของแท็กบรรทัด

  3. ใน<script>แท็กเขียน

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

    ฉันใช้ตัวเลือกเพื่อเลือกสอง divs และ line ...

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

    position()วิธีjQuery ช่วยให้เราได้รับตำแหน่งปัจจุบันขององค์ประกอบ ดูข้อมูลเพิ่มเติมได้ที่https://api.jquery.com/position/ (คุณสามารถใช้offset()วิธีนี้ได้เช่นกัน)

เมื่อได้ตำแหน่งทั้งหมดที่ต้องการแล้วเราสามารถลากเส้นได้ดังนี้ ...

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

.attr()วิธีjQuery ใช้เพื่อเปลี่ยนแอตทริบิวต์ขององค์ประกอบที่เลือก

สิ่งที่เราทำในบรรทัดข้างต้นคือเราเปลี่ยนแอตทริบิวต์ของบรรทัดจาก

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

ตอนนี้แท็กบรรทัดมีพิกัดที่แตกต่างกันสองจุดเพื่อลากเส้นระหว่างสองจุด

เคล็ดลับ: เพิ่มผู้ฟังเหตุการณ์ตามที่คุณต้องการใน div

เคล็ดลับ: ตรวจสอบให้แน่ใจว่าคุณนำเข้าไลบรารี 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
โปรดอย่าคัดลอกและวางคำตอบเดียวกันสำหรับคำถามหลายข้อ ให้ปรับแต่งคำตอบสำหรับคำถามแต่ละข้อแทน
แอนดี้

2
ฉันต้องใส่ svg ที่ความกว้างและความสูง 100% ในพื้นหลังโดยใช้ z-index -1 แต่มันใช้งานได้เหมือนมีเสน่ห์
สตี

4
คำตอบนี้คัดลอกมาจากstackoverflow.com/questions/19382872/…
Damjan Pavlica

33
ผู้โหวตโปรดแสดงความคิดเห็นถึงเหตุผลในการทำเช่นนั้น ... ฉันได้โพสต์คำตอบเดียวกันสำหรับทั้งสองคำถามเพราะฉันแน่ใจว่าคำตอบนี้ใช้ได้กับทั้งสองคำถาม ... หากสองคำถามเกี่ยวข้องกันคำตอบของพวกเขาก็เกี่ยวข้องเช่นกัน .. . ฉันไม่ได้ทำอะไรผิด ...
Ani

6

ฉันก็มีความต้องการเหมือนกันเมื่อสองสามวันก่อน

ฉันใช้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

VisJSสนับสนุนสิ่งนี้ด้วยตัวอย่าง Arrowsซึ่งรองรับองค์ประกอบที่ลากได้

นอกจากนี้ยังสนับสนุนการเชื่อมต่อที่สามารถแก้ไขได้ด้วยตัวอย่างเช่นการโต้ตอบเหตุการณ์


2

GoJSสนับสนุนสิ่งนี้ด้วยตัวอย่างแผนภูมิสถานะที่รองรับการลากและวางองค์ประกอบและการแก้ไขการเชื่อมต่อ

คำตอบนี้จะตามออกของวอลเตอร์ Northwoods' คำตอบคำตอบ


โซลูชั่นที่สมบูรณ์แบบ ... ขอบคุณ @balupton
Rj_Innocent_Coder

2

เมื่อเร็ว ๆ นี้ฉันได้พยายามพัฒนาเว็บแอปง่ายๆที่ใช้การลากและวางส่วนประกอบและมีเส้นเชื่อมต่อกัน ฉันเจอไลบรารีจาวาสคริปต์ที่เรียบง่ายและน่าทึ่งทั้งสองนี้:

  1. ลากธรรมดา : ไลบรารีที่เรียบง่ายและมีประสิทธิภาพสูงเพื่อให้สามารถลากองค์ประกอบ HTML / SVG ได้
  2. Leader Line : ลากเส้นผู้นำในหน้าเว็บของคุณ


1


1

Cytoscapeรองรับสิ่งนี้ด้วยตัวอย่างสถาปัตยกรรมซึ่งรองรับการลากองค์ประกอบ

สำหรับการสร้างการเชื่อมต่อมีส่วนขยายของedgehandles ยังไม่รองรับการแก้ไขการเชื่อมต่อที่มีอยู่ คำถาม.

สำหรับการแก้ไขรูปร่างการเชื่อมต่อมีส่วนขยายการแก้ไขขอบ การสาธิต.

ดูเหมือนว่าส่วนขยายการแก้ไขการแก้ไขจะมีแนวโน้มดี แต่ยังไม่มีการสาธิต


1

js-graph.itรองรับกรณีการใช้งานนี้ดังที่เห็นได้จากคู่มือเริ่มต้นใช้งานซึ่งสนับสนุนการลากองค์ประกอบโดยไม่มีการเชื่อมต่อทับซ้อนกัน ดูเหมือนว่าจะไม่รองรับการแก้ไข / สร้างการเชื่อมต่อ ดูเหมือนจะไม่ได้รับการดูแลอีกต่อไป


0

JointJS / Rappidรองรับกรณีการใช้งานนี้ด้วยตัวอย่าง Kitchensinkซึ่งรองรับการลากและวางองค์ประกอบและการจัดตำแหน่งการเชื่อมต่อใหม่ มันมีตัวอย่างมากมาย

คำตอบนี้จะตามออกVainbhav เชนของ คำตอบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.