Loïc
Loïc

Reputation: 11942

SVG line rotation and animation

I'm trying to have a line moving between two points.

In order to need only one gradient, I'm rotating the line using transform.

See this for details : SVG gradients direction

Now when I apply the animation on the line it behaves strangely. It's not going anywhere near the real destination, and I don't really understand what's happening.

Which is particulary weird is that if I remove the rotate transformation, the lines goes to the right point (but then obviously it's not having the right gradient).

<svg height="670.9" width="1920">
    <defs>
        <linearGradient y2="100%" x2="100%" y1="0%" x1="0%" id="linegradred">
            <stop style="stop-color:#F70D1A;stop-opacity:0" offset="0%" />
            <stop style="stop-color:#F70D1A;stop-opacity:0.3" offset="50%" />
            <stop style="stop-color:#F70D1A;stop-opacity:0.8" offset="100%" />
        </linearGradient>
    </defs>
    <circle cx="964" cy="426" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc"/>
    <circle cx="924" cy="230" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc" />
    <line class="svg_line_red" id="line_1442197044254" x1="964" y1="426" fill="url(#linegradred)" stroke="url(#linegradred)" x2="1030" y2="492" transform="rotate(-146.5346206536447 964 426)">
        <animate attributeName="x1" attributeType="XML" to="924" fill="freeze" dur="1.1s" />
        <animate attributeName="y1" attributeType="XML" to="230" fill="freeze" dur="1.1s" />
        <animate attributeName="x2" attributeType="XML" to="924" fill="freeze" dur="1s" />
        <animate attributeName="y2" attributeType="XML" to="230" fill="freeze" dur="1s" />
    </line>
    <circle cx="590" cy="344" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc" />
    <circle cx="924" cy="230" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc" />
    <line class="svg_line_red" id="line_1442197045251" x1="590" y1="344" fill="url(#linegradred)" stroke="url(#linegradred)" x2="707" y2="461" transform="rotate(-63.84566422168709 590 344)">
        <animate attributeName="x1" attributeType="XML" to="924" fill="freeze" dur="1.1s" />
        <animate attributeName="y1" attributeType="XML" to="230" fill="freeze" dur="1.1s" />
        <animate attributeName="x2" attributeType="XML" to="924" fill="freeze" dur="1s" />
        <animate attributeName="y2" attributeType="XML" to="230" fill="freeze" dur="1s" />
    </line>
    <circle cx="771" cy="363" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc" />
    <circle cx="924" cy="230" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc" />
    <line class="svg_line_red" id="line_1442197046253" x1="771" y1="363" fill="url(#linegradred)" stroke="url(#linegradred)" x2="838" y2="430" transform="rotate(-85.99981423948691 771 363)">
        <animate attributeName="x1" attributeType="XML" to="924" fill="freeze" dur="1.1s" />
        <animate attributeName="y1" attributeType="XML" to="230" fill="freeze" dur="1.1s" />
        <animate attributeName="x2" attributeType="XML" to="924" fill="freeze" dur="1s" />
        <animate attributeName="y2" attributeType="XML" to="230" fill="freeze" dur="1s" />
    </line>
</svg>

Here's a fiddle : https://jsfiddle.net/qj7z2hhr/

Any help to understand why this behaves like that would be greatly appreciated.

Upvotes: 1

Views: 944

Answers (1)

Paul LeBeau
Paul LeBeau

Reputation: 101936

In SVG files, anything that is lower in the hierarchy is affected by things in their ancestor elements. So all the coordinates in your animations are also being affected by the rotation you are applying to their parent element (the line).

If you want to fix it, you will have to apply the translate animation after (ie. higher up than) the rotation. One way you could do that would be to surround the line with a group. Apply the rotation to the line and an animateTransform to the group.

Update

Actually what I suggested wouldn't work. I didn't account for the fact that you are animating both the start and end points of the line.

But I have another suggestion. Make each line be a vector based at (0,0) and be the length match the original line. I.e.:

x1=0        y1=0
x2=(x2-x1)  y2=(y2-y2)

Then you can create your desired animation as a combination of three animation components.

  1. a translate between the original start and end points.
  2. a scale from 1 to 0 to make the start and end converge to a single point
  3. a fixed rotation transform to make your line and gradient point in the correct direction

Here's the result. I've just implemented two of the lines to show you how it works. I'll leave you to decide whether this is simpler than just having multiple gradients, or not.

<svg viewBox="0 0 1920 670.9">
    <defs>
        <linearGradient y2="100%" x2="100%" y1="0%" x1="0%" id="linegradred">
            <stop style="stop-color:#F70D1A;stop-opacity:0" offset="0%" />
            <stop style="stop-color:#F70D1A;stop-opacity:0.3" offset="50%" />
            <stop style="stop-color:#F70D1A;stop-opacity:0.8" offset="100%" />
        </linearGradient>
    </defs>

    <circle cx="964" cy="426" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc"/>
    <circle cx="924" cy="230" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc" />

    <line class="svg_line_red" id="line_1442197044254"
          x2="66" y2="66"
          fill="url(#linegradred)" stroke="url(#linegradred)">
        <animateTransform attributeName="transform" attributeType="XML"
                          type="translate" from="964 426" to="924 230" dur="1.1s"
                          additive="sum" fill="freeze" />
        <animateTransform attributeName="transform" attributeType="XML"
                          type="scale" from="1" to="0" dur="1.1s"
                          additive="sum" fill="freeze" />
        <animateTransform attributeName="transform" attributeType="XML"
                          type="rotate" from="-146.5" to="-146.5" dur="1.1s"
                          additive="sum" fill="freeze" />
    </line>

    <circle cx="590" cy="344" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc" />
    <circle cx="924" cy="230" r="4" stroke="black" fill="black" opacity="0.5" class="circle_loc" />

    <line class="svg_line_red" id="line_1442197045251"
          x2="117" y2="116"
          fill="url(#linegradred)" stroke="url(#linegradred)">
        <animateTransform attributeName="transform" attributeType="XML"
                          type="translate" from="590 344" to="924 230" dur="1.1s"
                          additive="sum" fill="freeze" />
        <animateTransform attributeName="transform" attributeType="XML"
                          type="scale" from="1" to="0" dur="1.1s"
                          additive="sum" fill="freeze" />
        <animateTransform attributeName="transform" attributeType="XML"
                          type="rotate" from="-63.8" to="-63.8" dur="1.1s"
                          additive="sum" fill="freeze" />
    </line>

</svg>

Upvotes: 1

Related Questions