【问题标题】:How to draw a part of a line in SVG?如何在 SVG 中绘制一条线的一部分?
【发布时间】:2017-06-07 09:17:53
【问题描述】:

有人知道是否/如何可以在点之间绘制一条线,同时与 SVG 中的端点保持一定距离吗?

如果这条线是水平的(例如,从(40,40)(100,40)),您可以轻松地绘制一条与以下点保持大约20 距离的线

<line x1="40" y1="40" x2="100" y2="40" desc="directional line" />
<line x1="60" y1="40" x2="80" y2="40" desc="actual part of line" />

然而,对于对角线,它有点难。要从(40,40)(100,100) 绘制一条(简单的)对角线,您需要cos(pi/4) = sin(pi/4) = sqrt(2) 来缩放您想要远离终点的距离(在本例中为:20*sqrt(2) = 14.1

<line x1="40" y1="40" x2="100" y2="100" desc="directional line" />
<line x1="54.1" y1="54.1" x2="85.9" y2="85.9" desc="actual part of line" />

此代码的演示可以在fiddle中找到

因此在计算时似乎可以这样做

  1. 方向线与水平线的夹角
  2. 角度的正弦和余弦
  3. 要绘制的线的实际部分的端点

这是唯一的方法还是 SVG 能够指定部分线条,或者有更智能、更方便的方法吗?

【问题讨论】:

    标签: svg line


    【解决方案1】:

    我不确定这是否明智或方便,但无需脚本即可执行此操作的一种方法如下。

    您可以使用矩形作为标记(marker-start 和marker-end),并且将markerWidth 和markerHeight 属性与线条的stroke-width 结合使用,您可以控制标记的大小。

    markerWidth * stroke-width = real width
    

    <svg width="220" height="220">
      <marker id="m1" orient="auto" viewBox="0 0 20 6" markerWidth="10" markerHeight="3" refX="20" refY="3">
        <rect x="0" y="0" width="20" height="6" fill="red" opacity="0.5" />
      </marker>
      <marker id="m2" orient="auto" viewBox="0 0 20 6" markerWidth="10" markerHeight="3" refX="0" refY="3">
        <rect x="0" y="0" width="20" height="6" fill="red" opacity="0.5" />
      </marker>
    
      <line id="l2" x1="20" y1="20" x2="200" y2="80" marker-end="url(#m1)" marker-start="url(#m2)" stroke="black" stroke-width="2" />
    
    </svg>

    现在假设我们使用白色矩形,那么标记将以固定宽度与线重叠,并且我们与端点之间的距离是固定的。

    但这并不是我们真正想要的。要真正通过标记“切割”线条,您可以使用蒙版。所以把你的线画成一个蒙版,用白色笔划,但用黑色标记。

    将此蒙版应用于您的线条(不带标记)...您就可以了:一条带有可见笔划的线条,与端点有固定距离。

    优点:不涉及 javascript

    缺点:你必须画两次线

    function redraw() {
      var x1 = Math.random() * 200
      var y1 = Math.random() * 200
      var x2 = Math.random() * 200
      var y2 = Math.random() * 200
    
      l1.setAttribute("x1", x1)
      l1.setAttribute("y1", y1)
      l1.setAttribute("x2", x2)
      l1.setAttribute("y2", y2)
    
      l2.setAttribute("x1", x1)
      l2.setAttribute("y1", y1)
      l2.setAttribute("x2", x2)
      l2.setAttribute("y2", y2)
    
      c1.setAttribute("cx", x1)
      c1.setAttribute("cy", y1)
      c2.setAttribute("cx", x2)
      c2.setAttribute("cy", y2)
    }
    line {
      stroke-width: 2px
    }
    <svg width="220" height="220">
      <marker id="m1" orient="auto" viewBox="0 0 20 6" markerWidth="10" markerHeight="3" refX="20" refY="3">
        <rect x="0" y="0" width="20" height="6" fill="black" />
      </marker>
      <marker id="m2" orient="auto" viewBox="0 0 20 6" markerWidth="10" markerHeight="3" refX="0" refY="3">
        <rect x="0" y="0" width="20" height="6" fill="black" />
      </marker>
      <mask id="mask">
        <line id="l2" x1="20" y1="20" x2="200" y2="80" marker-end="url(#m1)" marker-start="url(#m2)" stroke="white" />
      </mask>
      <circle id="c1" cx="200" cy="80" r="5" fill="blue" />
      <circle id="c2" cx="20" cy="20" r="5" fill="blue" />
      <line id="l1" x1="20" y1="20" x2="200" y2="80" mask="url(#mask)" stroke="black" />
    </svg>
    
    <button onclick="redraw()">redraw</button>

    【讨论】:

      【解决方案2】:

      曾经很老套的做法是使用缩放到线条大小的圆形图案作弊。不完美,但取决于您的用例:

      <svg width="200" height="200" viewbox="0 0 200 200">
        <defs>
          <pattern id="patt" width="1" height="1" patternContentUnits="objectBoundingBox">
            <rect x="0" y="0" width="1" height="1" fill="cyan" />
            <circle cx=".5" cy=".5" r=".4" fill="blue" />
          </pattern>
        </defs>
        
        <g id="hand-drawn">
          <line x1="40" y1="40" x2="100" y2="100" stroke="red" stroke-width="2" />
          <line x1="54.1" y1="54.1" x2="85.9" y2="85.9" stroke="green" stroke-width="2" />
        </g>
        
        <g id="circle-pattern">
          <line x1="80" y1="60" x2="200" y2="100" stroke="url(#patt)" stroke-width="2" />
          <line x1="150" y1="10" x2="100" y2="120" stroke="url(#patt)" stroke-width="2" />
          <line x1="0" y1="100" x2="150" y2="100" stroke="url(#patt)" stroke-width="2" />
          <line x1="0" y1="100" x2="150" y2="101" stroke="url(#patt)" stroke-width="2" />
        <g>
      </svg>

      当然,这只是为您提供了一种方法来显示一条线,该线距末端的特定百分比,而不是精确的像素值。希望这能给你一些想法。

      请注意,这有点错误 - 它不适用于水平线或垂直线......您必须将它们渲染为矩形或路径并使用填充而不是描边。

      【讨论】:

        猜你喜欢
        • 2017-09-28
        • 1970-01-01
        • 1970-01-01
        • 2020-11-09
        • 2021-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多