Forces
Like Middleware, Forces allow us to define custom functions that apply to a tween.
The previous lesson stated that Middleware is applied at the Timeline level, and converts non-tweenable values (stings etc.) to tweenable values (numbers).
Forces differ in that they are applied at the Shape level. Their role is to adjust the value of a Shape's points and/or attributes post-tween.
Why might we want to adjust a Shape's values?
The main use case for a Force is to apply an "external force" to a Shape. An external force could be a motion path, rotation or physics.
Let's take the case of a motion path. Normally, when we animate a Shape from position A to position B, the movement between the two positions will occur in a straight line. To move the Shape along a motion path instead, we can use a Force. This Force would offset the Shape depending on its position in the tween.
Create a force
A Force is just a function that is called on each tick of a tween. The function receives two arguments.
- A Frame Shape – the data required to render a Shape. A Frame Shape is calculated by tweening between two Keyframes. It takes the form of an object that can contain three properties.
points
– shape data as defined by Points.attributes
– an object of additional Shape attributes (eg.fill
).childFrameShape
– an array of child Frame Shapes.
- A Frame Position – a number (between 0 and 1 inc.) representing the Shape's current progress between two Keyframes.
A Force must return a Frame Shape.
As an example, let's create a Force called shakeForce
, that randomly adjusts the x
and y
value of each point in a Shape.
import { shape, timeline, render, play } from 'wilderness' const randomlyAdjustPoint = point => ({ ...point, x: point.x + Math.floor(Math.random() * 10) - 5, y: point.y + Math.floor(Math.random() * 10) - 5 }) const shakeForce = ({ points, attributes, childFrameShapes }, framePosition) => ({ points: points.map(randomlyAdjustPoint), attributes, childFrameShapes }) const plainShapeObject = { type: 'rect', x: 5, y: 5, width: 10, height: 10, fill: '#1F9FFD' } const keyframe1 = plainShapeObject const keyframe2 = { ...plainShapeObject, transforms: [[ 'offset', 80 ]], forces: [ shakeForce ] } const shakyRect = shape(keyframe1, keyframe2) const animation = timeline(shakyRect, { duration: 2000, iterations: Infinity, alternate: true }) render(document.querySelector('svg'), animation) play(animation)
Wowzers. What a shaky little guy.
Notice in the example above that we add Forces to a Shape by defining a forces
array on the Keyframe we are tweening to.
Force helpers
Wilderness has a couple of Force function helpers built in.
- ⚡️ Motion path.
- 🎡 Rotate (coming soon).