use std::collections::HashMap;
use leptos::callback::Callback;
use leptos::prelude::*;
use crate::engine::{clamp_zoom_window, default_zoom_window, enabled_zoom_axes};
use crate::{AxisDef, ChartFeatures, ZoomConfig, ZoomWindow};
#[derive(Clone, Debug, PartialEq)]
pub struct ZoomDragState {
pub axis_id: String,
pub start_x: f64,
pub start_window: ZoomWindow,
}
#[derive(Clone)]
pub struct ChartZoomContext {
pub windows: RwSignal<Vec<ZoomWindow>>,
pub dragging: RwSignal<Option<ZoomDragState>>,
pub enabled_axes: HashMap<String, ZoomConfig>,
pub features: ChartFeatures,
pub plot_width: f64,
pub on_zoom_change: Option<Callback<(Vec<ZoomWindow>,), ()>>,
}
impl ChartZoomContext {
pub fn is_active(&self) -> bool {
!self.enabled_axes.is_empty()
}
pub fn config_for(&self, axis_id: &str) -> Option<&ZoomConfig> {
self.enabled_axes.get(axis_id)
}
pub fn set_windows(&self, mut windows: Vec<ZoomWindow>) {
for window in &mut windows {
if let Some(config) = self.enabled_axes.get(&window.axis_id) {
*window = clamp_zoom_window(window.clone(), config);
}
}
self.windows.set(windows.clone());
if let Some(cb) = self.on_zoom_change.as_ref() {
cb.run((windows,));
}
}
pub fn update_axis_window(&self, axis_id: &str, window: ZoomWindow) {
let mut windows = self.windows.get_untracked();
if let Some(existing) = windows.iter_mut().find(|w| w.axis_id == axis_id) {
*existing = window;
} else {
windows.push(window);
}
self.set_windows(windows);
}
}
pub fn initial_zoom_windows(
controlled: Option<&[ZoomWindow]>,
features: ChartFeatures,
x_axes: &[AxisDef],
y_axes: &[AxisDef],
) -> Vec<ZoomWindow> {
let enabled = enabled_zoom_axes(features, x_axes, y_axes);
if enabled.is_empty() {
return Vec::new();
}
if let Some(controlled) = controlled {
return controlled.to_vec();
}
enabled
.into_iter()
.map(|(axis, _)| default_zoom_window(axis.id.clone()))
.collect()
}
#[component]
pub fn ChartZoomProvider(
windows: RwSignal<Vec<ZoomWindow>>,
dragging: RwSignal<Option<ZoomDragState>>,
enabled_axes: HashMap<String, ZoomConfig>,
features: ChartFeatures,
plot_width: f64,
on_zoom_change: Option<Callback<(Vec<ZoomWindow>,), ()>>,
children: Children,
) -> impl IntoView {
provide_context(ChartZoomContext {
windows,
dragging,
enabled_axes,
features,
plot_width,
on_zoom_change,
});
children()
}
pub fn use_chart_zoom() -> Option<ChartZoomContext> {
use_context::<ChartZoomContext>()
}