use leptos::prelude::*;
use crate::context::{
keyboard_nav_enabled, set_hovered_item, use_chart_context, use_highlighted_item,
};
use crate::shared::motion::PathDrawMotion;
use crate::{ChartItemId, FadeMode, HighlightMode, HighlightScope};
use orbital_motion::{MotionCurve, MotionDuration};
#[component]
pub fn LineStroke(
#[prop(into)]
d: Signal<String>,
#[prop(into)]
stroke: Signal<String>,
markers: Vec<(f64, f64, usize)>,
#[prop(into)]
series_id: String,
#[prop(default = false)]
show_markers: bool,
#[prop(default = false)]
skip_animation: bool,
#[prop(into)]
draw_key: Signal<String>,
#[prop(default = None)]
highlight_scope: Option<HighlightScope>,
) -> impl IntoView {
let highlighted = use_highlighted_item();
let chart_ctx = use_chart_context();
let keyboard_nav = keyboard_nav_enabled(chart_ctx.keyboard_navigation, chart_ctx.features);
let scope = highlight_scope.unwrap_or(HighlightScope {
highlight: HighlightMode::Item,
fade: FadeMode::Global,
});
let series = series_id.clone();
let stroke_class = move || {
let mut classes = vec!["orb-line-stroke".to_string()];
let active = highlighted.get();
if scope.highlight != HighlightMode::None && active.is_some() {
let is_series = active.as_ref().is_some_and(|item| item.series_id == series);
if !is_series && scope.fade == FadeMode::Global {
classes.push("orb-line-stroke-faded".into());
}
}
classes.join(" ")
};
view! {
<g class=stroke_class>
<PathDrawMotion
d=d
stroke=stroke
class="orb-line-stroke".to_string()
skip_animation=skip_animation
duration=MotionDuration::Normal
curve=MotionCurve::DecelerateMax
draw_key=draw_key
/>
</g>
{show_markers.then(|| {
let series_id = series_id.clone();
view! {
<For
each=move || markers.clone()
key=|(x, y, idx)| format!("{x}-{y}-{idx}")
let((x, y, data_index))
>
{
let series_id = series_id.clone();
let item_id = ChartItemId {
series_id: series_id.clone(),
data_index,
};
let item_for_hover = item_id.clone();
let item_for_class = item_id;
let item_for_tab = item_for_hover.clone();
let item_for_focus = item_for_hover.clone();
let point_class = move || {
let mut classes = vec!["orb-line-point".to_string()];
let active = highlighted.get();
let is_active = active.as_ref() == Some(&item_for_class);
if scope.highlight != HighlightMode::None && active.is_some() {
if is_active {
classes.push("orb-line-point-highlighted".into());
} else if scope.fade == FadeMode::Global {
classes.push("orb-line-point-faded".into());
}
}
classes.join(" ")
};
let tab_index = move || {
if !keyboard_nav {
return -1;
}
let active = highlighted.get();
if active.as_ref() == Some(&item_for_tab) {
0
} else if active.is_none() && data_index == 0 {
0
} else {
-1
}
};
view! {
<circle
class=point_class
cx=x
cy=y
r=4.0
fill=move || stroke.get()
tabindex=tab_index
style="pointer-events: all; cursor: pointer;"
on:focus=move |_| set_hovered_item(Some(item_for_focus.clone()))
on:mouseenter=move |_| set_hovered_item(Some(item_for_hover.clone()))
on:mouseleave=move |_| set_hovered_item(None)
/>
}
}
</For>
}
})}
}
}