Complex SVG Animations with GreenSock (GSAP)
O'Reilly Fluent Session, March 2016
Sarah Drasner
Manager, UX Design and Engineering at Trulia
Why?
- Animation is powerful to convey meaning
- Can guide your users
- If built correctly, animation can be useful and performant
- Because otherwise we're not using the web to it's full potential
- FUN!
Main Principle:
Design everything first, slowly unveil things.
This pen.
Ugly storyboards save you time!
SVG!
- Crisp on any display
- Less HTTP requests to handle
- Easily scalable for responsive
- Small filesize if you design for performance
- Easy to animate
- Easy to make accessible
- Fun! (there's a pattern here)
SVG!
This pen.
Before we get started:
Optimize!
Before we get started:
Animation Performance!
- People expect mobile to be faster than web
- JankFree.org
- Advanced Performance Audits with DevTools by Paul Irish
- CSS-Tricks Article: Weighing SVG Animation Techniques with Benchmarks
- Above all else: test things yourself!
Let's make some cool stuff.
We're going to use some JavaScript.
GSAP, to be exact.
here's why...
(I don't work for them and they don't pay me.)
Solves Cross-Browser Inconsistencies
Bad transform origin bug on rotation, now solved in Firefox.
More in this CSS-Tricks article.
Chrome
IE
Firefox
Safari (zoomed)
Timeline
- stack tweens
- set them a little before and after one another
- change their placement in time
- group them into scenes
- add relative labels
- animate the scenes!
- make the whole thing faster, move the placement of the whole scene, nesting
All without recalculation!
The issue with longer CSS animations:
This pen.
How do we do it?
This pen.
Other Cool Things
for Complex Animation
- Motion along a path (widest support)
- Draggable
- CSS Properties
- Draw SVG- make an SVG look like it draws itself.
- MorphSVG
- Relative Color Tweening
- CycleStagger
Relative Color Tweening
This pen.
Incrementing
//button hue
function hued() {
var ch1 = "hsl(+=110%, +=0%, +=0%)",
tl = new TimelineMax({
paused: true
});
tl.add("hu");
tl.to(mult, 1.25, {
fill: ch1
}, "hu");
...
tl.to(body, 1.25, {
backgroundColor: ch1
}, "hu");
return tl;
}
var hue = hued();
Relative Color Tweening
This pen.
DrawSVG
DrawSVG
Plugin for GSAP, very simple code.
TweenMax.staggerFromTo($draw, 4,{ drawSVG:'0' }, { drawSVG: true }, 0.1);
Under the Hood
Done with stroke-dasharray and stroke-dashoffset
- Path or shape has a stroke
- The stroke is dashed
- Use JS to .getTotalLength()
- Dasharray the whole length of the shape
- Animate dashoffset
@keyframes dash {
50% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -274;
}
}
Motion Along a Path
Motion Along a Path for Realism
This pen.
TweenMax.to($firefly1, 6, {
bezier: {
type:"soft",
values:[{x:10, y:30}, {x:-30, y:20}, {x:-40, y:10},
{x:30, y:20}, {x:10, y:30}],
autoRotate:true
},
ease:Linear.easeNone, repeat:-1}, "start+=3");
function displayVals() {
//get the value from the dropdown
var singleValues = $("#single").val();
//the timeline for the changing animation
tl.to($('.s2'), 1.75, {
rotation: 360,
bezier: {
type: 'thru',
values: bezier,
curviness: singleValues
},
ease: Power1.easeInOut
});
}
displayVals();
Draggable
Draggable.create(features, {
edgeResistance: 0.65,
type: "x,y",
throwProps: true,
autoScroll: true
});
This pen.
Draggable
- Device-enabled for touchscreen
- Impose bounds- containing units or pixel parameters bounds:{top:100, left:0, width:1000, height:800}
- Momentum: If you have ThrowPropsPlugin you can set throwProps:true
- Draggable.hitTest() to sense if elements touch eachother
- Honors transform-origin
- Still works on transformed elements
- Lock movement to an axis lockAxis:true
- GPU-accelerated and requestAnimationFrame-driven
- more
Draggable to Control a Timeline Interaction
This pen.
Draggable to Control a Timeline Interaction
TweenMax.set($("#flowers1, #radio, #burst, #magnolia, #flowers2, #starfish, #berries1, #berries2, #berries3, #skulls, #tv, #glitch, #shadow, #lights"), {
visibility: "visible"
});
// the first scene
function sceneOne() {
var tl = new TimelineMax();
tl.add("start");
tl.staggerFromTo($f1, 0.3, {
scale: 0
}, {
scale: 1,
ease: Back.easeOut
}, 0.05, "start");
...
return tl;
}
var master = new TimelineMax({paused:true});
master.add(sceneOne(), "scene1");
Draggable to Control a Timeline Interaction
Draggable.create($gear, {
type: "rotation",
bounds: {
minRotation: 0,
maxRotation: 360
},
onDrag: function() {
master.progress((this.rotation)/360 );
}
});
- onPress
- onDragStart
- onDrag
- onDragEnd
- onRelease
- onLockAxis
- onClick
Rich Callback System and Event Dispatching
Callbacks:
"this" refers to the Draggable instance itself, so you can easily access its "target" or bounds.
If you prefer event listeners, Draggable dispatches events:
yourDraggable.addEventListener("dragend", yourFunc);
This pen.
Responsive
Percentage-Based Transforms on SVG!
get excited.
This pen courtesy of GreenSock.
Cycle Stagger
This pen.
.container
-(1..3).each do |i|
%div{:class => ['unit', "unit#{i}"]}
.shape
.face.bm
.face.tp
-(1..14).each do |i|
%div{:class => ['face', 'side', "s#{i}"]}
HAML
@mixin colors($max-count, $color-frequency){
$color: 360/$max-count;
@for $i from 1 through $max-count {
.s#{$i} {
background: hsl(90%, ($i - 1)*($color / $color-frequency), 40%);
}
}
}
SASS
var bP = $(".face"),
unit = $(".unit"),
tl = new TimelineLite();
tl.add("start");
tl.staggerFrom(bP, 3, {
cycle:{
backgroundColor:["#00a99d", "#0072bc", "#2e3192"],
y:[1000, -500],
x:[500, -500],
opacity:[0.9, 0.7, 0.5],
rotation: function(i) {
return i * 25
}
},
rotation: 360,
ease:Circ.easeInOut
}, 0.006, "start");
JS
We can do stuff like this, All fully responsive in every direction
Atmosphere
Elemental Motion
- Further away is less contrast, blurry
- Does the air or environment effect movement
- Reducing precision allows for understanding
Putting Techniques Together
MorphSVG
- Tween paths to paths
- Tween shapes to paths
- Make animation magic
Point from one id to another
TweenMax.to("#start", 1, {morphSVG:{shape:"#end"},
ease:Linear.easeNone});
Use shapeIndex
TweenMax.to("#start", 1, {morphSVG:{shape:"#end",
shapeIndex:"1"}});
- Default is shapeIndex: "auto"
- Load the extra plugin, and a GUI will come up
- Usually auto will be correct, but you can pick
- Use findShapeIndex(#start, #end)
This pen.
How was this done?
MorphSVGPlugin.convertToPath("ellipse");
function flame() {
var tl = new TimelineMax();
tl.add("begin");
tl.fromTo(blurNode, 2.5, {
attr: {
stdDeviation: 9
}
}, {
attr: {
stdDeviation: 3
}
}, "begin");
var num = 9;
for (var i = 1; i <= num; i++) {
tl.to(fStable, 1, {
morphSVG: {
shape: "#f" + i
},
opacity: ((Math.random() * 0.7) + 0.7),
ease: Linear.easeNone
}, "begin+=" + i);
}
More than one way of working
By Blake Bowen
function solve(data) {
var size = data.length;
var last = size - 4;
var path = "M" + [data[0], data[1]];
for (var i = 0; i < size - 2; i +=2) {
var x0 = i ? data[i - 2] : data[0];
var y0 = i ? data[i - 1] : data[1];
var x1 = data[i + 0];
var y1 = data[i + 1];
var x2 = data[i + 2];
var y2 = data[i + 3];
var x3 = i !== last ? data[i + 4] : x2;
var y3 = i !== last ? data[i + 5] : y2;
var cp1x = (-x0 + 6 * x1 + x2) / 6;
var cp1y = (-y0 + 6 * y1 + y2) / 6;
var cp2x = (x1 + 6 * x2 - x3) / 6;
var cp2y = (y1 + 6 * y2 - y3) / 6;
path += "C" + [cp1x, cp1y, cp2x, cp2y, x2, y2];
}
return path;
}
Catmull-Rom Spline
Article about history in computer science.
var poly = document.querySelector("polyline");
var path = document.querySelector("path");
var points = [
100,350,
200,100,
300,350,
400,150,
500,350,
600,200,
700,350
];
poly.setAttribute("points", points);
path.setAttribute("d", solve(points));
var points = [
100,350,
200,150,
300,350,
400,120,
500,350,
600,180,
700,350
];
var points = [
100,350,
200,100,
300,350,
400,150,
500,350,
600,200,
700,350
];
This pen.
Accessibility
Title and associative aria tags: (WIP)
<svg aria-labelledby="title" id="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 765 587">
<title id="title" lang="en">Circle of icons that illustrate Global Warming Solutions</title>
You can also add a title for elements in the SVG DOM
This resource, with support charts.
Also, this article by Dudley Storey.
Social Coding Sites Help You Learn
Fun. Remember fun?
(I don't work for them and they don't pay me)
- Codepen
- JS Fiddle
- Dabblet
People You Should Know About
- Val Head
- Sara Soueidan
- Rachel Nabors
- Tiffany Rayside
- Chris Gannon
- CJ Gammon
- LegoMushroom
- Ana Tudor
- David Walsh Blog
- Gregor Adams
- Diaco ML
- Amelia Bellamy-Royds
- Taylor Hunt
- Dudley Storey
- GreenSock
- Blake Bowen
- I Hate Tomatoes (Petr Tichy)
- Lucas Bebber
- Rachel Smith
- Joni Trythall
- Jake Albaugh
- Louis Hoegbregts
More!
SVG Immersion Podcast and Web Animation Weekly
More Technical Information:
Frontend Masters Course
Advanced SVG Animation
O'Reilly Book
SVG Animation
Thank You!
These Slides:
slides.com/sdrasner/fluent-session
Complex SVG Animations with GreenSock (GSAP)
By sdrasner
Complex SVG Animations with GreenSock (GSAP)
Different ways to approach design and development for SVG animation, as well as theoretical guides for working with animation in a corporate context.
- 9,498