use leptos::prelude::*;
use lodviz_core::algorithms::statistics::{linear_regression, sma};
use lodviz_core::core::scale::{LinearScale, Scale};
#[component]
pub fn TrendLine(
points: Signal<Vec<(f64, f64)>>,
x_scale: Memo<LinearScale>,
y_scale: Memo<LinearScale>,
#[prop(default = "#D55E00")]
color: &'static str,
#[prop(default = 2.0)]
stroke_width: f64,
#[prop(default = "6,4")]
dash: &'static str,
) -> impl IntoView {
let line_coords = Memo::new(move |_| {
let pts = points.get();
let (b0, b1) = linear_regression(&pts)?;
let xs = x_scale.get();
let ys = y_scale.get();
let (x_domain_min, x_domain_max) = xs.domain();
let y0 = b0 + b1 * x_domain_min;
let y1 = b0 + b1 * x_domain_max;
Some((
xs.map(x_domain_min),
ys.map(y0),
xs.map(x_domain_max),
ys.map(y1),
))
});
view! {
{move || {
line_coords
.get()
.map(|(x1, y1, x2, y2)| {
view! {
<line
x1=format!("{x1:.2}")
y1=format!("{y1:.2}")
x2=format!("{x2:.2}")
y2=format!("{y2:.2}")
stroke=color
stroke-width=stroke_width
stroke-dasharray=dash
stroke-linecap="round"
/>
}
})
}}
}
}
#[component]
pub fn SmaOverlay(
data: Signal<Vec<f64>>,
xs: Signal<Vec<f64>>,
#[prop(default = 7)]
window: usize,
x_scale: Memo<LinearScale>,
y_scale: Memo<LinearScale>,
#[prop(default = "#009E73")]
color: &'static str,
#[prop(default = 2.0)]
stroke_width: f64,
) -> impl IntoView {
let path_d = Memo::new(move |_| {
let y_vals = data.get();
let x_vals = xs.get();
let smoothed = sma(&y_vals, window);
if smoothed.is_empty() {
return String::new();
}
let offset = window.saturating_sub(1);
let x_scale_val = x_scale.get();
let y_scale_val = y_scale.get();
smoothed
.iter()
.enumerate()
.filter_map(|(i, &y)| {
let xi = x_vals.get(i + offset).copied()?;
Some((x_scale_val.map(xi), y_scale_val.map(y)))
})
.enumerate()
.map(|(k, (px, py))| {
if k == 0 {
format!("M {px:.2} {py:.2}")
} else {
format!(" L {px:.2} {py:.2}")
}
})
.collect::<String>()
});
view! {
{move || {
let d = path_d.get();
if d.is_empty() {
().into_any()
} else {
view! {
<path
d=d
fill="none"
stroke=color
stroke-width=stroke_width
stroke-linejoin="round"
stroke-linecap="round"
/>
}
.into_any()
}
}}
}
}