Skip to content

Commit

Permalink
Use procs in derived nodes and animations (#468)
Browse files Browse the repository at this point in the history
In order to optimize the number of nodes attached I decided to use proc node in many possible places
  • Loading branch information
osdnk committed Nov 18, 2019
1 parent 0db1406 commit 2dc3df7
Show file tree
Hide file tree
Showing 12 changed files with 200 additions and 44 deletions.
2 changes: 1 addition & 1 deletion src/animations/backwardCompatibleAnimWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
startClock,
stopClock,
} from '../base';
import { default as Clock } from '../core/AnimatedClock';
import Clock from '../core/AnimatedClock';
import { evaluateOnce } from '../derived/evaluateOnce';

function createOldAnimationObject(node, AnimationClass, value, config) {
Expand Down
14 changes: 13 additions & 1 deletion src/animations/decay.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import {
block,
set,
lessThan,
proc,
} from '../base';
import { abs } from '../derived';

const VELOCITY_EPS = 5;

export default function decay(clock, state, config) {
function decay(clock, state, config) {
const lastTime = cond(state.time, state.time, clock);
const deltaTime = sub(clock, lastTime);

Expand All @@ -38,3 +39,14 @@ export default function decay(clock, state, config) {
cond(lessThan(abs(v), VELOCITY_EPS), set(state.finished, 1)),
]);
}

const procDecay = proc(
(clock, time, velocity, position, finished, deceleration) =>
decay(clock, { time, velocity, position, finished }, { deceleration })
);

export default (
clock,
{ time, velocity, position, finished },
{ deceleration }
) => procDecay(clock, time, velocity, position, finished, deceleration);
77 changes: 76 additions & 1 deletion src/animations/spring.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ import {
and,
lessThan,
greaterThan,
proc,
} from '../base';
import { min, abs } from '../derived';
import AnimatedValue from '../core/InternalAnimatedValue';

const MAX_STEPS_MS = 64;

export default function spring(clock, state, config) {
function spring(clock, state, config) {
const lastTime = cond(state.time, state.time, clock);

const deltaTime = min(sub(clock, lastTime), MAX_STEPS_MS);
Expand Down Expand Up @@ -127,3 +128,77 @@ export default function spring(clock, state, config) {
]),
]);
}

const procSpring = proc(
(
finished,
velocity,
position,
time,
prevPosition,
toValue,
damping,
mass,
stiffness,
overshootClamping,
restSpeedThreshold,
restDisplacementThreshold,
clock
) =>
spring(
clock,
{
finished,
velocity,
position,
time,
// @ts-ignore
prevPosition,
},
{
toValue,
damping,
mass,
stiffness,
overshootClamping,
restDisplacementThreshold,
restSpeedThreshold,
}
)
);

export default (
clock,
{
finished,
velocity,
position,
time,
// @ts-ignore
prevPosition,
},
{
toValue,
damping,
mass,
stiffness,
overshootClamping,
restDisplacementThreshold,
restSpeedThreshold,
}
) =>
procSpring(
finished,
velocity,
position,
time,
prevPosition,
toValue,
damping,
mass,
stiffness,
overshootClamping,
restSpeedThreshold,
restDisplacementThreshold,
clock
);
52 changes: 45 additions & 7 deletions src/animations/timing.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,64 @@ import {
block,
set,
greaterOrEq,
proc,
} from '../base';

export default function timing(clock, state, config) {
const lastTime = cond(state.time, state.time, clock);
const frameTime = add(state.frameTime, sub(clock, lastTime));
const internalTiming = proc(function(
clock,
time,
frameTime,
position,
finished,
toValue,
duration,
nextProgress,
progress,
newFrameTime
) {
const state = {
time,
finished,
frameTime,
position,
};

const config = {
duration,
toValue,
};

const progress = config.easing(divide(state.frameTime, config.duration));
const distanceLeft = sub(config.toValue, state.position);
const fullDistance = divide(distanceLeft, sub(1, progress));
const startPosition = sub(config.toValue, fullDistance);
const nextProgress = config.easing(divide(frameTime, config.duration));
const nextPosition = add(startPosition, multiply(fullDistance, nextProgress));

return block([
cond(
greaterOrEq(frameTime, config.duration),
greaterOrEq(newFrameTime, config.duration),
[set(state.position, config.toValue), set(state.finished, 1)],
set(state.position, nextPosition)
),
set(state.frameTime, frameTime),
set(state.frameTime, newFrameTime),
set(state.time, clock),
]);
});

export default function(clock, state, config) {
const lastTime = cond(state.time, state.time, clock);
const newFrameTime = add(state.frameTime, sub(clock, lastTime));
const nextProgress = config.easing(divide(newFrameTime, config.duration));
const progress = config.easing(divide(state.frameTime, config.duration));
return internalTiming(
clock,
state.time,
state.frameTime,
state.position,
state.finished,
config.toValue,
config.duration,
nextProgress,
progress,
newFrameTime
);
}
6 changes: 3 additions & 3 deletions src/derived/abs.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { cond, lessThan, multiply } from '../base';
import { cond, lessThan, multiply, proc } from '../base';

export default function abs(a) {
export default proc(function abs(a) {
return cond(lessThan(a, 0), multiply(-1, a), a);
}
});
8 changes: 6 additions & 2 deletions src/derived/acc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { set, add } from '../base';
import { set, add, proc } from '../base';
import AnimatedValue from '../core/InternalAnimatedValue';

const procAcc = proc(function(v, acc) {
return set(acc, add(acc, v));
});

export default function acc(v) {
const acc = new AnimatedValue(0);
return set(acc, add(acc, v));
return procAcc(v, acc);
}
6 changes: 3 additions & 3 deletions src/derived/ceil.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { sub, round } from '../base';
import { sub, round, proc } from '../base';

export default function ceil(a) {
export default proc(function ceil(a) {
return sub(1, round(sub(0.5, a)));
}
});
28 changes: 16 additions & 12 deletions src/derived/color.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import { Platform } from 'react-native';

import { add, cond, lessThan, multiply, round, sub } from '../base';
import { add, cond, lessThan, multiply, round, sub, proc } from '../base';
import AnimatedNode from '../core/AnimatedNode';

export default function color(r, g, b, a = 1) {
if (a instanceof AnimatedNode) {
a = round(multiply(a, 255));
} else {
a = Math.round(a * 255);
}

if (Platform.OS === 'web') {
throw new Error('color is not implemented on web yet');
}

const procColor = proc(function(r, g, b, a) {
const color = add(
multiply(a, 1 << 24),
multiply(r, 1 << 16),
Expand All @@ -29,4 +19,18 @@ export default function color(r, g, b, a = 1) {
);
}
return color;
});

export default function color(r, g, b, a = 1) {
if (a instanceof AnimatedNode) {
a = round(multiply(a, 255));
} else {
a = Math.round(a * 255);
}

if (Platform.OS === 'web') {
throw new Error('color is not implemented on web yet');
}

return procColor(r, g, b, a);
}
12 changes: 8 additions & 4 deletions src/derived/diff.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { cond, block, defined, sub, set } from '../base';
import { cond, block, defined, sub, set, proc } from '../base';
import AnimatedValue from '../core/InternalAnimatedValue';

export default function diff(v) {
const stash = new AnimatedValue(0);
const prev = new AnimatedValue();
const procDiff = proc(function(v, stash, prev) {
return block([
set(stash, cond(defined(prev), sub(v, prev), 0)),
set(prev, v),
stash,
]);
});

export default function diff(v) {
const stash = new AnimatedValue(0);
const prev = new AnimatedValue();
return procDiff(v, stash, prev);
}
10 changes: 7 additions & 3 deletions src/derived/diffClamp.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { cond, defined, set, add } from '../base';
import { cond, defined, set, add, proc } from '../base';
import AnimatedValue from '../core/InternalAnimatedValue';
import min from './min';
import max from './max';
import diff from './diff';

export default function diffClamp(a, minVal, maxVal) {
const value = new AnimatedValue();
const procAcc = proc(function(a, minVal, maxVal, value) {
return set(
value,
min(max(add(cond(defined(value), value, a), diff(a)), minVal), maxVal)
);
});

export default function diffClamp(a, minVal, maxVal) {
const value = new AnimatedValue();
return procAcc(a, minVal, maxVal, value);
}
19 changes: 15 additions & 4 deletions src/derived/interpolate.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,29 @@ import {
divide,
greaterThan,
} from '../operators';

import { createAnimatedCond as cond } from '../core/AnimatedCond';
import invariant from 'fbjs/lib/invariant';

import AnimatedNode from '../core/AnimatedNode';
import { createAnimatedCond as cond } from '../core/AnimatedCond';
import { createAnimatedFunction as proc } from '../core/AnimatedFunction';

const interpolateInternalSingleProc = proc(function(
value,
inS,
inE,
outS,
outE
) {
const progress = divide(sub(value, inS), sub(inE, inS));
return add(outS, multiply(progress, sub(outE, outS)));
});

function interpolateInternalSingle(value, inputRange, outputRange, offset) {
const inS = inputRange[offset];
const inE = inputRange[offset + 1];
const outS = outputRange[offset];
const outE = outputRange[offset + 1];
const progress = divide(sub(value, inS), sub(inE, inS));
return add(outS, multiply(progress, sub(outE, outS)));
return interpolateInternalSingleProc(value, inS, inE, outS, outE);
}

function interpolateInternal(value, inputRange, outputRange, offset = 0) {
Expand Down
10 changes: 7 additions & 3 deletions src/derived/onChange.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { block, cond, defined, neq, not, set } from '../base';
import { block, cond, defined, neq, not, set, proc } from '../base';
import AnimatedValue from '../core/InternalAnimatedValue';

export default function onChange(value, action) {
const prevValue = new AnimatedValue();
const procOnChange = proc(function(value, action, prevValue) {
return block([
cond(not(defined(prevValue)), set(prevValue, value)),
cond(neq(value, prevValue), [set(prevValue, value), action]),
]);
});

export default function onChange(value, action) {
const prevValue = new AnimatedValue();
return procOnChange(value, action, prevValue);
}

0 comments on commit 2dc3df7

Please sign in to comment.