How to reverse animate linearGradient on mouseout with inline SVG only - svg

I want to create a smooth reverse animation on the svg linearGradient on mouseout. Is this possible with inline code only (without js or css)?
I have tried the following code but after the first mouseover animation finished it reverts back to frame 1 which ruins the smooth mouseout effect.
On mouseout I want to reverse the linearGradient smoothly.
https://codepen.io/daneli84/pen/WNejrdd
<svg viewBox="0 0 360 160" width="360" height="160" id="ani">
<defs>
<linearGradient id="lightGradient">
<stop offset="0%" stop-color="red">
<animate attributeName="stop-color" values="red; gold" dur=".5s"
fill="freeze" begin="ani.mouseover" />
</stop>
<stop offset="90%" stop-color="gold">
</stop>
</linearGradient>
</defs>
<circle cx="80" cy="80" r="50" fill="url(#lightGradient)"/>
</svg>
Expected results with using mouseout and a reverse linearGradient for a smooth reverse animation.

How about this. We animate one way on mouseenter and the reverse on mouseleave.
<svg viewBox="0 0 360 160" width="360" height="160" id="ani">
<defs>
<linearGradient id="lightGradient">
<stop offset="0%" stop-color="red">
<animate attributeName="stop-color" values="red; gold" dur=".5s"
fill="freeze" restart = "whenNotActive" begin="ani.mouseenter" />
<animate attributeName="stop-color" values="gold; red" dur=".5s"
fill="freeze" restart = "whenNotActive" begin="ani.mouseleave" />
</stop>
<stop offset="90%" stop-color="gold">
</stop>
</linearGradient>
</defs>
<circle cx="80" cy="80" r="50" fill="url(#lightGradient)"/>
</svg>

Related

svg circle tapered fading stroke

I am trying to create an svg file with a circle that has a tapered stroke that fades, meaning the stroke width will be the thickest (say 20px) with the original color and will be the thinnest (say 3px) on the opposite side where the color has faded. I was able to create the circle with color fading with the gradient tool, but I am struggling to figure out how to change the stroke width
Here's the code I have so far, which I created in Photoshop and exported to svg.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" height="500" viewBox="0 0 500 500">
<defs>
<style>
.cls-1 {
fill: none;
stroke-width: 20px;
stroke: url(#a);
}
</style>
<linearGradient id="a" x1="255.5" y1="240" x2="255.5" y2="51" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="rgba(96,0,0,1)"/>
<stop offset="1" stop-color="rgba(96,0,0,.1)"/>
</linearGradient>
</defs>
<circle class="cls-1" cx="255.5" cy="255.5" r="184.5"/>
</svg>
Here's an image of what I am trying to do.
Sorry, one more favor. I am trying to create an icon, so it will have four of these circles with different colors, with one fading to the top as shown, another fading to the bottom, and the other two to each of the sides. I will really appreciate it if you can also show me how to rotate :)
Thank you in advance.
Regards,
Mike
I would draw a bigger circle with a hole inside. In this case I'm using a mask. You can also draw a holloed path. In both cases you are using the gradient as a fill not as a stroke
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" height="500" viewBox="0 0 500 500">
<defs>
<style>
.cls-1 {
fill: url(#a);
}
</style>
<linearGradient id="a" x1="255.5" y1="240" x2="255.5" y2="51" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="rgba(96,0,0,1)"/>
<stop offset="1" stop-color="rgba(96,0,0,.1)"/>
</linearGradient>
<mask id="m">
<circle id="c1" cx="255.5" cy="255.5" r="184.5" fill="white" />
<circle fill="black" cx="255.5" cy="245.5" r="164.5"/>
</mask>
</defs>
<circle cx="255.5" cy="255.5" r="184.5" class="cls-1" mask="url(#m)" />
</svg>
And this is an example where I'm using a holloed path instead of the masked circle. Please note that in this case I'm centering the path atound the point x=0 y=0.
<svg width="500" height="500" viewBox="-250 -250 500 500">
<defs>
<style>
.cls-1 {
fill: url(#a);
}
</style>
<linearGradient id="a" y1="200" y2="-200" x1="0" x2="0" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="rgba(96,0,0,1)"/>
<stop offset="1" stop-color="rgba(96,0,0,.1)"/>
</linearGradient>
</defs>
<path class="cls-1" d="M184.5,0A184.5,184.5 0 0 1 -184.5,0A184.5,184.5 0 0 1 184.5,0M164.5,-10A164.5,164.5 0 0 0 -164.5,-10A164.5,164.5 0 0 0 164.5,-10"/>
</svg>
I am trying to create an icon, so it will have four of these circles
with different colors, with one fading to the top as shown, another
fading to the bottom, and the other two to each of the sides. I will
really appreciate it if you can also show me how to rotate
The first circle rotates clockwise
<animateTransform
attributeName="transform"
type="rotate"
values="0 150 150;360 150 150"
begin="svg1.click"
dur="10s"
repeatCount="indefinite"
/>
The second circle rotates counterclockwise.
Since the top circle is set to the opacity parameter fill-opacity: 0.5;
then the effect of changing the thickness of the stroke is created
Added gradient animation to both circles:
<animate
attributeName="stop-color"
dur="1.5s"
values="red;yellow;red"
repeatCount="indefinite"
/>
The text Click me has been added for demonstration it can be removed.
Below is the complete code:
.container {
width:50%;
height:50%;
}
svg {
background:black;
}
#path1 {
fill:url(#gradl);
stroke:none;
fill-opacity:1;
}
#path2 {
fill:url(#grad2);
stroke:none;
fill-opacity:0.5;
}
#crc1 {
stroke:none;
fill:black;
}
#txt1 {
fill:url(#grad2);
}
<div class="container">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 300 300" >
<defs>
<linearGradient id="gradl" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="red" stop-opacity="0.9">
<animate
attributeName="stop-color"
dur="1.5s"
values="red;yellow;red"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="yellow">
<animate
attributeName="stop-color"
dur="1.5s"
values="yellow;red;yellow" repeatCount="indefinite"
/>
</stop>
</linearGradient>
<linearGradient id="grad2" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="lime">
<animate
attributeName="stop-color"
dur="1.5s"
values="lime;purple;lime"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="purple">
<animate
attributeName="stop-color"
dur="1.5s"
values="purple;lime;purple" repeatCount="indefinite"
/>
</stop>
</linearGradient>
</defs>
<path id="path1" d="M71.9 78.4C90.8 58.1 122.9 50.7 150.6 51.5c26.2 0.7 54.9 10.5 72.8 29.7 16.9 18.1 22.9 45.8 23.4 70.6 0.5 25.1-3.2 54.4-20.7 72.4-18.5 19.1-49.4 24.5-76 24.3-25.4-0.2-54.4-6.3-72.4-24.3C59.5 205.8 53.9 176.5 53 150.8 52.2 125.9 55 96.7 71.9 78.4Z" >
<animateTransform
attributeName="transform"
type="rotate"
values="0 150 150;360 150 150"
begin="svg1.click"
dur="10s"
repeatCount="indefinite"
/>
</path>
<path id="path2" transform="rotate(45 150 150)"
d="M71.9 78.4C90.8 58.1 122.9 50.7 150.6 51.5c26.2 0.7 54.9 10.5 72.8 29.7 16.9 18.1 22.9 45.8 23.4 70.6 0.5 25.1-3.2 54.4-20.7 72.4-18.5 19.1-49.4 24.5-76 24.3-25.4-0.2-54.4-6.3-72.4-24.3C59.5 205.8 53.9 176.5 53 150.8 52.2 125.9 55 96.7 71.9 78.4Z" >
<animateTransform
attributeName="transform"
type="rotate"
values="360 148 148;0 148 148"
begin="svg1.click"
dur="10s"
repeatCount="indefinite" />
</path>
<circle id="crc1" cx="150" cy="150" r="90" />
<text id="txt1" x="80" y="160" font-size="36" font-weight="700" > Click me </text>
</svg>
</div>

Is it possible to convert a raidal gradient expressed in objectBoundingBox coordinates to userSpaceOnUse coordinates?

I have this radial gradient expressed in objectBoundingBox coordinates.
<svg width="300" height="300">
<defs>
<radialGradient id="MyGradient" gradientUnits="objectBoundingBox"
cx="0.3" cy="0.4" r="0.3" fx="0.1" fy="0.2">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="100"/>
</svg>
Is it possible to convert it to userSpaceOnUse coordinates?
For this question it is same to assume that each radial gradient only applies to one shape, and that we know x, y, width, and height of said shape.
<svg width="300" height="300">
<defs>
<radialGradient id="MyGradient" gradientUnits="userSpaceOnUse"
cx="?" cy="?" r="?" fx="?" fy="?">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="100"/>
</svg>
First I would show how to do it if the rect you fill with the gradient is a square:
svg{border:solid; width:45vw}
<svg viewBox="0 0 300 300">
<defs>
<radialGradient id="MyGradient" gradientUnits="objectBoundingBox"
cx="0.3" cy="0.4" r="0.3" fx="0.1" fy="0.2">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="200"/>
</svg>
<svg viewBox="0 0 300 300">
<defs>
<radialGradient id="MyGradient1" gradientUnits="userSpaceOnUse"
cx="110" cy="180" r="60" fx="70" fy="140" >
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient1)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="200"/>
</svg>
In the case of `gradientUnits="userSpaceOnUse":
The bounding box of the rect to fill is:
bb:{x:50, y:100, width:200, height:200}
The calculated attributes for gradientUnits="userSpaceOnUse" are:
cx = bb.x + bb.width *.3 = 50 + 200 * .3 = 110
cy = bb.y + bb.height *.4 100 + 200*.4 = 180
r = bb.width*.3 = 200*.3 = 60
fx = bb.x + bb.width *.1 = 50 + 200 * .1 = 70
fy = bb.y + bb.height *.2 = 100 + 200 * .2 = 140
So you can use
<radialGradient id="MyGradient1" gradientUnits="userSpaceOnUse" cx="110" cy="180" r="60" fx="70" fy="140" >
When using objectBoundingBox the values of the attributes of the radialGradient are taking values between 0 and 1 or 0 and 100% of the filled box.
You can also use objectBoundingBox as a value for clipPathUnits. Please take a look at the folowing example.
There is this clipPath where the clipping path is a circle. If the clipped shape is a square the result is a circle. If the clipped shape is a rectangle the result is an ellipse meaning that the clipping path is stretched according to the aspect ratio of the clipped shape.
<svg viewBox="0 0 120 60">
<defs>
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<circle cx=".5" cy=".5" r=".45" />
</clipPath>
</defs>
<rect id="r" x="5" y="5" width="50" height="50" />
<use xlink:href="#r" fill="gold" clip-path="url(#clip)" />
<rect id="r1" x="60" y="15" width="55" height="30" />
<use xlink:href="#r1" fill="gold" clip-path="url(#clip)" />
</svg>
The same is happening with the gradient. If the radial gradient with gradientUnits="objectBoundingBox" is used to fill a rectangle with a different width and height the result would be an elliptical gradient (as in your example). If you want to translate an elliptical gradient to gradientUnits="userSpaceOnUse" you would need a way to create a gradient with a different rx and ry. Unfortunately this is not posible.

Fill SVG from bottom to top

I've got an SVG I'm trying to animate from bottom to top with a fill. I want it to start as color code #ddd and I want it to end as #ccc filling in from the bottom over a 1 second duration. I'm having problems getting this to work correctly as it seems to look a bit strange.
This is what I've got so far.
<svg width="30px" height="30px" viewBox="0 0 30 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Dashboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-color="#ddd"/>
<stop offset="50%" stop-color="#ccc">
<animate attributeName="offset" values="0;1;0" dur="1s" begin="0s"/>
</stop>
<stop offset="100%" stop-opacity="1" stop-color="#ccc">
<animate attributeName="offset" values="0;1;0" dur="1s" begin="0s"/>
</stop>
</linearGradient>
<g transform="translate(-1161.000000, -558.000000)" fill="url(#lg)" id="current-net-wealth">
<g transform="translate(437.000000, 475.000000)">
<g id="houses" transform="translate(340.000000, 83.000000)">
<g id="house" transform="translate(384.000000, 0.000000)">
<polygon id="Path" points="21 6.66002593 21 3 25 3 25 11.1000432 30 16.6500648 25.3846154 16.6500648 25.3846154 30 4.61538462 30 4.62306431 16.6500648 0 16.6500648 15 0"></polygon>
</g>
</g>
</g>
</g>
</g>
</svg>
Do I need to add an additional stop to the linearGradiant animation?
Something like this.
If you want a duration of 1 second then that's what to write
Your values make the fill go up and down again
fill="freeze" makes the animated value remain after its duration is complete
Your colours don't match the ones you say you want
<svg width="30px" height="30px" viewBox="0 0 30 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Dashboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-color="#ccc"/>
<stop offset="0%" stop-color="#ccc">
<animate attributeName="offset" to="100%" dur="1s" begin="0s" fill="freeze"/>
</stop>
<stop offset="0%" stop-color="#ddd">
<animate attributeName="offset" to="100%" dur="1s" begin="0s" fill="freeze"/> </stop>
</linearGradient>
<g transform="translate(-1161.000000, -558.000000)" fill="url(#lg)" id="current-net-wealth">
<g transform="translate(437.000000, 475.000000)">
<g id="houses" transform="translate(340.000000, 83.000000)">
<g id="house" transform="translate(384.000000, 0.000000)">
<polygon id="Path" points="21 6.66002593 21 3 25 3 25 11.1000432 30 16.6500648 25.3846154 16.6500648 25.3846154 30 4.61538462 30 4.62306431 16.6500648 0 16.6500648 15 0"></polygon>
</g>
</g>
</g>
</g>
</g>
</svg>

Starting svg animation on the end of another animation doesn't trigger

I have two svg animations and I want to start #anim-join-gradient animation on the end of #anim-vert-gradient, but #anim-join-gradient animation doesn't start.
#anim-join-gradient element has attribute begin="anim-vert-gradient.end"
.box1{width:25px}
<div class="box box1">
<svg viewbox="0 0 100 100">
<path id="button" class="arrow" d="M 50,0 L 60,10 L 20,50 L 60,90 L 50,100 L 0,50 Z" />
</svg>
</div>
<svg id="play-vert-line" width="110" height="110">
<defs>
<linearGradient id="vert-gradient" gradientUnits="userSpaceOnUse" y1="0%" y2="100%" x1="0" x2="0">
<stop stop-color="#1689fb"></stop>
<stop stop-color="#7e7e7e"></stop>
<animate xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#vert-gradient" id="anim-vert-gradient" attributeName="y1" dur="800ms" to="99%" begin="button.click" fill="freeze"></animate>
</linearGradient>
</defs>
<line id="vert-line-1" x1="55.3" y1="0" x2="55.3" y2="105" stroke="url(#vert-gradient)" stroke-width="2"></line>
</svg>
<svg id="line-join" width="110" height="110">
<defs>
<linearGradient id="vert-join-gradient" gradientUnits="userSpaceOnUse" y1="0%" y2="100%" x1="0" x2="0">
<stop stop-color="#1689fb"></stop>
<stop stop-color="#7e7e7e"></stop>
<animate xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#vert-join-gradient" id="anim-join-gradient" attributeName="y1" dur="400ms" from="0%" to="99%" begin="anim-vert-gradient.end" fill="freeze"></animate>
</linearGradient>
</defs>
<line id="vert-line-2" x1="105" y1="0" x2="105" y2="105" stroke="url(#vert-join-gradient)" stroke-width="2"></line>
</svg>
minus signs are treated specially in begin attributes. Unescaped minus signs are treated as the subtraction operator. Per the spec you need to escape them if you don't want that e.g.
begin="anim\-vert\-gradient.end"
That would work on Firefox. Chrome has a bug and doesn't support escaping so if you want it to work there you'd have to remove the - signs.

Is it possible to apply a transform matrix to a SVG filter effect

I'm trying to recreate an iphone maps like push pin in SVG and I have the pin part down but I'm wondering how to tackle the shadow. I've seen a bunch of drop shadow examples but they're all just offsetting the original by a few pixels. Is it possible to apply a transform matrix to a filter so it's skewed?
Here's the pin SVG so far:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<radialGradient id="SVGID_1_" cx="29.3623" cy="31.1719" r="11.6241" gradientTransform="matrix(1.1875 0 0 1.1875 -30.8438 -30.2812)" gradientUnits="userSpaceOnUse">
<stop offset="0.2637" style="stop-color:#FF0000"/>
<stop offset="1" style="stop-color:#6D0000"/>
</radialGradient>
</defs>
<rect x="9.251" y="13.844" fill="#CCCCCC" stroke="#7C7C7C" width="2" height="24.83"/>
<circle fill="url(#SVGID_1_)" stroke="#660000" cx="10.5" cy="11.5" r="9.5"/>
<ellipse transform="matrix(0.8843 0.4669 -0.4669 0.8843 4.475 -1.6621)" fill="#FFCCCC" cx="6.591" cy="8.199" rx="1.538" ry="1.891"/>
</svg>
thanks!
Here is a simple transform and filter to rotate it. If you want to do the skewing too you will need to replace the rotate line with some matrix stuff.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<radialGradient id="SVGID_1_" cx="29.3623" cy="31.1719" r="11.6241" gradientTransform="matrix(1.1875 0 0 1.1875 -30.8438 -30.2812)" gradientUnits="userSpaceOnUse">
<stop offset="0.2637" style="stop-color:#FF0000"/>
<stop offset="1" style="stop-color:#6D0000"/>
</radialGradient>
<filter id="drop-shadow">
<feGaussianBlur in="SourceAlpha" result="blur-out" stdDeviation="1" />
</filter>
</defs>
<g id="pin">
<rect x="9.251" y="13.844" fill="#CCCCCC" stroke="#7C7C7C" width="2" height="24.83"/>
<circle fill="url(#SVGID_1_)" stroke="#660000" cx="10.5" cy="11.5" r="9.5"/>
<ellipse transform="matrix(0.8843 0.4669 -0.4669 0.8843 4.475 -1.6621)" fill="#FFCCCC" cx="6.591" cy="8.199" rx="1.538" ry="1.891"/>
</g>
<use xlink:href="#pin" transform="rotate(60 10.251 38.674)" filter="url(#drop-shadow)"/>
</svg>

Resources