web-dev-qa-db-ja.com

divからdivへの湾曲したSVG矢印線の描画

次のように、SVGを使用して2つの要素を接続し、2つの要素が前後に移動することを示す2つの曲線矢印を描画します。

enter image description here

SVGについて少し読みましたが、垂直の線を作成する方法が完全にわかりません。

次に、SVGが座標を取る場合、SVG図面を作成する前に要素の座標位置を見つける必要がありますか?ウィンドウサイズを調整した場合、再描画する必要がありますか?

20
dsp_099

ドキュメント全体の基礎となる(見えないように)svg要素を作成します。これは両方の矢印を保持します。 2つのsvg path要素(矢印)を挿入します。これらの要素の開始座標と終了座標は、接続するdivの位置に基づいて計算され、その曲線は、これらの開始座標と終了座標に基づいて任意の方法で作成されます。

以下の例では、「コードスニペットの実行」をクリックします。次に、いずれかのdivをクリックしてドラッグし、矢印がどのように動的に作成されるか、つまり、divとともに移動するかを確認します。 jQueryとjQueryUIはコードスニペットで使用されており、単にdivを簡単にドラッグできるようにし、矢印の作成と使用とは関係ありません。

この例には、divの側面の中央で開始および終了する2つの矢印があります。もちろん、カーブの詳細はあなた次第です。矢印線は、svg dpath属性を使用して作成されます。この例では、「M」はパスが始まる「moveTo」座標であり、「C」ポイントは3次ベジエ曲線の最初と2番目の制御点と最終座標です。それらが何であるかを理解するには それらを調べる が必要ですが、これらはsvg要素で滑らかな曲線を作成する一般的な方法です。矢印は、svg <marker>要素を使用して追加されます。この要素は here について読むことができます。

より複雑なドキュメントでは、svg path要素の開始座標と終了座標、つまり矢印を決定するためにさらに注意が必要ですが、この例では少なくとも開始する場所が提供されます。

特定の質問に対する回答:

  • SVGが座標を取る場合、SVG図面を作成する前に要素の座標位置を見つける必要がありますか?はい、コードで行ったように。

  • ウィンドウサイズを調整した場合、再描画する必要がありますか?おそらくはい、ウィンドウのサイズが変更されたときにdiv自体に何が起こるかによって異なります。

var divA       = document.querySelector("#a");
var divB       = document.querySelector("#b");
var arrowLeft  = document.querySelector("#arrowLeft");
var arrowRight = document.querySelector("#arrowRight");

var drawConnector = function() {
  var posnALeft = {
    x: divA.offsetLeft - 8,
    y: divA.offsetTop  + divA.offsetHeight / 2
  };
  var posnARight = {
    x: divA.offsetLeft + divA.offsetWidth + 8,
    y: divA.offsetTop  + divA.offsetHeight / 2    
  };
  var posnBLeft = {
    x: divB.offsetLeft - 8,
    y: divB.offsetTop  + divA.offsetHeight / 2
  };
  var posnBRight = {
    x: divB.offsetLeft + divB.offsetWidth + 8,
    y: divB.offsetTop  + divA.offsetHeight / 2
  };
  var dStrLeft =
      "M" +
      (posnALeft.x      ) + "," + (posnALeft.y) + " " +
      "C" +
      (posnALeft.x - 100) + "," + (posnALeft.y) + " " +
      (posnBLeft.x - 100) + "," + (posnBLeft.y) + " " +
      (posnBLeft.x      ) + "," + (posnBLeft.y);
  arrowLeft.setAttribute("d", dStrLeft);
  var dStrRight =
      "M" +
      (posnBRight.x      ) + "," + (posnBRight.y) + " " +
      "C" +
      (posnBRight.x + 100) + "," + (posnBRight.y) + " " +
      (posnARight.x + 100) + "," + (posnARight.y) + " " +
      (posnARight.x      ) + "," + (posnARight.y);
  arrowRight.setAttribute("d", dStrRight);
};

$("#a, #b").draggable({
  drag: function(event, ui) {
    drawConnector();
  }
});

setTimeout(drawConnector, 250);
/* The setTimeout delay here is only required to prevent
 * the initial appearance of the arrows from being
 * incorrect due to the animated expansion of the
 * Stack Overflow code snippet results after clicking
 * "Run Code Snippet." If this was a simpler website,
 * a simple command, i.e. `drawConnector();` would suffice.
 */
html,
body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}
#instructions {
  position: fixed;
  left: 50%;
}
#a, #b {
  color: white;
  text-align: center;
  padding: 10px;
  position: fixed;
  width: 100px;
  height: 20px;
  left: 100px;
}
#a {
  background-color: blue;
  top: 20px;
}
#b {
  background-color: red;
  top: 150px;
}
<p id="instructions">Click and drag either div to see automatic arrow adjustments.</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min.js"></script>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
  <defs>
    <marker id="arrowhead" viewBox="0 0 10 10" refX="3" refY="5"
        markerWidth="6" markerHeight="6" orient="auto">
      <path d="M 0 0 L 10 5 L 0 10 z" />
    </marker>
  </defs>
  <g fill="none" stroke="black" stroke-width="2" marker-end="url(#arrowhead)">
    <path id="arrowLeft"/>
    <path id="arrowRight"/>
  </g>
</svg>
<div id="a">Div 1</div>
<div id="b">Div 2</div>
56
Andrew Willems

アンドリュー・ウィレムスの答えはとても役に立ちました。関数draw_arrow( sel1, locs1, sel2, locs2, arr )をエクスポートするライブラリdraw_arrow.jsを作成するように変更しました。これにより、CSSセレクターsel1で識別される要素からsel2で識別される要素への矢印が描画されます。 locs1およびlocs2は、要素のどこで矢印を開始または終了するかを示します。 arrは、矢印を保持するSVGパスを識別します。

http://www.chromophilia.uk/blog/dress-reform-architecture-and-modernism/ の最後にあるリンクから、これをダウンロードして2つのデモを見ることができます。アニメーションの一部として、モダニズムに関連するさまざまなトピック間の関係を表すための矢印が必要でした。それが、Andrewのコードを見つけて適応させるきっかけになりました。

ここに提案された改善があります。私はもともとこれを新しい、追加の回答として書きましたが、いくつかのコメント投稿者がそれを実行したので、ここに入れて、それが気付かれるといいのですが。モジュール性が重要であるため、私はこれを追求しています。 draw_arrowなどのルーチンは、ユーザーがその周りのコードに対してできる限り少ないことを要求する必要があります。ただし、現時点では、描画する矢印ごとに<path>内に<svg>要素を1つ作成し、パスのIDを作成する必要があります。 DOMツリーを更新することで、draw_arrowがこれを実行する方が良いと思います。賛成か反対か。

6
Phil van Kleur

2020年にこれをお探しの方は、 react-curved-arrow ! 2つのDOM要素の間に派手な曲線の矢印を描くことができます。 enter image description here

0
Nick