web-dev-qa-db-ja.com

2つの要素間に接続線を引く

2つ以上の要素の間に線を引き、それらを接続するにはどうすればよいですか(または使用可能なツール)? HTML/CSS/JavaScript/SVG/Canvasの任意の組み合わせで問題ありません。

答えがこれらのいずれかをサポートしている場合は、言及してください:

  • ドラッグ可能な要素
  • ドラッグ可能/編集可能な接続
  • 要素の重複回避

この質問は 多数のバリエーションを統合する に更新されました。

91
Bakhtiyor

jsPlumb は、 フローチャートデモ を含む 多数のデモ からわかるように、ドラッグアンドドロップをサポートするオプションです。

無料のコミュニティエディションと有料のツールキットエディションで利用できます。

Toolkitエディションは、Communityエディションを包括的なデータバインディングレイヤーと、人気のあるライブラリのアプリケーションおよび統合を構築するためのいくつかのUIウィジェットでラップし、商用ライセンスです。

157

線をsvgと結合するのは一見の価値があり、完璧に機能しました...まず、Scalable Vector Graphics(SVG)は、双方向性とアニメーションをサポートする2次元グラフィック用のXMLベースのベクター画像形式です。 SVG画像とその動作は、XMLテキストファイルで定義されます。 <svg>タグを使用してHTMLでsvgを作成できます。 Adobe Illustratorは、パスを使用して複雑なsvgを作成するために使用される最高のソフトウェアの1つです。

ラインを使用して2つのdivを結合する手順:

  1. 2つの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タグを使用すると、指定された2つのポイント(x1、y1)と(x2、y2)の間に線を引くことができます。 (参照用にw3schoolsを参照してください。)まだ指定していません。 jQueryを使用して行タグの属性(x1、y1、x2、y2)を編集するためです。

  3. <script>タグ書き込み

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

    セレクターを使用して2つの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()は2つの値、「左」と「上」を返すため、オブジェクト(ここではpos1とpos2)を使用して.topと.leftを使用して簡単にアクセスできます...

現在、lineタグには、2つのポイント間に線を引くための2つの異なる座標があります。

ヒント:divする必要があるときにイベントリスナーを追加する

ヒント:スクリプトタグに何かを書き込む前に、必ずjQueryライブラリをインポートしてください

AfterJQueryを介して座標を追加...これは次のようになります

次のスニペットはデモンストレーションのみを目的としています。正しい手順を得るには上記の手順に従ってください

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

数日前にも同じ要件がありました

私はフルwidthheightsvgを使用し、すべての下に追加しましたdivsおよびlinesをこれらの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);
});
5
Nadir Laskar

VisJS は、ドラッグ可能な要素をサポートする 矢印の例 でこれをサポートします。

相互作用イベントの例 の編集可能な接続もサポートします。

2
balupton

Raphaël は、これを Graffleの例 でサポートしています。

この回答は、 Awais Akhtar'sanswer 、および Vaibhav Jain'sanswer に基づいています。

1
balupton

mxGraphdraw.io で使用— Grapheditorの例 でこの使用例をサポートします。 ドキュメント

この回答は、 Vainbhav Jain'sanswer に基づいています。

1
balupton
1
balupton

Cytoscape は、要素のドラッグをサポートする アーキテクチャ例 でこれをサポートします。

接続を作成するために、 edgehandles 拡張があります。 既存の接続の編集はまだサポートされていません。質問

接続形状の編集には、 エッジ編集 拡張機能があります。 デモ

edit-editation 拡張は有望なようですが、まだデモはありません。

1
balupton

GoJS は、これをサポートします ステートチャートの例 は、要素のドラッグアンドドロップ、および接続の編集をサポートします。

この回答は、 Walter Northwoods 'answer に基づいています。

0
balupton

JointJS/Rappid は、このユースケースをサポートします Kitchensinkの例 要素のドラッグアンドドロップ、および接続の再配置をサポートします。 多くの例があります。

この回答は、 Vainbhav Jain'sanswer に基づいています。

0
balupton

js-graph.it は、このユースケースをサポートしています 入門ガイド に見られるように、接続の重複なしに要素をドラッグすることをサポートしています。接続の編集/作成をサポートしているようには見えません。もうメンテナンスされていないようです。

0
balupton