Skip to content

Commit

Permalink
feat: allow pass custom state reducer to the animation process
Browse files Browse the repository at this point in the history
  • Loading branch information
bhovhannes committed Dec 20, 2016
1 parent d440265 commit ffac0b4
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 12 deletions.
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,51 @@ Name | Signature | Description
**onRender** | `function(state)` | (**required**) a callback for rendering current animation state.
**onFinish** | `function(finalState)` | Fires after the last animation is completed.
**onCancel** | `function()` | Fires if animation is canceled.
**stateReducer** | `IStateReducer` | An object, which provides `clone()` and `reduce()` methods thus implementing `IStateReducer` interface.

##### State reducers

State reducer is an object, which provides `clone()` and `reduce()` methods thus implementing `IStateReducer` interface.

```typescript
interface IStateReducer<T> {
clone: (state: T) => T,
reduce: (targetState: T, toState: T, fromState: T, pos: number) => T
}
```

`clone()` method is called once per each animation frame in order to get full clone of the target animation state.

`reduce()` method is called at least once per each animation frame in order to get animation state for the given tweening position `pos` - a number from [0,1] interval. `targetState` - is the current animation state.

If there are more than one tweening processes in progress, `reduce()` will be called once for each tweening process during single animation frame.

The default state reducer is called and exported as `PlainObjectReducer`. Its implementation is below:

```javascript
var PlainObjectReducer = {
clone: function (obj) {
var target = {},
key
for (key in obj) {
target[key] = obj[key]
}
return target
},

reduce: function (targetState, toState, fromState, pos) {
var key
for (key in targetState) {
targetState[key] -= (toState[key] - fromState[key]) * pos
}
return targetState
}
}
```

It can be used to animate states which are plain JavaScript objects with numeric values, such as `{ width: 10, height: 20 }`.



#### anim.tween(fromState, toState, duration, easing)

Expand Down
12 changes: 11 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,22 @@ declare namespace additween {

export type EasingFunction = (t: number) => number

export interface IStateReducer<T> {
clone: (state: T) => T,
reduce: (targetState: T, toState: T, fromState: T, pos: number) => T
}

export const ArrayReducer: IStateReducer<number[]>

export const PlainObjectReducer: IStateReducer<Object>

export class AdditiveTweening<T> {

constructor(options: {
onRender: (state: T) => void,
onFinish?: (finalState: T) => void,
onCancel?: () => void
onCancel?: () => void,
stateReducer?: IStateReducer<T>
})

tween(fromState: T, toState: T, duration?: number, easing?: EasingFunction): number
Expand Down
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict'

module.exports = {
AdditiveTweening: require('./src/additiveTweening')
AdditiveTweening: require('./src/AdditiveTweening'),
PlainObjectReducer: require('./src/PlainObjectReducer')
}
17 changes: 7 additions & 10 deletions src/additiveTweening.js → src/AdditiveTweening.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
'use strict'

var now = require('./now')
var PlainObjectReducer = require('./PlainObjectReducer')


function noop() {}

Expand All @@ -15,6 +17,7 @@ function AdditiveTweening(options) {
currentState = null,
animationStack = [],
onRender = options.onRender || noop,
stateReducer = options.stateReducer || PlainObjectReducer,
onFinish = options.onFinish || noop,
onCancel = options.onCancel || noop,
stepFunc
Expand All @@ -34,24 +37,18 @@ function AdditiveTweening(options) {
}

function getCurrentState(time) {
var target = {},
animation,
remain,
key
var animation,
remain

for (key in lastTargetState) {
target[key] = lastTargetState[key]
}
var target = stateReducer.clone(lastTargetState)

for (var i = animationStack.length - 1; i >= 0; i--) {
animation = animationStack[i]
if (animation.end < time) {
continue
}
remain = (animation.end - time) / animation.duration
for (key in target) {
target[key] -= (animation.toState[key] - animation.fromState[key]) * animation.easing(remain)
}
target = stateReducer.reduce(target, animation.toState, animation.fromState, animation.easing(remain))
}

return target
Expand Down
20 changes: 20 additions & 0 deletions src/PlainObjectReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict'

module.exports = {
clone: function (obj) {
var target = {},
key
for (key in obj) {
target[key] = obj[key]
}
return target
},

reduce: function (targetState, toState, fromState, pos) {
var key
for (key in targetState) {
targetState[key] -= (toState[key] - fromState[key]) * pos
}
return targetState
}
}

0 comments on commit ffac0b4

Please sign in to comment.