use dioxus::prelude::*;
use crate::runtime::{SplineApplication, SplineEvent, SplineEventName};
use wasm_bindgen::{JsCast, JsValue};
#[derive(Props, PartialEq, Clone)]
pub struct SplineProps {
#[props(into)]
pub scene: String,
pub on_load: Option<EventHandler<SplineApplication>>,
pub on_mouse_down: Option<EventHandler<SplineEvent>>,
pub on_mouse_up: Option<EventHandler<SplineEvent>>,
pub on_mouse_hover: Option<EventHandler<SplineEvent>>,
pub on_key_down: Option<EventHandler<SplineEvent>>,
pub on_key_up: Option<EventHandler<SplineEvent>>,
pub on_start: Option<EventHandler<SplineEvent>>,
pub on_look_at: Option<EventHandler<SplineEvent>>,
pub on_follow: Option<EventHandler<SplineEvent>>,
pub on_wheel: Option<EventHandler<SplineEvent>>,
pub render_on_demand: Option<bool>,
}
fn get_raw_canvas_element(mounted: &MountedData) -> &web_sys::HtmlCanvasElement {
mounted
.downcast::<web_sys::Element>()
.unwrap()
.dyn_ref::<web_sys::HtmlCanvasElement>()
.unwrap()
}
fn _event_factory(
props: &SplineProps,
) -> Vec<(SplineEventName, Option<EventHandler<SplineEvent>>)> {
vec![
(SplineEventName::mouseDown, props.on_mouse_down),
(SplineEventName::mouseUp, props.on_mouse_up),
(SplineEventName::mouseHover, props.on_mouse_hover),
(SplineEventName::keyDown, props.on_key_down),
(SplineEventName::keyUp, props.on_key_up),
(SplineEventName::start, props.on_start),
(SplineEventName::lookAt, props.on_look_at),
(SplineEventName::follow, props.on_follow),
(SplineEventName::scroll, props.on_wheel),
]
}
#[component]
pub fn Spline(props: SplineProps) -> Element {
let mut app = use_signal(|| None::<SplineApplication>);
let scene = use_signal(|| props.scene.clone());
let props_cloned = props.clone();
let mut is_loading = use_signal(|| true);
let _ = use_resource(move || {
let events = _event_factory(&props_cloned);
async move {
app.unwrap().load(scene()).await;
is_loading.set(false);
for (event_name, handler) in events {
if let Some(handler) = handler {
let cb = move |event: JsValue| {
let event: SplineEvent = event.into();
handler.call(event);
};
tracing::info!("Adding event listener for {:?}", event_name);
app.unwrap()
.add_event_listener(event_name.to_string().as_str(), cb);
}
}
if let Some(on_load) = props_cloned.on_load {
on_load.call(app.unwrap())
}
}
});
rsx! {
canvas {
onmounted: move |event: Event<MountedData>| {
let canvas_ref = get_raw_canvas_element(&event.data);
let render_on_demand = props.render_on_demand.unwrap_or(true);
app.set(Some(SplineApplication::new(canvas_ref, render_on_demand)));
},
style: match is_loading() {
true => "display: none;",
false => "display: block; width: 100%; height: 100%;",
}
}
}
}