use leptos::prelude::*;
use orbital_motion::{MotionCurve, MotionDuration};
use crate::engine::arc_path_d_sweep;
use crate::ChartMotion;
pub fn arc_sweep_motion(motion: &ChartMotion) -> (MotionDuration, MotionCurve) {
(motion.stagger, MotionCurve::DecelerateMax)
}
#[component]
pub fn ArcSweepSlice(
cx: f64,
cy: f64,
inner_r: f64,
outer_r: f64,
start_rad: f64,
end_rad: f64,
#[prop(into)]
full_path: String,
#[prop(into)]
fill: Signal<String>,
#[prop(into, default = "orb-pie-slice".into())]
class: String,
#[prop(default = false)]
skip_animation: bool,
#[prop(default = MotionDuration::Normal)]
duration: MotionDuration,
#[prop(default = MotionCurve::DecelerateMax)]
curve: MotionCurve,
#[prop(into)]
draw_key: Signal<String>,
) -> impl IntoView {
let full_path_stored = StoredValue::new(full_path);
let sweep_fraction = RwSignal::new(if skip_animation { 1.0 } else { 0.0 });
Effect::new(move |_| {
let _ = draw_key.get();
if skip_animation {
sweep_fraction.set(1.0);
return;
}
sweep_fraction.set(0.0);
animate_sweep(sweep_fraction, duration);
});
let animated_path = move || {
let frac = sweep_fraction.get();
let path = full_path_stored.get_value();
if frac >= 1.0 {
path
} else {
arc_path_d_sweep(cx, cy, inner_r, outer_r, start_rad, end_rad, frac)
}
};
let style = move || {
format!(
"fill: {}; transition: opacity {} {};",
fill.get(),
duration.ms(),
curve.css_var(),
)
};
view! {
<path
class=class
d=animated_path
style=style
/>
}
}
fn animate_sweep(signal: RwSignal<f64>, duration: MotionDuration) {
#[cfg(feature = "hydrate")]
{
let ms = duration
.ms()
.trim_end_matches("ms")
.parse::<u32>()
.unwrap_or(300);
let steps = 20u32;
let step_ms = (ms / steps).max(16);
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;
let mut step = 0u32;
fn tick(signal: RwSignal<f64>, step: &mut u32, steps: u32, step_ms: u32) {
*step += 1;
let frac = (*step as f64 / steps as f64).min(1.0);
signal.set(frac);
if *step < steps {
if let Some(win) = web_sys::window() {
let s = signal;
let mut st = *step;
let cb = Closure::once(move || {
tick(s, &mut st, steps, step_ms);
});
let _ = win.set_timeout_with_callback_and_timeout_and_arguments_0(
cb.as_ref().unchecked_ref(),
step_ms as i32,
);
cb.forget();
}
}
}
tick(signal, &mut step, steps, step_ms);
}
#[cfg(not(feature = "hydrate"))]
{
let _ = duration;
signal.set(1.0);
}
}