Animating
Animating elements is very much the same as manipulating elements using the attr()
method. The only difference is you have to include the animate()
method.
animate()
returns
SVG.Runner
rect.animate().move(150, 150)
The animate()
method will take three arguments. The first is duration
, the second delay
and the third when
:
rect.animate(2000, 1000, 'now').attr({ fill: '#f03' })
Alternatively you can pass an object as the first argument which accepts even more parameters:
rect.animate({
duration: 2000,
delay: 1000,
when: 'now',
swing: true,
times: 5,
wait: 200
}).attr({ fill: '#f03' })
By default duration
will be set to 400
, delay
will be set to 0
and when
is set to after
.
The when
parameter specifies the startpoint of the animation. It can have the following values:
-now
: Play the animation right after this call executes
-absolute
or start
: Schedules the animation to run to an absolute time on your timeline
-relative
: Schedules the animation to play relative to its old start time (not useful for the animate()-call)
-last
or after
: Plays the animation after the animation which comes last on the timeline. If there is none, the animation is played right away (see now
)
You can chain multiple animations together by calling animate
again:
rect.animate().attr({ fill: '#f03' }).animate().dmove(50,50)
you can also add delays betwen the animations:
rect.animate().attr({ fill: '#f03' }).delay(200).animate().dmove(50,50)
of course this can also be done by just adding a delay to the second call:
rect.animate().attr({ fill: '#f03' }).animate({delay: 200}).dmove(50,50)
SVG.Runner
The animate()
method will not return the targeted element but an instance of SVG.Runner which has the same methods as any element and additional methods to control the runner:
let rect = draw.rect(100, 100)
let runner = rect.animate()
runner.element() // returns or sets the element the runner is bound to
runner.timeline() // returns or sets the timeline the runner will be / is scheduled on
runner.animate() // for animation chaining. See element.animate()
runner.schedule(timeline, delay, when) // schedules the runner on the timeline. Timeline can be skipped if already set
runner.unschedule() // removes the runner from the timeline
runner.loop(times, swing, wait) // loops the animation by `times` times with `wait` milliseconds time between each loop
runner.queue(runOnceFn, runOnEveryStepFn) // Lets you chain functions which are not neccecarily animations
runner.during(fn) // Lets you bind a function to every animation step
runner.after(fn) // Lets you bind a function which is executed after the animation is finished
runner.time() // returns or sets the runner time
runner.duration() // returns the duration the runner will run
runner.loops() // Lets you jump to a specific iteration of the runner e.g. 3.5 for 4th loop half way through
runner.persist() // Make this runner persist on the timeline forever (true) or for a specific time. Usually a runner is deleted after execution to clean up memory.
runner.position() // returns or sets the current position of the runner ignoring the wait times (between 0 and 1)
runner.progress() // returns or sets the current position of the runner including the wait times (between 0 and 1)
runner.step(dt) // step the runner by a certain time (for manually stepping trough animations)
runner.reset() // set the runner back to zero time and all animations with it
runner.finish() // steps the runner to its finished state
runner.reverse() // execute the runner backwards
runner.ease() // change the easing of the animation
runner.active() // returns or sets the active state of the runner. Inactive runners are not executed
Runners are usually created by calling animate. However, it is possible to create runners without an element and set the element later:
var runner = new SVG.Runner(1000)
runner.move(100, 100)
runner.element(someElement)
// Step animation by 20ms
runner.step(20)
// To animate, we need a timeline on which the runner is run
var timeline = new SVG.Timeline()
timeline.schedule(runner)
Easing
The easing of the animation can be changed with the ease()
method of the runner.
All available ease types are:
<>
: ease in and out>
: ease out<
: ease in-
: linear- a function
beziere(x1, y1, x2, y2)
step(steps, stepPosition)
The beziere()
and step()
methods creates an easing function for you, which then can be passed to ease()
var runner = new SVG.Runner({duration: 1000})
// use a string
runner.ease('<>')
// or pass a function
runner.ease(SVG.easing.beziere(x1, y1, x2, y2))
runner.ease(SVG.easing.step(5, 'jump-end'))
For more easing equations, have a look at the svg.easing.js plugin.
SVG.Timeline
The SVG.Timeline drives the runner to animate elements. Runner can be scheduled on the same timeline to orchestrate a bigger animation.
finish()
returns
itself
This method finishes the whole timeline. All values are set to their corresponding end values and every animation gets fullfilled
rect.animate().move(200, 200).animate().dmove(50,50).size(300,400)
rect.timeline().finish() // rect at 250,250 with size 300,400
pause()
returns
itself
Pauses the timeline:
rect.animate().move(200, 200)
rect.mouseover(function() { this.timeline().pause() })
play()
returns
itself
Unpauses the timeline:
rect.animate().move(200, 200)
rect.mouseover(function() { this.timeline().pause() })
rect.mouseout(function() { this.timeline().play() })
reverse()
returns
itself
Play the timeline in reverse basically going back in time:
// will run from 100,100 to rects initial position
rect.animate(3000).move(100, 100)
rect.timeline().reverse()
// sets direction to backwards
rect.timeline().reverse(true)
// sets direction to forwards
rect.timeline().reverse(false)
stop()
returns
itself
Stops the timeline and sets the time back to zero
rect.animate().move(200, 200)
rect.timeline().stop()
speed()
returns
itself
Changes the speed of the timeline. Negative speeds will reverse the timeline.
rect.animate().move(200, 200)
rect.timeline().speed(2)
time()
returns
itself
Set the current time of the timeline
rect.animate().move(200, 200)
rect.timeline().time(100)
seek()
returns
itself
Seek the time by a delta
rect.animate().move(200, 200)
rect.timeline().seek(100)
persist()
returns
itself
Sets how runners are handled by default after they executed. Usually runners are deleted to clear up memory
rect.animate().move(200, 200)
rect.timeline().persist(100) // persist runner for 100ms more than their end time
rect.timeline().persist(true) // never delete runners
source()
returns
itself
Change the timesource for the timeline
rect.animate().move(200, 200)
rect.timeline().source(fn)
schedule()
returns
itself
Schedules a runner on the timeline
var timeline = new SVG.Timeline()
var runner = new SVG.Runner()
runner.move(100, 100)
timeline.schedule(runner, 100, 'now') // runner, delay, when - see animate()
unschedule()
returns
itself
Unschedule/removes a runner from the timeline
var timeline = new SVG.Timeline()
var runner = new SVG.Runner()
runner.move(100, 100)
timeline.schedule(runner, 100, 'now')
timeline.unschedule(runner) // same as runner.unschedule()
Controllers
Instead of using an easing function, it is possible to control animations using a controller. SVG.js comes with two buildin controllers. SVG.Spring
and SVG.PID
.
element.animate(new SVG.Spring(settleTime)).move(200, 200)
element.animate(new SVG.PID(p, i, d)).move(200, 200)
As you might notice, the controller is specified instead of the duration because only the controller itself knows when the animation is finished.
Thats why it is not possible to orchestrate or reverse animations with controllers.
Orchestrate Animations
To create a bigger animation with many elements which are all bound to the same timeline, you can use SVG.Timeline
and SVG.Runner
together:
var timeline = new SVG.Timeline()
var rect1 = draw.rect(100, 200)
var rect2 = draw.rect(200, 100)
rect1.timeline(timeline)
rect2.timeline(timeline)
rect1.animate(300, 0, 'absolute').move(300, 300) // start at time 0 of timeline
rect2.animate(400, 200, 'absolute').move(500, 500) // start at time 200 of timeline