web-dev-qa-db-fra.com

Dessin de lignes de flèche SVG incurvées de div à div

Je veux dessiner deux lignes de flèche incurvées en utilisant SVG pour connecter deux éléments pour indiquer qu'ils vont et viennent, comme ceci:

enter image description here

J'ai lu un peu sur SVG mais je ne sais pas trop comment créer une ligne verticale.

Deuxièmement, si SVG prend des coordonnées, dois-je trouver la position des coordonnées des éléments avant de créer le dessin SVG? Doit-il être redessiné si la taille de la fenêtre est ajustée?

20
dsp_099

Créez un élément svg qui sous-tend (de manière invisible) tout le document. Cela contiendra les deux flèches. Insérez deux éléments svg path (les flèches) dont les coordonnées de début et de fin sont calculées en fonction des positions des div à connecter, et dont la courbe est créée comme vous le souhaitez en fonction de ces coordonnées de début et de fin.

Pour l'exemple ci-dessous, cliquez sur "Exécuter l'extrait de code". Ensuite, cliquez et faites glisser l'un des div pour voir comment les flèches sont créées dynamiquement, c'est-à-dire qu'elles se déplacent avec les div. jQuery et jQueryUI sont utilisés dans l'extrait de code simplement pour permettre la glisser facilement des divs et n'ont rien à voir avec la création et l'utilisation des flèches.

Cet exemple a deux flèches commençant et se terminant au milieu des côtés des divisions. Les détails de la courbe sont, bien sûr, à vous. Les lignes de flèche sont construites en utilisant l'attribut d du svg path. Dans cet exemple, "M" est les coordonnées "moveTo" où le chemin va commencer et les points "C" sont les premier et deuxième points de contrôle et la coordonnée finale pour une courbe de Bézier cubique. Vous devrez chercher ceux-ci pour comprendre ce qu'ils sont, mais ils sont un moyen général de créer des courbes lisses dans un élément svg. Les pointes de flèches sont ajoutées à l'aide d'un svg <marker> élément sur lequel vous pouvez lire ici .

Un document plus complexe aurait besoin de plus de soin pour déterminer les coordonnées de début et de fin des éléments svg path, c'est-à-dire les flèches, mais cet exemple vous donne au moins un point de départ.

Réponses à vos questions spécifiques:

  • Si SVG prend des coordonnées, dois-je trouver la position des coordonnées des éléments avant de créer le dessin SVG? Oui, comme je l'ai fait dans mon code.

  • Doit-il être redessiné si la taille de la fenêtre est ajustée? Probablement oui, en fonction de ce qui arrive aux divs eux-mêmes lorsque la fenêtre est redimensionnée.

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

J'ai trouvé la réponse d'Andrew Willems très utile. Je l'ai modifié pour créer une bibliothèque, draw_arrow.js, Qui exporte une fonction draw_arrow( sel1, locs1, sel2, locs2, arr ). Cela trace une flèche de l'élément identifié par le sélecteur CSS sel1 À celui identifié par sel2. locs1 Et locs2 Indiquent où la flèche doit commencer ou se terminer sur l'élément. arr identifie un chemin SVG pour maintenir la flèche.

Vous pouvez le télécharger et voir deux démos à partir des liens à la fin de http://www.chromophilia.uk/blog/dress-reform-architecture-and-modernism/ . J'avais besoin des flèches pour représenter les relations entre divers sujets liés au modernisme, dans le cadre d'une animation. C'est ce qui m'a poussé à trouver et à adapter le code d'Andrew.

Voici une amélioration suggérée. À l'origine, j'ai écrit cela comme une nouvelle réponse supplémentaire, mais plusieurs commentateurs l'ont exécutée, donc je vais devoir la mettre ici et j'espère qu'elle sera remarquée. Je poursuis cela parce que la modularité est importante. Une routine telle que draw_arrow Devrait obliger son utilisateur à faire le moins possible avec le code qui l'entoure. Mais pour le moment, il faut que l'utilisateur crée un élément <path> À l'intérieur du <svg> Pour chaque flèche à dessiner, et invente des identifiants pour les chemins. Je suggère qu'il serait préférable que draw_arrow Fasse cela, en mettant à jour l'arborescence DOM. Des commentaires pour ou contre?

6
Phil van Kleur

Pour ceux qui le recherchent en 2020, consultez react-curved-arrow ! Il vous permet de dessiner des flèches courbes fantaisie entre deux éléments DOM. enter image description here

0
Nick