如何沿 SVG 线放置多个均匀间隔的箭头? [英] How to place multiple evenly-spaced arrowheads along an SVG line?

查看:31
本文介绍了如何沿 SVG 线放置多个均匀间隔的箭头?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 SVG 新手,我想在两点之间画一条直线.到目前为止,我使用此命令进行了管理:

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

在这条线上添加小三角形或箭头(均匀间隔)以指示方向的最简单方法是什么?

编辑 1:

为了更清楚,我不是在行尾的箭头,而是沿着整条线的多个三角形(均匀间隔).如果可能的话,我想用一个指向虚线方向的三角形替换虚线中的每个虚线.

编辑 2

根据 Phrogz 的建议,我创建了一个如下所示的页面,但没有显示任何内容.我做错了什么?

<%@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"><头><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>无标题文档</title><link href="css/com.css" rel="stylesheet" type="text/css"/><body style="background:none;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-10 -10 70 90"><定义><marker id="t" markerWidth="4" markerHeight="4"orient="自动" refY="2"><path d="M0,0 L4,2 0,4"/></标记></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);//给定一个多边形/折线,创建沿线的中间点//straightaways"的间距不小于 `spacing` 距离.//沿每个部分的中间点始终均匀分布.//修改多边形/折线.函数 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;}}

解决方案

基于对问题的澄清,这里有一个沿 元素创建中间点的实现,例如marker-mid="url(#arrowhead)" 属性将起作用.有关标记和箭头的介绍,请参见下文.

演示: 并将 marker-start="..." 和/或 marker-end="..." 属性添加到您的行中.使用标记将任意形状复制到路径的末端,并(使用 orient="auto")旋转形状以匹配.

<定义><marker id='head' orient='auto'markerWidth='2'markerHeight='4'refX='0.1' refY='2'><path d='M0,0 V4 L2,2 Z' fill='red'/></标记></defs><路径标记结束 ='url(#head)'笔画宽度=5"填充=无"笔画=黑色"d='M0,0 C45,45 45,-45 90,0'/></svg>

演示:使标记随线旋转
  • 唯一的问题是任何沿线改变方向的点搞乱方向;这就是为什么在演示中我使用贝塞尔曲线来圆角,使线的中点沿着直线部分.

    <定义><marker id='mid' orient="auto"标记宽度='2' 标记高度='4'refX='0.1' refY='1'><!-- 指向右侧的三角形 (+x) --><path d='M0,0 V2 L1,1 Z' fill="orange"/></标记><marker id='head' orient="auto"标记宽度='2' 标记高度='4'refX='0.1' refY='2'><!-- 指向右侧的三角形 (+x) --><path d='M0,0 V4 L2,2 Z' fill="red"/></标记></defs><路径id='箭头线'标记mid='url(#mid)'标记结束 ='url(#head)'笔画宽度='5'填充='无'笔触='黑色'd='M0,0 L20,20 C40,40 40,40 60,20 L80,0'/></svg>

    要按程序执行此操作,您可以使用 JavaScript 和 getPointAtLength() 命令作为 对路径进行采样.

    I am new to SVG and I am trying to draw a straight line between two points. I managed so far by using this command:

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

    What is the simplest way to add tiny triangles or arrow heads (evenly spaced) over this line in order to indicate the direction?

    Edit 1:

    Just to be more clear, I am not after an arrow at the end of the line, but multiple triangles (evenly spaced) along the whole line. If possible, I would like to replace each dash in the dashed line with a triangle pointing in the direction of the line.

    Edit 2

    Based on Phrogz' suggestion, I created a page as shown below, but nothing is showing up. What am I doing wrong?

    <%@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>
    

    解决方案

    Based on a clarification of the question, here's an implementation of creating intermediary points along a <polyline> element such that the marker-mid="url(#arrowhead)" attribute will work. See below that for an introduction to markers and arrowheads.

    Demo: 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;
      }
    }
    

    The above code modifies an existing <polyline> element to add points every spacing units along each straight edge. Combine this with marker-mid to place a rotated marker at every vertex, and you have the ability to draw arbitrarily complex shapes/graphics consistently along your path.

    Although the code spaces out the points evenly along each segment (so that no unsightly 'bunching up' occurs at corners) as the above demo shows the code does not remove any points that you already have in your path that are closer together than the spacing value.


    (Original "Intro to Markers" answer follows.)


    You want to define an SVG <marker> element and add the marker-start="…" and/or marker-end="…" attributes to your line. Using a marker copies any arbitrary shape onto the end(s) of your path, and (with orient="auto") rotates the shape to match.

    <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>​
    

    Demo: http://jsfiddle.net/Z5Qkf/1/

    In the above:

    • orient="auto" causes the marker to rotate with the line
    • markerWidth and markerHeight define a bounding box (like a viewBox) to use for the marker.
      • Note that these are then scaled by the stroke-width of the final line; having a height of "4" causes it to be 20 units wide in the final drawing (4×5).
    • refX and refY define where the 'origin' is when placing the shape on the end of the path
      • I've used refX="0.1" to ensure that the marker overlaps the end of the line slightly
    • For the auto orientation to work correctly you want the "forward" direction of the marker to be in the +x direction. (The red path used for the marker looks like this ▶ when unrotated.)
    • You can adjust the fill-opacity and stroke-opacity of the marker and/or line independently, but changes to the opacity of the line will affect the drawn marker, as well.
      • Since the line and marker are overlapping, if you lower the fill-opacity of the marker you would see the overlap; however, if you lower the opacity of the line itself then the marker is composited fully-opaque over the line and the combination of the two are then lowered in opacity.

    If you want arrows along the length of the line, you will need to use marker-mid="…" with either <path> or <polyline> and interim points along the line.

    Demo: http://jsfiddle.net/Z5Qkf/2/

    The only problem is that any point that changes direction along the line messes up the orientation; this is why in the demo I've used a Bézier curve to round the corner so that the midpoint on the line is along a straight section.

    <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>​
    

    To do this procedurally, you can use JavaScript and the getPointAtLength() command for a path to sample the path.

    这篇关于如何沿 SVG 线放置多个均匀间隔的箭头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆