use crate::animations::Easing;
use crate::utils::Scalable;
use crate::utils::State;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug)]
pub struct Keyframe {
target: State,
start: u64,
end: u64,
transition: Easing,
}
impl Keyframe {
pub fn new<S: Into<State>>(target: S, start: u64, end: u64) -> Keyframe {
assert!(
start <= end,
"Start time must be less than or equal to end time."
);
Keyframe {
target: target.into(),
start,
end,
transition: Easing::default(),
}
}
pub fn get_duration(&self) -> u64 {
self.end - self.start
}
pub(crate) fn compute_target_coefficient(&self, time: u64) -> f32 {
let clamped_time = time.clamp(self.start, self.end) as f32;
let progress = clamped_time.scale(self.start as f32, self.end as f32, 0.0, 1.0);
self.transition.call(progress)
}
pub fn get_target(&self) -> State {
self.target.clone()
}
pub fn get_start(&self) -> u64 {
self.start
}
pub fn get_end(&self) -> u64 {
self.end
}
pub fn get_transition(&self) -> Easing {
self.transition
}
pub fn set_transition(mut self, transition: Easing) -> Self {
self.transition = transition;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_keyframe_new() {
let keyframe = Keyframe::new(100, 0, 1000);
assert_eq!(keyframe.get_target().as_integer(), 100);
assert_eq!(keyframe.get_start(), 0);
assert_eq!(keyframe.get_end(), 1000);
assert_eq!(keyframe.get_duration(), 1000);
let keyframe = keyframe.set_transition(Easing::QuadOut);
assert_eq!(keyframe.get_transition(), Easing::QuadOut);
}
#[test]
#[should_panic(expected = "Start time must be less than or equal to end time.")]
fn test_new_panic_start_greater_than_end() {
let _ = Keyframe::new(100, 2000, 1000);
}
#[test]
fn test_keyframe_duration() {
let keyframe = Keyframe::new(100, 1000, 2000);
assert_eq!(keyframe.get_duration(), 1000);
}
#[test]
fn test_compute_target_coefficient() {
let keyframe = Keyframe::new(100, 0, 1000);
let progress = keyframe.compute_target_coefficient(500);
assert_eq!(progress, 0.5); let keyframe = keyframe.set_transition(Easing::QuadOut);
let progress = keyframe.compute_target_coefficient(500);
assert_eq!(progress, 0.75);
let keyframe = Keyframe::new(100, 1000, 2000);
assert_eq!(keyframe.compute_target_coefficient(500), 0.0); assert_eq!(keyframe.compute_target_coefficient(2500), 1.0); assert_eq!(keyframe.compute_target_coefficient(1300), 0.3); }
}