Timeline queuing

Often, we need to animate more that one Shape at a time.

Timeline queuing to the rescue.

A Timeline allows for complex queuing of Shapes in sequence (one after the other) or in parallel (alongside each other).

By default, when we pass more than one Shape to a Timeline, they will queue in sequence.


import { shape, timeline, render, play } from 'wilderness'

const shape1Keyframe1 = {
  type: 'circle',
  cx: 5,
  cy: 10,
  r: 5,
  fill: '#DBF8A1'
}

const shape1Keyframe2 = {
  type: 'rect',
  x: 40,
  y: 5,
  width: 10,
  height: 10,
  fill: '#1F9FFD'
}

const shape2Keyframe1 = {
  type: 'rect',
  x: 50,
  y: 5,
  width: 10,
  height: 10,
  fill: '#1F9FFD'
}

const shape2Keyframe2 = {
  type: 'circle',
  cx: 95,
  cy: 10,
  r: 5,
  fill: '#DBF8A1'
}

const shape1 = shape(shape1Keyframe1, shape1Keyframe2)
const shape2 = shape(shape2Keyframe1, shape2Keyframe2)

const animation = timeline(shape1, shape2, {
  duration: 2000,
  iterations: Infinity,
  alternate: true
})

render(document.querySelector('svg'), animation)

play(animation)
    

Fine grain queue control

As well as Shapes, the timeline function can also accept arrays as arguments.


timeline(
  [ shape1, { name: 'SHAPE_1' } ],
  [ shape2, { name: 'SHAPE_2', queue: { after: 'SHAPE_1', offset: -200 } } ]
)
    

When passing an array argument to the timeline function, the first array item should be a Shape, and the second an options object.

This options object has two properties that can help with fine grain queue control – name (a string or a number) and queue (an object).

The name property is a value we can use to reference a Shape from another Shape. In the case of Timeline queuing, we can reference the name value from another Shape's queue.at or queue.after properties.

The mutually exclusive at and after properties queue a Shape in parallel or sequence respectively.

If neither the at nor after property is defined, the after property will be set to reference the previous Shape in the Timeline. This is the reason why, by default, Wilderness queues a Timeline in sequence.

The final queue property to understand is offset. This is a number that defines the milliseconds to offset the Shape from its position on the Timeline. For example, a queue object of { at: 'SHAPE_X', offset: 200 } means start playback 200 milliseconds after SHAPE_X has started.


import { shape, timeline, render, play } from 'wilderness'

const shape1Keyframe1 = {
  type: 'circle',
  cx: 5,
  cy: 5,
  r: 5,
  fill: '#DBF8A1'
}

const shape1Keyframe2 = {
  type: 'rect',
  x: 90,
  y: 0,
  width: 10,
  height: 10,
  fill: '#1F9FFD',
  duration: 1000
}

const shape2Keyframe1 = {
  type: 'circle',
  cx: 5,
  cy: 15,
  r: 5,
  fill: '#1F9FFD'
}

const shape2Keyframe2 = {
  type: 'rect',
  x: 90,
  y: 10,
  width: 10,
  height: 10,
  fill: '#DBF8A1',
  duration: 1000
}

const shape1 = shape(shape1Keyframe1, shape1Keyframe2)
const shape2 = shape(shape2Keyframe1, shape2Keyframe2)

const shape1WithOpts = [ shape1, {
  name: 'SHAPE_1'
} ]

const shape2WithOpts = [ shape2, {
  queue: { at: 'SHAPE_1', offset: 250 }
} ]

const animation = timeline(shape1WithOpts, shape2WithOpts, {
  iterations: Infinity,
  alternate: true
})

render(document.querySelector('svg'), animation)

play(animation)
    

Something to note is that when we are working with fine grain queue control we should be setting our duration properties at the Keyframe level (on our Plain Shape Objects). The reason for this is that all queue calculations are made before playback options are applied to the timeline.

Take a look at the Timeline API reference for further detail.