GSAP + SVG for Power Users 3: New 1.18.0 Features
Complete Series
This is the third article in a series about the GreenSock Animation API and SVG. This series isn't intended for beginners, but rather a deep dive into some of the more exciting and lesser-known features that one can work with after they've gotten past the initial introduction. The first article was about Motion Along a Path. The second was about Complex Responsive Animation. Today we'll briefly explore some new GSAP features, and use them to make a more involved animation.
Stagger Cycle
The first feature we'll cover is stagger cycle. The stagger feature in a lot of JavaScript animation libraries tends to be a incredibly useful tool for creating elegant animations, and is definitely a benefit over a CSS workflow to create the same effect. To create a stagger effect in CSS, you increment the delay using the element or pseudo element with the same keyframes:
@keyframes staggerFoo { to { background: orange; transform: rotate(90deg); } } .css .bar:nth-child(1) { animation: staggerFoo 1s 0.1s ease-out both; } .css .bar:nth-child(2) { animation: staggerFoo 1s 0.2s ease-out both; } .css .bar:nth-child(3) { animation: staggerFoo 1s 0.3s ease-out both; } .css .bar:nth-child(4) { animation: staggerFoo 1s 0.4s ease-out both; } .css .bar:nth-child(5) { animation: staggerFoo 1s 0.5s ease-out both; } .css .bar:nth-child(6) { animation: staggerFoo 1s 0.5s ease-out both; }
And in SASS, you could DRY it out a little:
@keyframes staggerFoo { to { background: orange; transform: rotate(90deg); } } @for $i from 1 through 6 { .sass .bar:nth-child(#{$i} ) { animation: staggerFoo 1s ($i * 0.1s) ease-out both; } }
However, with GSAP, you can create this effect with a single line of code:
TweenMax.staggerTo(".gsap .bar", 1, { backgroundColor: "orange", rotation: 90, ease: Sine.easeOut}, 0.1);
See the Pen here by Sarah Drasner (@sdras) on CodePen.
The conciseness is a workflow boon, especially if things need to be adjusted down the line.
With stagger cycle, we can now pass in multiple values to stagger between, something that would be exponentially complex in CSS. The syntax calls for an array of values:
TweenMax.staggerTo(".foo", 1, { cycle: { y: [75, 0, -75] }, ease: Power4.easeInOut }, 0.05);
Which you can also randomize, as well, for even more interesting effects.
var coord = [40, 800, 70, -200]; TweenMax.staggerTo(".foo", 1, { cycle: { x: function(i) { return coord[Math.floor(Math.random() * coord.length)]; } }, ease: Power4.easeInOut }, 0.1);
In the following pen, I simply staggered between three values for each element, and only applied it to one element in the SVG. With very little code (22 lines of JS) you can accomplish so much:
See the Pen SVG with Cycle Stagger by Sarah Drasner (@sdras) on CodePen.
Relative HSL Color Animation
This one is relatively simple. Get it? Relative? Hoo Boy. The ability to tween relative HSL color amounts is fantastic, because if you're going to create sophisticated color effects easily in animation, slightly adjusting:
- Hue
- Saturation
- Lightness
yields very powerful visuals. Say you wanted to turn a whole scene, every element a slightly different color, from day to night slowly. Previously the easiest way to do so was to slowly change the color value of each of these elements individually. You could put an overlay on the whole container, but that lacks sophistication and realism. Or, perhaps, use an SVG fe matrix filter- which is very unsemantic and not very intuitive to animate. Or even a CSS filter, that doesn't, as of yet, have a ton of support. Now, in one small piece of code, you can uniformly, and with great backwards compatibility, grab hundreds of elements and make them slightly darker, decrease their relative saturation, and slowly adjust their hue to turn them a slightly different shade. Tweening HSL also has the benefit of being able to be used for both background
(for divs) or fill
(for SVG) because it's not opinionated towards a certain type of property.
Here's a little demo to show how it works:
See the Pen Turtles that show Relative HSL tweening by Sarah Drasner (@sdras) on CodePen.
So many options! What's a good use case? Let's leave that up to your viewer. We can put the stagger cycle and the HSL color tweening together with some interaction. But instead of a night scene, let's make it a little more wild.
Because we are tweening relative values, we can combine effects on the buttons and get multiple outputs. We'll make two different buttons with slightly different relative effects. It's also worth mentioning that we finally have class operation on SVG in the 3.0.0 release of jquery and can easily control our tweens in interaction:
//button hue function hued() { //keeps the fill and background consistent relative hue changes var ch1 = "hsl(+=110%, +=0%, +=0%)", tl = new TimelineMax({ paused: true }); tl.add("hu"); tl.to(mult, 1.25, { fill: ch1 }, "hu"); //tweens for background because of divs and css tl.to(body, 1.25, { backgroundColor: ch1 }, "hu"); //the gauge responds to the action in the scene as if it's showing pressure tl.from(gauge, 2, { rotation: "-=70", transformOrigin: "50% 50%", ease: Bounce.easeOut }, "hu"); return tl; } var hue = hued(); //same thing for the tweens for button saturation (has some relative hue as well) function saturation() { var ch2 = "hsl(+=5%, +=2%, -=10%)", tl = new TimelineMax({ paused: true }); tl.add("sated"); tl.to(body, 1, { backgroundColor:ch2 }, "sated"); tl.to(mult, 2, { fill:ch2 }, "sated"); tl.from(gauge, 2, { rotation: "-=100", transformOrigin: "50% 50%", ease: Bounce.easeOut }, "sated"); return tl; } var sat = saturation(); // ... //detect class and either start or reverse the timeline depending $(but1).on('click', function(e) { e.preventDefault(); $(this).toggleClass('a-s'); if ($(this).hasClass('a-s')) { sat.restart(); } else { sat.reverse(); } }); $(but2).on('click', function(e) { e.preventDefault(); $(this).toggleClass('a-h'); if ($(this).hasClass('a-h')) { hue.restart(); } else { hue.reverse(); } });
We'll also make the scene stagger in with a bit more nuance with the new stagger cycle. But because we want all of the elements to come in and eventually look the same, it makes more sense to use a staggerFrom
than staggerTo
:
tl.staggerFrom(city, 0.75, { y: -50, scale: 0, cycle:{ x:[300, 100, 200], opacity:[0.5, 0.3, 0.2, 0.8], rotation:[50, 100, 150], }, transformOrigin: "50% 50%", ease: Back.easeOut }, 0.02, "in");
And that becomes our city constructor set:
See the Pen City Construction Site by Sarah Drasner (@sdras) on CodePen.
There is one more key feature in this release: tweening and morphing complex string-based values. This is such a mind-blowing feature, though, we'll spend a future article focusing on this feature.
This is the third part of a several-part series. As we move forward learning each of these techniques, we'll tie together different ways of working to create increasingly complex and engaging work. Stay tuned!
About Sarah Drasner
Sarah Drasner is currently a Senior UX Engineer at Trulia (Zillow Group) in San Francisco. She spends most of her time thinking about engaging user interfaces, animation, and how to weld together pieces of the DOM. You can find her on Codepen as sdras, on Twitter as @sarah_edo, or at sarahdrasnerdesign.com.