web-dev-qa-db-fra.com

Comment placer des triangles à tête de flèche sur des lignes SVG?

Je suis nouveau sur SVG et j'essaie de tracer une ligne droite entre deux points. J'ai réussi jusqu'à présent en utilisant cette commande:

<line x1="50" y1="50" x2="150" y2="150" style="stroke:rgb(255,255,0); stroke-width:2" stroke-dasharray="5,3" />"

Quelle est la manière la plus simple d'ajouter de minuscules triangles ou têtes de flèche (régulièrement espacés) sur cette ligne afin d'indiquer la direction?

Modifier 1:

Pour être plus clair, je ne suis pas après une flèche à la fin de la ligne, mais plusieurs triangles (régulièrement espacés) sur toute la ligne. Si possible, je voudrais remplacer chaque tiret de la ligne pointillée par un triangle pointant dans la direction de la ligne.

Éditer 2

Sur la base de la suggestion de Phrogz, j'ai créé une page comme indiqué ci-dessous, mais rien ne s'affiche. Qu'est-ce que je fais mal?

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<link href="css/com.css" rel="stylesheet" type="text/css" />
</head>
<body style="background:none;">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-10 -10 70 90">
<defs>
<marker id="t" markerWidth="4" markerHeight="4"
        orient="auto" refY="2">
  <path d="M0,0 L4,2 0,4" />
</marker>
</defs>
<polyline points="0,0 0,50 20,70 40,10 42,8 44,10, 46,14 50,50" />
</svg>
<script type="text/javascript">
midMarkers(document.querySelector('polyline'),6);

    // Given a polygon/polyline, create intermediary points along the
    // "straightaways" spaced no closer than `spacing` distance apart.
    // Intermediary points along each section are always evenly spaced.
    // Modifies the polygon/polyline in place.
    function midMarkers(poly,spacing){
        var svg = poly.ownerSVGElement;
        for (var pts=poly.points,i=1;i<pts.numberOfItems;++i){
            var p0=pts.getItem(i-1), p1=pts.getItem(i);
            var dx=p1.x-p0.x, dy=p1.y-p0.y;
            var d = Math.sqrt(dx*dx+dy*dy);
            var numPoints = Math.floor( d/spacing );
            dx /= numPoints;
            dy /= numPoints;
            for (var j=numPoints-1;j>0;--j){
                var pt = svg.createSVGPoint();
                pt.x = p0.x+dx*j;
                pt.y = p0.y+dy*j;
                pts.insertItemBefore(pt,i);
            }
            if (numPoints>0) i += numPoints-1;
        }
    }
</script>
</body>
</html>
40
Osprey

Sur la base d'une clarification de la question, voici une implémentation de la création de points intermédiaires le long d'un élément <polyline> De telle sorte que l'attribut marker-mid="url(#arrowhead)" fonctionnera. Voir ci-dessous pour une introduction aux marqueurs et pointes de flèches.

Démo: http://jsfiddle.net/Zv57N/

midMarkers(document.querySelector('polyline'),6);

// Given a polygon/polyline, create intermediary points along the
// "straightaways" spaced no closer than `spacing` distance apart.
// Intermediary points along each section are always evenly spaced.
// Modifies the polygon/polyline in place.
function midMarkers(poly,spacing){
  var svg = poly.ownerSVGElement;
  for (var pts=poly.points,i=1;i<pts.numberOfItems;++i){
    var p0=pts.getItem(i-1), p1=pts.getItem(i);
    var dx=p1.x-p0.x, dy=p1.y-p0.y;
    var d = Math.sqrt(dx*dx+dy*dy);
    var numPoints = Math.floor( d/spacing );
    dx /= numPoints;
    dy /= numPoints;
    for (var j=numPoints-1;j>0;--j){
      var pt = svg.createSVGPoint();
      pt.x = p0.x+dx*j;
      pt.y = p0.y+dy*j;
      pts.insertItemBefore(pt,i);
    }
    if (numPoints>0) i += numPoints-1;
  }
}

Le code ci-dessus modifie un élément <polyline> Existant pour ajouter des points toutes les unités d'espacement le long de chaque arête droite. Combinez cela avec marker-mid Pour placer un marqueur pivoté à chaque sommet, et vous avez la possibilité de dessiner des formes/graphiques arbitrairement complexes de manière cohérente le long de votre chemin.

Bird Tracks

Bien que le code espace les points uniformément le long de chaque segment (de sorte qu'aucun `` regroupement '' disgracieux ne se produise dans les coins), comme le montre la démonstration ci-dessus, le code ne supprime pas les points que vous avez déjà sur votre chemin qui sont plus proches les uns des autres que le valeur d'espacement .


(La réponse originale "Intro to Markers" suit.)


Vous souhaitez définir un élément SVG <marker> et ajouter les attributs marker-start="…" Et/ou marker-end="…" À votre ligne. L'utilisation d'un marqueur copie toute forme arbitraire aux extrémités de votre chemin et (avec orient="auto") Fait pivoter la forme pour qu'elle corresponde.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="-50 -100 200 200">
  <defs>
    <marker id='head' orient='auto' markerWidth='2' markerHeight='4'
            refX='0.1' refY='2'>
      <path d='M0,0 V4 L2,2 Z' fill='red' />
    </marker>
  </defs>    
  <path
    marker-end='url(#head)'
    stroke-width='5' fill='none' stroke='black'  
    d='M0,0 C45,45 45,-45 90,0'
    />    
</svg>​

Démo: http://jsfiddle.net/Z5Qkf/1/

Curved line with arrowhead

Au dessus:

  • orient="auto" fait tourner le marqueur avec la ligne
  • markerWidth et markerHeight définissent une boîte englobante (comme une viewBox) à utiliser pour le marqueur.
    • Notez que ceux-ci sont ensuite mis à l'échelle par le stroke-width De la ligne finale; ayant une hauteur de "4", elle a une largeur de 20 unités dans le dessin final (4 × 5).
  • refX et refY définissent où se trouve l '"origine" lors du placement de la forme à la fin du chemin
    • J'ai utilisé refX="0.1" Pour m'assurer que le marqueur chevauche légèrement la fin de la ligne
  • Pour que l'orientation automatique fonctionne correctement, vous voulez que la direction "avant" du marqueur soit dans la direction + x. (Le chemin rouge utilisé pour le marqueur ressemble à ceci ▶ lorsqu'il n'est pas tourné.)
  • Vous pouvez ajuster le fill-opacity Et stroke-opacity Du marqueur et/ou de la ligne indépendamment, mais les modifications apportées au opacity de la ligne affecteront également le marqueur dessiné.
    • Puisque la ligne et le marqueur se chevauchent, si vous abaissez le fill-opacity Du marqueur, vous verriez le chevauchement; cependant, si vous abaissez le opacity de la ligne elle-même, le marqueur est composé entièrement opaque sur la ligne et la combinaison des deux est alors réduite en opacité.
      enter image description here

Si vous voulez des flèches le long de la ligne, vous devrez utiliser marker-mid="…" Avec <path> Ou <polyline> Et des points intermédiaires le long de la ligne.

Démo: http://jsfiddle.net/Z5Qkf/2/

enter image description here

Le seul problème est que tout point qui change de direction le long de la ligne gâche l'orientation ; c'est pourquoi dans la démo j'ai utilisé une courbe de Bézier pour arrondir le coin afin que le milieu de la ligne soit le long d'une section droite.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="-50 -100 200 200">
<defs>
  <marker id='mid' orient="auto"
    markerWidth='2' markerHeight='4'
    refX='0.1' refY='1'>
    <!-- triangle pointing right (+x) -->
    <path d='M0,0 V2 L1,1 Z' fill="orange"/>
  </marker>
  <marker id='head' orient="auto"
    markerWidth='2' markerHeight='4'
    refX='0.1' refY='2'>
    <!-- triangle pointing right (+x) -->
    <path d='M0,0 V4 L2,2 Z' fill="red"/>
  </marker>
</defs>

<path
  id='arrow-line'
  marker-mid='url(#mid)'
  marker-end='url(#head)'
  stroke-width='5'
  fill='none' stroke='black'  
  d='M0,0 L20,20 C40,40 40,40 60,20 L80,0'
  />

</svg>​

Pour ce faire, vous pouvez utiliser JavaScript et la commande getPointAtLength() pour un chemin d'accès à exemple du chemin d'accès .

146
Phrogz

Je veux juste ajouter quelques liens et exemples utiles:

1. La flèche peut être quadratique enter image description here

2. Courbe cubique enter image description here

Documentation: https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths

Démo: les deux types de flèches implémentées ici:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>

  
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="-50 -100 200 200">
<defs>
  <marker id='head' orient="auto"
    markerWidth='2' markerHeight='4'
    refX='0.1' refY='2'>
    <!-- triangle pointing right (+x) -->
    <path d='M0,0 V4 L2,2 Z' fill="black"/>
  </marker>
</defs>

<path
  id='arrow-line'
  marker-end='url(#head)'
  stroke-width='1'
  fill='none' stroke='black'  
  d='M0,0 Q45,-20 90,0'
  />
    
<path
  id='arrow-line'
  marker-end='url(#head)'
  stroke-width='1'
  fill='none' stroke='black'  
  d='M0,50 C10,30 80,30 90,50'
  />

</svg>
</body>
</html>
4
Yarik