Animate SVG on scroll using GSAP - svg

GSAP has this ScrollTrigger plugin that will trigger animations on scroll, that I would like to use.
I already got a working SVG animation (without GSAP):
<svg width="596" height="255">
<linearGradient id="prog-mask" x1=0% x2="100%" y1="0%" y2="100%">
<stop offset="0%" stop-color="white" stop-opacity="1" />
<stop offset="5%" stop-color="white" stop-opacity="0">
<animate attributeName="offset" values="0; 1" dur="2s" begin="0s" repeatCount="0" fill="freeze" />
<animate attributeName="stop-opacity" values="0; 1" dur="2s" begin="2s" repeatCount="0" fill="freeze" />
</stop>
<stop offset="100%" stop-color="white" stop-opacity="0" />
</linearGradient>
<mask id="prog-render">
<rect x="0" y="0" width="100%" height="100%" fill="url(#prog-mask)"/>
</mask>
<pattern id="pattern-circles" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="6" cy="6" r="3" stroke="red" stroke-width="2" fill="transparent">
<animate attributeName="r" values="0; 5" dur="2s" begin="0s" repeatCount="0" fill="freeze" />
</circle>
</pattern>
<!-- The canvas with our applied pattern -->
<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-circles)" mask="url(#prog-render)"/>
</svg>
As mentioned, this SVG animation is not hooked up with GSAP (which I believe is a must if it should work in conjunction with the ScrollTrigger plugin?)
That's why I have tried to create this animation using GSAP:
// 1. offset
gsap.to("#prog-mask stop:nth-child(2)", {
duration: 2,
attr: { offset: 1, fill: "freeze" },
repeat: 1,
delay: 0
});
// 2. stop-opacity
gsap.to("#prog-mask stop:nth-child(2)", {
duration: 5,
attr: { stopOpacity: 1, fill: "freeze" },
repeat: 1,
delay: 2
});
// 3. r = radius
gsap.to("circle", {
duration: 5,
attr: { r: 5, fill: "transparent" },
repeat: 0,
delay: 0
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.0/gsap.min.js"></script>
<section>
<svg width="596" height="255">
<linearGradient id="prog-mask" x1=0% x2="100%" y1="0%" y2="100%">
<stop offset="0%" stop-color="white" stop-opacity="1" />
<stop offset="5%" stop-color="white" stop-opacity="0">
<!-- <animate attributeName="offset" values="0; 1" dur="2s" begin="0s" repeatCount="0" fill="freeze" />
<animate attributeName="stop-opacity" values="0; 1" dur="2s" begin="2s" repeatCount="0" fill="freeze" />-->
</stop>
<stop offset="100%" stop-color="white" stop-opacity="0" />
</linearGradient>
<mask id="prog-render">
<rect x="0" y="0" width="100%" height="100%" fill="url(#prog-mask)"/>
</mask>
<pattern id="pattern-circles" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="6" cy="6" r="0" stroke="red" stroke-width="1.5" fill="transparent">
<!--<animate attributeName="r" values="0; 5" dur="2s" begin="0s" repeatCount="0" fill="freeze" />-->
</circle>
</pattern>
<!-- The canvas with our applied pattern -->
<rect id="rect" x="0" y="0" width="100%" height="100%" fill="url(#pattern-circles)" mask="url(#prog-render)"/>
</svg>
</section>
As you can tell, I have basically just tried to replace the three <animate> elements with some GSAP code.
At this point the dots are revealed immediately and not revealed in a linear fashion from top left to bottom right.
Also, for some unknown reason, the whole rectangle is gradient (actually, I don't mind this effect, but I don't understand why it is happening?).
Do I have to animate this SVG in GSAP to use ScrollTrigger?
How can I get the original animation result using GSAP?
Why does this color gradient happen in the GSAP code?

Do I have to animate this SVG in GSAP to use ScrollTrigger?
It depends. If you just want to fire off an animation (SMIL animation, CSS animation, GSAP animation, whatever), you could use the ScrollTrigger callbacks to do that.
If you want to scrub through the animation it probably makes sense to make the animation in GSAP because it's easier to update. AFAIK, you can't tell SMIL animations to go to a specific progress point like you can with GSAP.
With that being said, pretty much everyone who animates SVGs regularly recommends using JS for your SVG animations in most cases (more info on that here).
Why does this color gradient happen in the GSAP code?
If you look at the SVG of the GSAP version with your dev tools you can see it's animating a stopOpacity attribute instead of the stop-opacity attribute. Using the regular attribute name (i.e. not camel-case) inside of quotes fixes that.
How can I get the original animation result using GSAP?
I'd make use of GSAP's timeline functionality to set things up like this: Demo.

Related

SVG pattern size relative to container shape

I am trying to create a svg pattern where size of it is relative to shape to which is applied. Pattern should consist of rect with linearGradient and text elements which repeats in x-axis n-times or every n pixels and is vertically aligned in middle of rect.
The results should look like this.
I have tried following approaches.
<svg width="100%" height="100">
<defs>
<linearGradient id="gradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#fff" />
<stop offset="100%" stop-color="#c6c6c6" />
</linearGradient>
<pattern id="pattern" width="25%" height="100%">
<rect width="100%" height="100%" fill="url(#gradient)"></rect>
<text x="10" y="50%" dx=50 fill="red">test</text>
</pattern>
</defs>
<rect width="1000" height="100" fill="url(#pattern)"></rect>
</svg>
This approach gives the result I want but the size of pattern is not relatve to shape to which is applied and fails when shape is resized, to solve this issue I have tried to create a pattern with patternContentUnits="objectBoundingBox" but then I am having problems positioning the text.
<svg width="100%" height="100%">
<defs>
<linearGradient id="gradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#fff" />
<stop offset="100%" stop-color="#c6c6c6" />
</linearGradient>
<pattern id="pattern" patternContentUnits="objectBoundingBox" width="25%" height="100%">
<rect width="1" height="1" fill="url(#gradient)"></rect>
<text x="0.1" y="0.5">test</text>
</pattern>
</defs>
<rect width="1000" height="100" fill="url(#pattern)"></rect>
</svg>
objectBoundingBox units are in the range [0, 1] so 10 is too big.
You'll need to use a suitable font-size too.
<svg width="100%" height="100%">
<defs>
<linearGradient id="gradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#fff" />
<stop offset="100%" stop-color="#c6c6c6" />
</linearGradient>
<pattern id="pattern" patternContentUnits="objectBoundingBox" width="25%" height="100%">
<rect width="1" height="1" fill="url(#gradient)"></rect>
<text transform="scale(0.2, 1)" x="0.1" y="0.5" font-size="0.1">test</text>
</pattern>
</defs>
<rect width="1000" height="100" fill="url(#pattern)"></rect>
</svg>

Why is my rotated SVG shifted?

I try to build a reflection of my text with gradient. But the reflection (the second text) has an off set and by applying the rotation the letters are shifting.
body {
background-color: black;
}
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1000" height="140" viewBox="0 0 1000 140">
<text x="260" y="70" font-size="60" fill=" #888888" style="text-anchor: right">Multimediale Kunst</text>
<defs>
<linearGradient id="linearGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#000000" />
<stop offset="10%" stop-color="#666666" />
</linearGradient>
</defs>
<text rotate="180" x="310" y="80" font-size="60" fill="url(#linearGradient)" style="text-anchor: right">Multimediale Kunst</text>
</svg>
This is happening because the rotate attribute rotates individual start points. So wider characters end up further away from narrow characters and vice-versa.
The rotate attribute is the wrong approach anyway. If you want to vertically flip the text, then you should use a transform that scales the object on the y axis by -1.
body {
background-color: black;
}
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1000" height="140" viewBox="0 0 1000 140">
<text x="260" y="70" font-size="60" fill=" #888888" style="text-anchor: right">Multimediale Kunst</text>
<defs>
<linearGradient id="linearGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="50%" stop-color="#000000" />
<stop offset="100%" stop-color="#666666" />
</linearGradient>
</defs>
<text x="260" y="-80" font-size="60" fill="url(#linearGradient)" style="text-anchor: right" transform="scale(1,-1)">Multimediale Kunst</text>
</svg>

How to graph a political coordinates graph

I'm trying to program a graph like this one:
I tried with SVG, but it's not very good since I had to use 2 different rectangles and didn't manage to get only the 4 edges to be rounded.
Here's my code:
<svg width="400" height="250">
<defs>
<linearGradient id="solids" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
<stop offset="50%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
<stop offset="50%" style="stop-color:rgb(0,255,0);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(0,255,0);stop-opacity:1" />
</linearGradient>
<linearGradient id="solids2" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="50%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
<stop offset="50%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
</linearGradient>
</defs>
<text x="135" y="12" style="fill:black;">Conservadorismo
<tspan x="150" y="240">Liberalismo</tspan>
<tspan x="20" y="125">Esquerda</tspan>
<tspan x="305" y="125">Direita</tspan>
</text>
<rect x="100" y="20" rx="20" ry="20" width="200" height="100" style="fill:url(#solids); opacity:0.76" />
<rect x="100" y="120" rx="20" ry="20" width="200" height="100" style="fill:url(#solids2); opacity:0.76" />
<line x1="100" y1="120" x2="300" y2="120" style="stroke:black;stroke-width:2" />
<line x1="200" y1="20" x2="200" y2="220" style="stroke:black;stroke-width:2" />
</svg>
What should I do to fix it or do it better?
I would use ordinary <rect> objects without rounded corners, and apply a clipPath to the whole drawing to round off the corners.
Here's a simple example:
<svg width="400" height="400" viewBox="0 0 400 400">
<defs>
<clipPath id="roundRect">
<rect x="10" y="10" rx="20" ry="20" width="380" height="380"/>
</clipPath>
</defs>
<g clip-path="url(#roundRect)">
<rect fill="#0a0" stroke="none" x="10" y="10" width="190" height="190"/>
<rect fill="#f00" stroke="none" x="200" y="10" width="190" height="190"/>
<rect fill="#0bf" stroke="none" x="10" y="200" width="190" height="190"/>
<rect fill="#fd0" stroke="none" x="200" y="200" width="190" height="190"/>
</g>
</svg>

svg transparent radial gradient in safari not working

I have a SVG radial gradient that works in Chrome, Firefox and even Internet Explorer but does not work in Safari. Any idea how to get this to work in Safari?
Here is the codepen: http://codepen.io/fractorr/pen/OVaYvV
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient r="50%" cy="50%" cx="50%" id="myRadialGradient2">
<stop stop-color="transparent" offset="0"></stop>
<stop stop-color="#000000" offset="1"></stop>
</radialGradient>
</defs>
<rect x="10" y="10" width="100" height="100" rx="10" ry="10" style="fill:blue;"/>
<rect x="10" y="10" width="100" height="100" rx="10" ry="10" style="fill:url(#myRadialGradient2); stroke: #005000; stroke-width: 3;"/>
</svg>
In your gradient's definition, alter the opacity for the stop points. So,instead of shifting the color from a given value to transparency, you would alter the transparency itself. The result seems to mimick the firefox behavior accurately.
Leaving the stop-color attributes in the code does not harm the displayed result. However, the duplicate computation is pointless, and given that bitmapping a gradient is relatively costly iirc, better drop it.
See here for a demo: http://codepen.io/anon/pen/aOQreP
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient r="50%" cy="50%" cx="50%" id="myRadialGradient2">
<stop stop-opacity="0" offset="0"></stop>
<stop stop-opacity="1" offset="1"></stop>
</radialGradient>
</defs>
<rect x="10" y="10" width="100" height="100" rx="10" ry="10" style="fill:blue;"/>
<rect x="10" y="10" width="100" height="100" rx="10" ry="10" style="fill:url(#myRadialGradient2); stroke: #005000; stroke-width: 3;"/>
</svg>
These modifications shouldn't affect the rendering on other platforms.
Tested on Safari 5.1.7 (7534.57.2) on Windows.

Cut off transparent radial gradient in SVG

I wanna make something like torch, I know I can use CSS for that. (image with circle and positioning absolute).But in this circumstances I can't, becouse it will create lot of problems.
We have red [div] on that we have darkness[svg>rect]. The problem is how to make transparent radius circle through that darkness ?
I prepared jsfiddle for my problem, I will be pleased if someone can edit it, to achieve my demands.
http://jsfiddle.net/BXM2G/2/
<div id="box">
<svg id="dark">
<defs>
<radialGradient id="rade" r="50%" cx="50%" cy="50%">
<stop stop-color="green" offset="0%" stop-opacity="1" />
<stop stop-color="green" offset="50%" stop-opacity="1"/>
<stop stop-color="back" offset="100%"stop-opacity="1" />
</radialGradient>
</defs>
<rect x="0" y="0" height="200" width="200"/>
<circle cx="90" cy="100" r="40" style="fill:url(#rade)"/>
</svg>
</div>
You can use a mask if you want to make a transparent hole in the svg.
Some further reading on that can be found here.
An interactive example using svg masking can be seen here. The interesting part being:
<radialGradient id="radGrad">
<stop offset="0" stop-color="white" stop-opacity="1"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<mask id="mask">
<circle id="c" cx="175" cy="175" r="50" fill="url(#radGrad)"
stroke-width="6" stroke-dasharray="6.28"/>
</mask>
...
<g mask="url(#mask)">
... masked content ...
</g>

Resources