/
Animation.re
106 lines (85 loc) · 2.83 KB
/
Animation.re
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
module Event = Reactify.Event;
open Revery_Core;
open Revery_Math;
module type AnimationTicker = {
let time: unit => Time.t;
let onTick: Event.t(Time.t);
};
module Make = (AnimationTickerImpl: AnimationTicker) => {
type animationValue = {mutable current: float};
type animation = {
delay: float,
mutable startTime: float,
duration: float,
startValue: float,
toValue: float,
value: animationValue,
repeat: bool,
};
let activeAnimations: ref(list(animation)) = ref([]);
type animationOptions = {
duration: Time.t,
delay: Time.t,
toValue: float,
repeat: bool,
};
let floatValue = (v: float) => {
let ret = {current: v};
ret;
};
let getLocalTime = (clock: float, anim: animation) => {
let adjustedStart = anim.startTime +. anim.delay;
let endTime = adjustedStart +. anim.duration;
(clock -. adjustedStart) /. (endTime -. adjustedStart);
};
let hasStarted = (clock: float, anim: animation) => {
let t = getLocalTime(clock, anim);
t > 0.;
};
let isComplete = (clock: float, anim: animation) => {
let t = getLocalTime(clock, anim);
t > 1. && !anim.repeat;
};
let tickAnimation = (clock: float, anim: animation) => {
let t = getLocalTime(clock, anim);
/* If the anim is set to repeat and the time has expired, restart */
if (anim.repeat && t > 1.) {
/* reset */
anim.startTime = anim.startTime +. anim.delay +. anim.duration;
let newT = getLocalTime(clock, anim);
anim.value.current = interpolate(newT, anim.startValue, anim.toValue);
} else {
anim.value.current = interpolate(t, anim.startValue, anim.toValue);
};
};
let getAnimationCount = () => List.length(activeAnimations^);
let anyActiveAnimations = () => {
let t = Time.to_float_seconds(AnimationTickerImpl.time());
let anims = List.filter(hasStarted(t), activeAnimations^);
List.length(anims) > 0;
};
let start =
(animationValue: animationValue, animationOptions: animationOptions) => {
let animation: animation = {
delay: Time.to_float_seconds(animationOptions.delay),
duration: Time.to_float_seconds(animationOptions.duration),
toValue: animationOptions.toValue,
repeat: animationOptions.repeat,
value: animationValue,
startTime: Time.to_float_seconds(AnimationTickerImpl.time()),
startValue: animationValue.current,
};
activeAnimations := List.append(activeAnimations^, [animation]);
animation;
};
let cancel = (anim: animation) =>
activeAnimations := List.filter(a => a == anim, activeAnimations^);
let tick = (t: float) => {
List.iter(tickAnimation(t), activeAnimations^);
activeAnimations :=
List.filter(a => !isComplete(t, a), activeAnimations^);
};
Event.subscribe(AnimationTickerImpl.onTick, t =>
tick(Time.to_float_seconds(t))
);
};