Animating element moving to the beginning/end of a path? - javascript

I'm animating an element along a path, and while the animation works fine I need to be able to animate the element going TO the path, and then along it.
I can't find any examples of ways to do this, should I create an invisible element so I have a target to animate that element to before it starts on the path? If so how could I do that, or is there a better way?
This is my path.
<svg width="100%" height="100%" viewBox="0 0 840 840" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="rg1" cx="0.474" cy="0.472" r="50%">
<stop offset="5%" style="stop-color:violet;" />
<stop offset="15%" style="stop-color:indigo;" />
<stop offset="30%" style="stop-color:blue;" />
<stop offset="40%" style="stop-color:lime;" />
<stop offset="75%" style="stop-color:yellow;" />
<stop offset="90%" style="stop-color:orange;" />
<stop offset="100%" style="stop-color:red;" />
</radialGradient>
</defs>
<g id="spirals" transform="translate(420,420) rotate(270)"
style="fill:none;stroke-width:6px;stroke-linecap:round;">
<path id="spiral" style="stroke:url(#rg1);"
d="M0,0C3.36,0.06,6.6,-2.82,7.07,-7.07C7.66,-11.26,5.28,-16.67,0,-20C-5.18,-23.4,-13.27,-24.43,-21.21,-21.21C-29.13,-18.12,-36.69,-10.51,-40,0C-43.42,10.46,-42.3,23.68,-35.36,35.36C-28.53,47,-15.79,56.71,0,60C15.69,63.43,34.14,60.2,49.5,49.5C64.88,38.98,76.71,21.03,80,0C83.43,-20.92,78.08,-44.6,63.64,-63.64C49.44,-82.74,26.27,-96.74,0,-100C-26.16,-103.45,-55.05,-95.94,-77.78,-77.78C-100.6,-59.88,-116.76,-31.53,-120,0C-123.48,31.43,-113.8,65.49,-91.92,91.92C-70.34,118.47,-36.76,136.79,0,140C36.66,143.5,75.94,131.67,106.07,106.07C136.34,80.79,156.81,42,160,0C163.53,-41.9,149.54,-86.4,120.21,-120.21C91.24,-154.2,47.24,-176.83,0,-180C-47.13,-183.56,-96.85,-167.4,-134.35,-134.35C-172.06,-101.7,-196.86,-52.47,-200,0C-203.55,52.4,-185.28,107.29,-148.49,148.49C-112.14,189.9,-57.74,216.9,0,220C57.63,223.58,117.75,203.14,162.63,162.63C207.77,122.6,236.92,62.97,240,0C243.62,-62.86,220.98,-128.21,176.78,-176.78C133.05,-225.63,68.21,-256.95,0,-260C-68.13,-263.64,-138.65,-238.85,-190.92,-190.92C-243.49,-143.49,-276.98,-73.47,-280,0C-283.66,73.36,-256.71,149.1,-205.06,205.06C-153.94,261.36,-78.71,297,0,300C78.6,303.69,159.56,274.58,219.2,219.2C279.23,164.4,317.02,83.94,320,0C323.72,-83.84,292.44,-170.01,233.35,-233.35C174.84,-297.12,89.21,-337.04,0,-340C-89.07,-343.71,-180.46,-310.32,-247.49,-247.49C-315,-185.31,-357.03,-94.41,-360,0C-363.74,94.33,-328.18,190.91,-261.63,261.63C-195.75,332.86,-99.67,377.06,0,380C99.57,383.76,201.36,346.05,275.77,275.77C350.73,206.2,397.08,104.91,400,0" />
</g>
</svg>

maybe this is what you need. This is done with SMIL Animation:
<svg width="100%" height="100%" viewBox="0 0 840 840" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="rg1" cx="0.474" cy="0.472" r="50%">
<stop offset="5%" style="stop-color:violet;" />
<stop offset="15%" style="stop-color:indigo;" />
<stop offset="30%" style="stop-color:blue;" />
<stop offset="40%" style="stop-color:lime;" />
<stop offset="75%" style="stop-color:yellow;" />
<stop offset="90%" style="stop-color:orange;" />
<stop offset="100%" style="stop-color:red;" />
</radialGradient>
</defs>
<g>
<path id="spiral" style="fill:none;stroke:url(#rg1);stroke-width:6px;stroke-linecap:round" d="m 420,420 c 0.06,-3.36 -2.82,-6.6 -7.07,-7.07 -4.19,-0.59 -9.6,1.79 -12.93,7.07 -3.4,5.18 -4.43,13.27 -1.21,21.21 3.09,7.92 10.7,15.48 21.21,18.79 10.46,3.42 23.68,2.3 35.36,-4.64 C 467,448.53 476.71,435.79 480,420 c 3.43,-15.69 0.2,-34.14 -10.5,-49.5 -10.52,-15.38 -28.47,-27.21 -49.5,-30.5 -20.92,-3.43 -44.6,1.92 -63.64,16.36 -19.1,14.2 -33.1,37.37 -36.36,63.64 -3.45,26.16 4.06,55.05 22.22,77.78 17.9,22.82 46.25,38.98 77.78,42.22 31.43,3.48 65.49,-6.2 91.92,-28.08 C 538.47,490.34 556.79,456.76 560,420 563.5,383.34 551.67,344.06 526.07,313.93 500.79,283.66 462,263.19 420,260 378.1,256.47 333.6,270.46 299.79,299.79 265.8,328.76 243.17,372.76 240,420 c -3.56,47.13 12.6,96.85 45.65,134.35 32.65,37.71 81.88,62.51 134.35,65.65 52.4,3.55 107.29,-14.72 148.49,-51.51 C 609.9,532.14 636.9,477.74 640,420 643.58,362.37 623.14,302.25 582.63,257.37 542.6,212.23 482.97,183.08 420,180 357.14,176.38 291.79,199.02 243.22,243.22 194.37,286.95 163.05,351.79 160,420 c -3.64,68.13 21.15,138.65 69.08,190.92 47.43,52.57 117.45,86.06 190.92,89.08 73.36,3.66 149.1,-23.29 205.06,-74.94 C 681.36,573.94 717,498.71 720,420 723.69,341.4 694.58,260.44 639.2,200.8 584.4,140.77 503.94,102.98 420,100 336.16,96.28 249.99,127.56 186.65,186.65 122.88,245.16 82.96,330.79 80,420 76.29,509.07 109.68,600.46 172.51,667.49 234.69,735 325.59,777.03 420,780 514.33,783.74 610.91,748.18 681.63,681.63 752.86,615.75 797.06,519.67 800,420 803.76,320.43 766.05,218.64 695.77,144.23 626.2,69.27 524.91,22.92 420,20"/>
</g>
<g><path style="fill:#ff0000" d="m 10,-50 30,0 c 5.54,0 10,4.46 10,10 l 0,30.0000001 C 50,-4.459999 45.54,0 40,0 L 10,0 C 4.46,0 0,-4.459999 0,-9.9999999 L 0,-40 c 0,-5.54 4.46,-10 10,-10 z"/>
<animateMotion id="animateMotion12-8" rotate="auto" repeatCount="indefinite" dur="15s" path="m 420,420 c 0.06,-3.36 -2.82,-6.6 -7.07,-7.07 -4.19,-0.59 -9.6,1.79 -12.93,7.07 -3.4,5.18 -4.43,13.27 -1.21,21.21 3.09,7.92 10.7,15.48 21.21,18.79 10.46,3.42 23.68,2.3 35.36,-4.64 C 467,448.53 476.71,435.79 480,420 c 3.43,-15.69 0.2,-34.14 -10.5,-49.5 -10.52,-15.38 -28.47,-27.21 -49.5,-30.5 -20.92,-3.43 -44.6,1.92 -63.64,16.36 -19.1,14.2 -33.1,37.37 -36.36,63.64 -3.45,26.16 4.06,55.05 22.22,77.78 17.9,22.82 46.25,38.98 77.78,42.22 31.43,3.48 65.49,-6.2 91.92,-28.08 C 538.47,490.34 556.79,456.76 560,420 563.5,383.34 551.67,344.06 526.07,313.93 500.79,283.66 462,263.19 420,260 378.1,256.47 333.6,270.46 299.79,299.79 265.8,328.76 243.17,372.76 240,420 c -3.56,47.13 12.6,96.85 45.65,134.35 32.65,37.71 81.88,62.51 134.35,65.65 52.4,3.55 107.29,-14.72 148.49,-51.51 C 609.9,532.14 636.9,477.74 640,420 643.58,362.37 623.14,302.25 582.63,257.37 542.6,212.23 482.97,183.08 420,180 357.14,176.38 291.79,199.02 243.22,243.22 194.37,286.95 163.05,351.79 160,420 c -3.64,68.13 21.15,138.65 69.08,190.92 47.43,52.57 117.45,86.06 190.92,89.08 73.36,3.66 149.1,-23.29 205.06,-74.94 C 681.36,573.94 717,498.71 720,420 723.69,341.4 694.58,260.44 639.2,200.8 584.4,140.77 503.94,102.98 420,100 336.16,96.28 249.99,127.56 186.65,186.65 122.88,245.16 82.96,330.79 80,420 76.29,509.07 109.68,600.46 172.51,667.49 234.69,735 325.59,777.03 420,780 514.33,783.74 610.91,748.18 681.63,681.63 752.86,615.75 797.06,519.67 800,420 803.76,320.43 766.05,218.64 695.77,144.23 626.2,69.27 524.91,22.92 420,20"/>
</g>
</svg>

I was able to create a solution. I wanted to animate an element along a path, but the element doesn't start exactly where the path begins. In my example the path starts on the top-middle side of the container, but the element is closer to the top-left side of the container. This moves an element toward the top-middle side, then starts the animation along the path once the element reaches it.
The code could be adapted to other similar situations. I'm sure there are better ways but I've gone through the GSAP and anime.js libraries and couldn't find a way to do it without the Flip plug-in from GSAP which is under the paid license.
let element_position = element.getBoundingClientRect()
let path_container_position = path_container.getBoundingClientRect()
let tl = gsap.timeline()
tl.to(element, {
x: path_container_position.left - element_position.left + (path_container_position.width / 2) - (element_position.width / 2),
y: path_container_position.top - element_position.top - (element_position.height / 2),
ease: 'none',
duration: 5,
})
tl.to(element, {
motionPath: {
path: path_container,
align: path_container,
alignOrigin: [0.5, 0.5]
},
ease: "power4.easeInOut",
duration: 10,
yoyo: true,
repeat: -1,
})

Related

How can I set the offset on a straight line in svg

I want to make a linear gradient on a straight line.But the offset always remains constant does not change because it is a straight line.
For example, the first stop is color red and the second stop is color blue, but the offset is a single color.
<defs>
<linearGradient id="Gradientm5cf5" x1="11.111" x2="33.111" y1="44.111" y2="77.111" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="red"></stop>
<stop offset="50%" stop-color="blue"></stop>
</linearGradient>
</defs>
<path d="M 1518 1131 L 1681.63 1131" fill="none" stroke="url(#Gradientm5cf5)" stroke-miterlimit="10" pointer-events="stroke" stroke-width="6" style="--animation-time:1s;" class="flow">
</path>

How to calculate the position of a circle depending on the current time on the curve

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1158 696">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:red;stop-opacity:1" />
<stop offset="50%" style="stop-color:blue;stop-opacity:1" />
<stop offset="100%" style="stop-color:red;stop-opacity:1" />
</linearGradient>
</defs>
<g><g><g><path fill="none" stroke="url(#grad1)" stroke-miterlimit="50" stroke-width="4" d="M0 212.4c241.4 0 274.174-213.852 579-210 304.826 1.853 345.472 211 581 210"/></g></g></g>
<g>
<g opacity=".76">
<path fill="#011134" d="M.25 214.001c239.653 0 274.65-213.852 580.005-210 305.355 3.853 340.062 210 580.005 210v486H.25v-486z"/>
</g>
</g>
<g transform="translate(0, 198)" >
<filter id="blurMe">
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
</filter>
<circle filter="url(#blurMe)" cx="16" cy="16" r="12" fill="red" />
</g>
</svg>
I've tried to use a formula of Normal distribution
I need to achive a result where the circle moves along the curve depends on the current time for that i need to find a formula which represents the graph described above, but the Gaussian distribution does not give me a desirable graph, the Gaussian distribution gives me next:

Is it possible to start/stop SVG gradients at a certain absolute position?

I am creating in Javascript different L- shaped paths. They differ in length and in position. I would like to have a linearGradient as a stroke for them, where the first stop offset is at the position of x=10 pixels, i.e. the change in color always starts after x pixels.
Using gradient the standard way just offers relative positioning (e.g. wrt the object bounding box). This results in different stop offsets due to the different object bounding boxes.
Here is one example how it looks like:
path.p1 {
fill: none;
stroke-width: 20px;
}
<svg height="600" width="1000">
<path class="p1" d="M10 10 V 100 H 100 " stroke="url(#cl1)"/>
<path class="p1" d="M150 10 V 100 H 200 " stroke="url(#cl1)"/>
<path class="p1" d="M250 10 V 100 H 400 " stroke="url(#cl1)"/>
<defs>
<linearGradient id="cl1" gradientUnits="objectBoundingBox" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0" style="stop-color:grey;stop-opacity:1" />
<stop offset="0.02" style="stop-color:grey;stop-opacity:1" />
<stop offset="0.15" style="stop-color:orange;stop-opacity:1" />
<stop offset="0.2" style="stop-color:orange;stop-opacity:1" />
</linearGradient>
</defs>
</svg>
Is there a way to use one gradient but a clever way to reference it through SVG nesting or javascript?
Use gradientUnits="userSpaceOnUse". This way, the gradient is positioned in absolute units, but always in the local coordinate system of the element it is defined on.
In your case, having all paths in the same coordinate system would mean you defined an overall gradient spanning all paths. To avoid that, you have to change that, for example by defining a transform attribute. Each consecutive path is moved more to the right, while its starting point, measured in the local coordinate system, remains in the same place.
path.p1 {
fill: none;
stroke-width: 20px;
}
<svg height="600" width="1000">
<path class="p1" d="M10 10 V 100 H 100 " stroke="url(#cl1)"/>
<path class="p1" d="M10 10 V 100 H 60 " stroke="url(#cl1)" transform="translate(140)"/>
<path class="p1" d="M10 10 V 100 H 160 " stroke="url(#cl1)" transform="translate(240)"/>
<defs>
<linearGradient id="cl1" gradientUnits="userSpaceOnUse" x1="10" y1="0" x2="110" y2="0">
<stop offset="0" style="stop-color:grey;stop-opacity:1" />
<stop offset="0.02" style="stop-color:grey;stop-opacity:1" />
<stop offset="0.15" style="stop-color:orange;stop-opacity:1" />
<stop offset="0.2" style="stop-color:orange;stop-opacity:1" />
</linearGradient>
</defs>
</svg>

SVG Filter does not binds to its icon

I have a simple SVG icon, where I need to set the linearGradient for it. I'm trying to make it by specifying id of filter to the SVG body, but it does not wok, because in such way I got an empty SVG icon at all... Why?
<svg xmlns="http://www.w3.org/2000/svg" class="default___3oPC0 " style=" fill: url(#chat); filter: url(#chat); " fill="black" stroke="black" stroke-width="0" width="21px" height="21px" viewBox="0 0 17 17">
<filter id="chat">
<linearGradient>
<stop offset="0" stop-color="#cecebf"></stop>
<stop offset="1" stop-color="#9b9b8c"></stop>
</linearGradient>
</filter>
<path d="M7.08,3a6.14,6.14,0,0,0-2.14.37,5.34,5.34,0,0,0-1.68,1A3.64,3.64,0,0,0,1.89,7.07a3.26,3.26,0,0,0,.44,1.62,4.48,4.48,0,0,0,1.33,1.42,2,2,0,0,1,.83,1.38,2.7,2.7,0,0,1,0,.28l.12-.12A1.8,1.8,0,0,1,6,11.07h.24a6.11,6.11,0,0,0,.86.06,6.43,6.43,0,0,0,2.15-.37,5.29,5.29,0,0,0,1.67-1,3.62,3.62,0,0,0,1.38-2.74A3.62,3.62,0,0,0,10.9,4.33a5.29,5.29,0,0,0-1.67-1A6.19,6.19,0,0,0,7.08,3Zm0-2h0C11,1,14.17,3.72,14.17,7.07S11,13.14,7.08,13.14A10,10,0,0,1,6,13.07,6.57,6.57,0,0,1,.94,15v-.39A2.89,2.89,0,0,0,2.66,12.2a2.73,2.73,0,0,0,0-.41A5.78,5.78,0,0,1,0,7.07C0,3.72,3.17,1,7.08,1ZM14.7,14.6a2.32,2.32,0,0,0,1.36,2.06V17a5.46,5.46,0,0,1-4.24-1.66,7.5,7.5,0,0,1-1,.06,6.87,6.87,0,0,1-3.74-1.07,8.79,8.79,0,0,0,5.68-2.05A7.09,7.09,0,0,0,14.6,10a6.45,6.45,0,0,0,.69-2.91c0-.16,0-.33,0-.49A4.81,4.81,0,0,1,17,10.2a4.93,4.93,0,0,1-2.28,4C14.71,14.36,14.7,14.48,14.7,14.6Z"></path>
</svg>
You might need to apply the fill to the path using an ID attached to the gradient
svg {
height: 200px;
}
path {
fill: url(#chat);
}
<svg xmlns="http://www.w3.org/2000/svg" class="default___3oPC0" viewBox="0 0 17 17">
<linearGradient id="chat">
<stop offset="0" stop-color="#cecebf"></stop>
<stop offset="1" stop-color="#9b9b8c"></stop>
</linearGradient>
<path d="M7.08,3a6.14,6.14,0,0,0-2.14.37,5.34,5.34,0,0,0-1.68,1A3.64,3.64,0,0,0,1.89,7.07a3.26,3.26,0,0,0,.44,1.62,4.48,4.48,0,0,0,1.33,1.42,2,2,0,0,1,.83,1.38,2.7,2.7,0,0,1,0,.28l.12-.12A1.8,1.8,0,0,1,6,11.07h.24a6.11,6.11,0,0,0,.86.06,6.43,6.43,0,0,0,2.15-.37,5.29,5.29,0,0,0,1.67-1,3.62,3.62,0,0,0,1.38-2.74A3.62,3.62,0,0,0,10.9,4.33a5.29,5.29,0,0,0-1.67-1A6.19,6.19,0,0,0,7.08,3Zm0-2h0C11,1,14.17,3.72,14.17,7.07S11,13.14,7.08,13.14A10,10,0,0,1,6,13.07,6.57,6.57,0,0,1,.94,15v-.39A2.89,2.89,0,0,0,2.66,12.2a2.73,2.73,0,0,0,0-.41A5.78,5.78,0,0,1,0,7.07C0,3.72,3.17,1,7.08,1ZM14.7,14.6a2.32,2.32,0,0,0,1.36,2.06V17a5.46,5.46,0,0,1-4.24-1.66,7.5,7.5,0,0,1-1,.06,6.87,6.87,0,0,1-3.74-1.07,8.79,8.79,0,0,0,5.68-2.05A7.09,7.09,0,0,0,14.6,10a6.45,6.45,0,0,0,.69-2.91c0-.16,0-.33,0-.49A4.81,4.81,0,0,1,17,10.2a4.93,4.93,0,0,1-2.28,4C14.71,14.36,14.7,14.48,14.7,14.6Z"></path>
</svg>

directed gradient in svg's path element

I'm writing a simple webpage that displays a graph and shows dependencies. I found an unexpected behavior in how path elements are rendered within svg.
Here's the full HTML of the example:
<html>
<body>
<svg id="svgConnections" xmlns="http://www.w3.org/2000/svg" style="width: 300px; height: 120px">
<defs>
<linearGradient id="grad1" >
<stop offset="0%" style="stop-color:yellow;stop-opacity:1" />
<stop offset="100%" style="stop-color:red;stop-opacity:1" />
</linearGradient>
</defs>
<path d="M40,40 L100,100 Z" stroke="url(#grad1)" strokeWidth="1px" />
<path d="M200,100 L140,40 Z" stroke="url(#grad1)" strokeWidth="1px" />
</svg>
</body>
</html>
The same example is on https://jsfiddle.net/4fLjm0e2/
What bugs me is that the first line, which goes from top left to bottom right corner, looks exactly like the second line, which goes "in reverse": from bottom right corner to the top left.
How do I make the path always start with yellow and end with red?
This is not a bug. This is problem in understanding.
The default behavior of a linear gradient is to transition along a horizontal line from the left side of an object to its right side. It doesn't matter if you draw a path from left to right or from right to left. In both cases gradient will appear as from left to right as per default settings.
Consider the demo below:
<svg width="120" height="120" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad1" gradientUnits="userSpaceOnUse">
<stop offset="0%" style="stop-color:yellow;stop-opacity:1" />
<stop offset="100%" style="stop-color:red;stop-opacity:1" />
</linearGradient>
</defs>
<g stroke-width="2">
<path d="M10,40 L110,40 Z" stroke="url(#grad1)" />
<path d="M110,70 L10,70 Z" stroke="url(#grad1)" />
</g>
</svg>
If you wants the transition of colors to occur across a vertical line or a line at an angle, you must specify the line's starting point with the x1 and
y1 attributes and its ending points with the x2 and y2 attributes.
Rather than duplicate the stops into each <linearGradient> element, we'll use the xlink:href attribute to refer to the original gradient. The stops will be inherited, but the x- and y-coordinates will be overridden by each individual gradient.
<linearGradient id="grad1" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad2" xlink:href="#grad1" x1="1" y1="1" x2="0" y2="0"></linearGradient>
Extending the above example:
<svg width="120" height="120" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad1" gradientUnits="userSpaceOnUse">
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad2" xlink:href="#grad1" x1="120" y1="0" x2="0" y2="0"></linearGradient>
</defs>
<g stroke-width="2">
<path d="M10,40 L110,40" stroke="url(#grad1)" />
<path d="M110,70 L10,70 Z" stroke="url(#grad2)" />
</g>
</svg>
As in your example, you are using diagonal paths so we need to override x1, y1, x2 and y2 attribute of both <linearGradient> elements.
These values on the first <linearGradient> element will override the default left to right settings to produce a diagonal gradient from top left to the right bottom.
While on the <linearGradient> element these values will change the direction of gradient i.e from bottom to top.
Now we can apply these gradients to the respective paths.
<svg width="300" height="120" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad1" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="grad2" xlink:href="#grad1" x1="1" y1="1" x2="0" y2="0"></linearGradient>
</defs>
<g stroke-width="2">
<path d="M40,40 L100,100 Z" stroke="url(#grad1)" />
<path d="M200,100 L140,40 Z" stroke="url(#grad2)" />
</g>
</svg>
Note: This Question can be useful in context with the current problem.

Categories