SVG.js

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
Fork me on GitHub