在SVG中旋转形状时保持旋转线性渐变不旋转

时间:2017-11-27 16:41:05

标签: wpf svg linear-gradients

(SVG或WPF XAML - 我愿意(并且需要)两者。我不认为它们在实现方面有任何不同。下面的例子是在SVG中。

我正在尝试找到一种在线性渐变上使用旋转的方法(在这种情况下为270°),但是当它填充的形状旋转时,保持线性渐变不变,就好像它填充的形状不是旋转了。

举例来说,这就是Microsoft Word可以做的事情。使用线性渐变填充自选图形时,可以取消选中“使用形状旋转”,无论您如何旋转形状,线性渐变都将保持不变。

所以,这是一个例子,我想在它的中心旋转线性渐变270°(在linearGradient定义中gradientTransform="rotate(270 0.5 0.5)")。在那之后,我想要旋转它填充45°的路径(在pathtransform="rotate(45 0.5 0.5)")。

<svg width="960" height="540" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
 <svg x="265.24353" y="133.125046" width="337.287231" height="211.206543" viewBox="0 0 337.287231 211.206543" style="overflow: visible;" >
    <defs>
    <linearGradient id="linear"  gradientTransform="rotate(270 0.5 0.5)" spreadMethod="pad" >
      <stop offset="0%" stop-color="#FF0000"/>
      <stop offset="48%" stop-color="#FF0000"/>
      <stop offset="48%" stop-color="#0070C0"/>
      <stop offset="100%" stop-color="#0070C0"/>
    </linearGradient>
  </defs>
  <path id="9" fill="url(#linear)"  transform="rotate(45 0.5 0.5)" stroke="#000000" stroke-width="5" stroke-linecap="round" d="M0,0L205.8147,0L205.8147,174.9073L0,174.9073Z"/>
  </svg>
</svg>

好的,所以这个没有工作,对吧?它不应该。所以我尝试从270°(林氏渐变的旋转)减去45°(路径的旋转)225°,然后在linearGradient集合gradientTransform="rotate(225 0.5 0.5)"减去。这让我很接近。真的很近那么我尝试降低角度和voilà,它大约是221°似乎是正确的。低于270°-45°4°。

所以我再次尝试这个策略,路径旋转65° - 我知道linearGradient的旋转(原来是270°)不会是205°,但是接近那个,啊哈!它是201°(或者某个浮点)比270°-65°低4°。

我怎么知道它比两种情况下的减法低了270°-65°?我注意linearGradient中的分隔符,以确保它是水平的。

那么无论linearGradient旋转角度或形状的旋转角度如何,都有办法计算上述内容吗?例如,如果线性渐变的旋转是180°(垂直划分上面的例子)或任何其他程度?如果我能想出如何在这里插入JS Fiddle,我会提供更多可以运行的例子。

更新(在WPF上):

@Clemens通过转换PathGeometry而非Path提供了一些敏锐的洞察力,了解如何在WPF中实现这一目标。真棒。

以下是转换Path的示例,与上面的SVG完全相同。

<Path RenderTransformOrigin="0.5,0.5" Data="M0,0L205.8147,0L205.8147,174.9073L0,174.9073Z" Stroke="Black" StrokeLineJoin="Miter" StrokeThickness="5">
        <Path.RenderTransform>
            <TransformGroup>
                <RotateTransform Angle="45" CenterY="0.5" CenterX="0.5"/>
            </TransformGroup>
        </Path.RenderTransform>
        <Path.Fill>
            <LinearGradientBrush StartPoint="0,1" EndPoint="1,1" >
                <LinearGradientBrush.RelativeTransform>
                    <TransformGroup>
                        <RotateTransform Angle="221" CenterY="0.5" CenterX="0.5"/>
                    </TransformGroup>
                </LinearGradientBrush.RelativeTransform>
                <GradientStopCollection>
                    <GradientStop Offset="0" Color="#FF0000" />
                    <GradientStop Offset="0.48" Color="#FF0000" />
                    <GradientStop Offset="0.48" Color="#0070C0" />
                    <GradientStop Offset="1" Color="#0070C0" />
                </GradientStopCollection>
            </LinearGradientBrush>
        </Path.Fill>
    </Path>

这就是改变PathGeometry的方法 - 它完全按照我的需要工作(好吧,除了旋转中心,但我想我可以解决这个问题。)

<Path RenderTransformOrigin="0.5,0.5" Stroke="Black" StrokeLineJoin="Miter" StrokeThickness="5" Canvas.Left="15" Canvas.Top="23" >
        <Path.Data>
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigure StartPoint="0,0" IsClosed="True">
                        <LineSegment Point="205.8147,0"/>
                        <LineSegment Point="205.8147,174.9073"/>
                        <LineSegment Point="0,174.9073"/>
                    </PathFigure>
                </PathGeometry.Figures>
                <PathGeometry.Transform>
                    <RotateTransform Angle="45" CenterY="0.5" CenterX="0.5"/>
                </PathGeometry.Transform>
            </PathGeometry>
        </Path.Data>
        <Path.Fill>
            <LinearGradientBrush StartPoint="0,1" EndPoint="1,1" >
                <LinearGradientBrush.RelativeTransform>
                    <TransformGroup>
                        <RotateTransform Angle="270" CenterY="0.5" CenterX="0.5"/>
                    </TransformGroup>
                </LinearGradientBrush.RelativeTransform>
                <GradientStopCollection>
                    <GradientStop Offset="0" Color="#FF0000" />
                    <GradientStop Offset="0.48" Color="#FF0000" />
                    <GradientStop Offset="0.48" Color="#0070C0" />
                    <GradientStop Offset="1" Color="#0070C0" />
                </GradientStopCollection>
            </LinearGradientBrush>
        </Path.Fill>
    </Path>

1 个答案:

答案 0 :(得分:1)

仅限SVG:

由于在元素上应用渐变的方式,角度不会相加。默认情况下..

  

(...)它实际上将渐变缩放到对象的大小,因此您只需要指定从0到1的值的坐标,并且它们会自动缩放到对象的大小

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

另一种看待它的方式;首先将渐变应用于正方形,然后拉伸以适合元素的边界框。请参阅此示例,其中所有三个元素具有相同的45度渐变:

&#13;
&#13;
<svg width="960" height="540" xmlns="http://www.w3.org/2000/svg" >
  <defs>
    <linearGradient id="linear" gradientTransform="rotate(45 0.5 0.5)" spreadMethod="pad">
      <stop offset="49%" stop-color="gold"/>
      <stop offset="51%" stop-color="blue"/>
    </linearGradient>
  </defs>
  
  <path fill="url(#linear)" d="M0,0   h170 v100 h-170"/>
  <path fill="url(#linear)" d="M210,0 h100 v100 h-100"/>
  <path fill="url(#linear)" d="M350,0 h100 v170 h-100"/>
</svg>
&#13;
&#13;
&#13;

所以在你的情况下,如果你想要一个225度角的渐变,想象一下将渐变压缩成方形,然后计算出角度的样子。

Angle squeezing math

长话短说,这里有一些代码:

https://jsfiddle.net/bc4k4Lcv/