跨 SVG 线的线性渐变

Linear gradient across SVG line

我想知道如何制作 linearGradient across (from top to bottom) 线,而不是下面渐变 along (from left to right) 线的示例。

<svg xmlns="http://www.w3.org/2000/svg" version="1">
<defs>
    <linearGradient id="e" x1="40" y1="210" x2="460" y2="210" gradientUnits="userSpaceOnUse">
        <stop stop-color="steelblue" offset="0" />
        <stop stop-color="red" offset="1" />
    </linearGradient>
</defs>
 <line x1="40" y1="210" x2="460" y2="210" stroke="url(#e)" stroke-width="30" />
</svg>

更改 y 坐标对于未旋转的线非常有效,linearGradient 现在(从上到下)穿过线:

<svg xmlns="http://www.w3.org/2000/svg" version="1">
<defs>
    <linearGradient id="e" x1="40" y1="195" x2="40" y2="225" gradientUnits="userSpaceOnUse">
        <stop stop-color="steelblue" offset="0" />
        <stop stop-color="red" offset="1" />
    </linearGradient>
</defs>
 <line x1="40" y1="210" x2="460" y2="210" stroke="url(#e)" stroke-width="30"/> 
</svg>

但是这个在旋转时不起作用:

<svg xmlns="http://www.w3.org/2000/svg" version="1">
<defs>
    <linearGradient id="e" x1="40" y1="235" x2="40" y2="265" gradientUnits="userSpaceOnUse">
        <stop stop-color="steelblue" offset="0" />
        <stop stop-color="red" offset="1" />
    </linearGradient>
</defs>
 <line x1="40" y1="210" x2="460" y2="290" stroke="url(#e)" stroke-width="30"/> 
</svg>

我想要的是带有线性渐变的旋转线。 是这样的:

你的意思是旋转渐变?然后使用 gradientTransform

<svg xmlns="http://www.w3.org/2000/svg" version="1">
<defs>
    <linearGradient id="e" x1="40" y1="210" x2="460" y2="210" gradientUnits="userSpaceOnUse" gradientTransform="rotate(90)">
        <stop stop-color="steelblue" offset="0" />
        <stop stop-color="red" offset="1" />
    </linearGradient>
</defs>
 <line x1="40" y1="210" x2="460" y2="210" stroke="url(#e)" stroke-width="30" />
</svg>

<svg width="600" height="200" viewBox="0 190 600 200" xmlns="http://www.w3.org/2000/svg" version="1">
<defs>
    <linearGradient id="e" x1="40" y1="210" x2="460" y2="290" gradientUnits="userSpaceOnUse">
        <stop stop-color="steelblue" offset="0" />
        <stop stop-color="red" offset="1" />
    </linearGradient>
</defs>
 <line x1="40" y1="210" x2="460" y2="290" stroke="url(#e)" stroke-width="30"/> 
</svg>

第一种情况的诀窍是使直线的 x1 y1,x2 y2 与线性渐变的 x1 y1,x2 y2 坐标相匹配。 对于第二种情况,它在数学方面涉及更多。 您必须创建一条垂直于第一条线且长度等于所需线宽的线,并且从其中一个点的宽度的一半开始。

所以在你的情况下(伪代码!):

第 1 步:

获取方向

   dx=x2-x1;
   dy=y2-y1;

dx,dy现在是点1到点2的方向

第 2 步:

通过将 dx 和 dy 除以线的长度将方向标准化为长度 1。

    len=Math.sqrt(dx*dx+dy*dy);
    dx=dx/len;
    dy=dy/len;

当然,如果 len=0,这将不起作用,但是因为你给了我坐标,所以我现在不必担心了。

第 3 步:

找到垂直方向。这其实很容易,但逻辑上可以是两个方向。我就选一个吧。

    temp=dx;
    dx=-dy;
    dy=temp;

如果你想要另一个方向,只需取反dx和dy。在这个过程之后。

    dx=-dx;
    dy=-dy;

dx,dy 现在保持垂直方向。

第 4 步:

将 dx 和 dy 乘以所需的线宽,在您的情况下为 30。我将其称为 w。

    dx=w*dx;
    dy=w*dy;

第 5 步:

要找到梯度的 p1 和 p2,从直线中取出 p1 并加上或减去 dx 的一半。

    gradient_x1=x1+dx*0.5;
    gradient_y1=y1+dx*0.5;
    gradient_x2=x1-dx*0.5;
    gradient_y2=y1-dx*0.5;

现在你可以再次建立你的阵容了。

为了向您展示我的意思,我插入了您的值并完成了整个操作,我明白了:

    Your case: (x1="40" y1="210" x2="460" y2="290" w=30)

    ## STEP1 ##
    dx: 420 dy:80

    ## STEP2 ##
    dx: 0.9823385664224747 dy:0.1871121078899952

    ## STEP3 ##
    dx: -0.1871121078899952 dy:0.9823385664224747

    ## STEP4 ##
    dx: -5.613363236699856 dy:29.47015699267424

    ## STEP5 ##
    gradient_x1=37.19331838165007
    gradient_y1=224.7350784963371

    gradient_x2=42.80668161834993
    gradient_y2=195.2649215036629

所以将其插入到您的示例中:

<svg width="600" height="200" viewBox="0 190 600 200" xmlns="http://www.w3.org/2000/svg" version="1">
<defs>
    <linearGradient id="e" x1="37.19331838165007" y1="224.7350784963371" x2="42.80668161834993" y2="195.2649215036629" gradientUnits="userSpaceOnUse">
        <stop stop-color="steelblue" offset="0" />
        <stop stop-color="red" offset="1" />
    </linearGradient>
</defs>
 <line x1="40" y1="210" x2="460" y2="290" stroke="url(#e)" stroke-width="30"/> 
</svg>

总结

幸运的是,我们根本不需要进行所有这些计算,因为我们有一台计算机并且 svg 元素可以很容易地被 javascript 操作。 要使用 javascript 获取 svg 中的元素,如果它们有一个 id 是最方便的。 你的渐变有一个 id="e",让我们给你的线和 id="l".

之后就是在页面中插入一个小脚本的问题 从直线 ("l") 中取出 x1 y1,x2 y2 并计算所有内容并将其放入梯度 ("e") 中,您会得到:

<svg width="600" height="200" viewBox="0 190 600 200" xmlns="http://www.w3.org/2000/svg" version="1">
  <defs>
    <linearGradient id="e" x1="0" y1="0" x2="1" y2="1" gradientUnits="userSpaceOnUse">
    <!-- put the coords on 0,0 1,1 it really doesn't matter, they will be calculated-->
      <stop stop-color="steelblue" offset="0" />
      <stop stop-color="red" offset="1" />
  </linearGradient>
  </defs>
  <line id="l" x1="40" y1="270" x2="450" y2="210" stroke="url(#e)" stroke-width="30"/> 
</svg>

<script>
  var line=document.getElementById("l");
  var x1=parseFloat(l.getAttribute("x1"));
  var y1=parseFloat(l.getAttribute("y1"));
  var x2=parseFloat(l.getAttribute("x2"));
  var y2=parseFloat(l.getAttribute("y2"));
  var w=parseFloat(l.getAttribute("stroke-width"));

  // step 1
  var dx=x2-x1;
  var dy=y2-y1;

  // step 2
  len=Math.sqrt(dx*dx+dy*dy);
  dx=dx/len;
  dy=dy/len;

  // step 3
  var temp=dx;
  dx=-dy;
  dy=temp;
  
  //step 4
  dx=w*dx;
  dy=w*dy;

  //step 5
  var gradient_x1=x1+dx*0.5;
  var gradient_y1=y1+dy*0.5;
  var gradient_x2=x1-dx*0.5;
  var gradient_y2=y1-dy*0.5;

  document.getElementById("e");
  e.setAttribute("x1",gradient_x1);
  e.setAttribute("y1",gradient_y1);
  e.setAttribute("x2",gradient_x2);
  e.setAttribute("y2",gradient_y2);
</script>

您可以自由编辑线条的起点和终点,甚至笔划宽度,脚本会即时修复您的渐变。 'prove' 这对你来说,这正是我所做的。 :) 希望这有帮助。