This repository has no description
1use crate::{Canvas, context::Context, video::hooks::InnerHook};
2use easing_function::Easing;
3pub use easing_function::{EasingFunction, easings};
4use nanoid::nanoid;
5use std::fmt::Display;
6
7/// Arguments: animation progress (from 0.0 to 1.0), canvas, current ms
8pub type AnimationUpdateFunction =
9 dyn Fn(f32, &mut Canvas, usize) -> anyhow::Result<()> + Send + Sync;
10
11pub struct Animation {
12 pub name: String,
13 // pub keyframes: Vec<Keyframe<C>>,
14 pub update: Box<AnimationUpdateFunction>,
15}
16
17// pub struct Keyframe<C: Default> {
18// pub at: f32, // from 0 to 1
19// pub action: Box<RenderFunction<C>>,
20// }
21
22impl Animation {
23 /// Example
24 /// ```
25 /// use shapemaker::*;
26 /// Animation::new("example", &|t, canvas, _| {
27 /// let mut dot = canvas.root().object("dot");
28 /// dot.refill(Fill::Translucent(Color::Red, t));
29 /// Ok(())
30 /// });
31 /// ```
32 pub fn new<N>(name: N, f: &'static AnimationUpdateFunction) -> Self
33 where
34 N: Display,
35 {
36 Self {
37 name: format!("{}", name),
38 update: Box::new(f),
39 }
40 }
41}
42
43impl From<(String, Box<AnimationUpdateFunction>)> for Animation {
44 fn from((name, f): (String, Box<AnimationUpdateFunction>)) -> Self {
45 Self { name, update: f }
46 }
47}
48
49impl<C: Default> Context<'_, C> {
50 /// duration is in milliseconds
51 pub fn start_animation(
52 &mut self,
53 duration: usize,
54 easing: impl Into<EasingFunction>,
55 animation: Animation,
56 ) {
57 let start_ms = self.ms;
58 let ms_range = start_ms..(start_ms + duration);
59 let easing = easing.into();
60
61 self.inner_hooks.push(InnerHook {
62 once: false,
63 when: Box::new(move |_, ctx, _| ms_range.contains(&ctx.ms)),
64 render_function: Box::new(move |canvas, ms| {
65 let t = (ms - start_ms) as f32 / duration as f32;
66 (animation.update)(easing.ease(t), canvas, ms)
67 }),
68 })
69 }
70
71 /// duration is in milliseconds
72 /// Animates with ease-in-out quadratic easing
73 /// See animat_linear or animate_eased for other options
74 pub fn animate(
75 &mut self,
76 duration: usize,
77 f: &'static AnimationUpdateFunction,
78 ) {
79 self.animate_eased(duration, easings::EaseInOutQuadradic, f);
80 }
81
82 pub fn animate_linear(
83 &mut self,
84 duration: usize,
85 f: &'static AnimationUpdateFunction,
86 ) {
87 self.animate_eased(duration, easings::Linear, f);
88 }
89
90 pub fn animate_eased(
91 &mut self,
92 duration: usize,
93 easing: impl Into<EasingFunction>,
94 f: &'static AnimationUpdateFunction,
95 ) {
96 self.start_animation(
97 duration,
98 easing.into(),
99 Animation::new(format!("unnamed animation {}", nanoid!()), f),
100 );
101 }
102}