#![cfg(target_arch = "wasm32")]
use bevy_math::Vec2;
use parking_lot::Mutex;
use std::sync::Arc;
use wasm_bindgen::prelude::*;
use crate::core::{Dashboard, Plot};
use crate::runtime::run_dashboard;
#[wasm_bindgen]
pub struct JsDashboard {
dashboard: Arc<Mutex<Dashboard>>,
canvas_id: String,
started: bool,
}
#[wasm_bindgen]
impl JsDashboard {
#[wasm_bindgen(constructor)]
pub fn new(json: &str, canvas_id: &str) -> Result<JsDashboard, JsValue> {
let dashboard: Dashboard = serde_json::from_str(json)
.map_err(|e| JsValue::from_str(&format!("Failed to parse dashboard JSON: {}", e)))?;
Ok(JsDashboard {
dashboard: Arc::new(Mutex::new(dashboard)),
canvas_id: canvas_id.to_string(),
started: false,
})
}
#[wasm_bindgen]
pub fn start(&mut self) {
if self.started {
web_sys::console::warn_1(&"Dashboard already started".into());
return;
}
let dashboard = self.dashboard.lock().clone();
self.started = true;
run_dashboard(dashboard, &self.canvas_id);
}
#[wasm_bindgen]
pub fn set_dashboard(&mut self, json: &str) -> Result<(), JsValue> {
let dashboard: Dashboard = serde_json::from_str(json)
.map_err(|e| JsValue::from_str(&format!("Failed to parse dashboard JSON: {}", e)))?;
*self.dashboard.lock() = dashboard;
web_sys::console::log_1(&"Dashboard updated (requires restart to take effect)".into());
Ok(())
}
#[wasm_bindgen]
pub fn append_points(
&mut self,
plot_id: u64,
layer_idx: usize,
points: &[f32],
) -> Result<(), JsValue> {
if points.len() % 2 != 0 {
return Err(JsValue::from_str(
"Points array length must be even (x,y pairs)",
));
}
let mut dashboard = self.dashboard.lock();
for plot in dashboard.plots.iter_mut() {
if let Plot::Graph2D(graph) = plot {
if graph.id.0 == plot_id {
if let Some(layer) = graph.layers.get_mut(layer_idx) {
for chunk in points.chunks(2) {
layer.xy.push(Vec2::new(chunk[0], chunk[1]));
}
return Ok(());
} else {
return Err(JsValue::from_str(&format!("Layer {} not found", layer_idx)));
}
}
}
}
for tab in dashboard.tabs.iter_mut() {
for plot in tab.plots.iter_mut() {
if let Plot::Graph2D(graph) = plot {
if graph.id.0 == plot_id {
if let Some(layer) = graph.layers.get_mut(layer_idx) {
for chunk in points.chunks(2) {
layer.xy.push(Vec2::new(chunk[0], chunk[1]));
}
return Ok(());
}
}
}
}
}
Err(JsValue::from_str(&format!("Plot {} not found", plot_id)))
}
#[wasm_bindgen]
pub fn replace_trace(
&mut self,
plot_id: u64,
layer_idx: usize,
points: &[f32],
) -> Result<(), JsValue> {
if points.len() % 2 != 0 {
return Err(JsValue::from_str(
"Points array length must be even (x,y pairs)",
));
}
let mut dashboard = self.dashboard.lock();
let new_points: Vec<Vec2> = points
.chunks(2)
.map(|chunk| Vec2::new(chunk[0], chunk[1]))
.collect();
for plot in dashboard.plots.iter_mut() {
if let Plot::Graph2D(graph) = plot {
if graph.id.0 == plot_id {
if let Some(layer) = graph.layers.get_mut(layer_idx) {
layer.xy = new_points;
return Ok(());
}
}
}
}
for tab in dashboard.tabs.iter_mut() {
for plot in tab.plots.iter_mut() {
if let Plot::Graph2D(graph) = plot {
if graph.id.0 == plot_id {
if let Some(layer) = graph.layers.get_mut(layer_idx) {
layer.xy = new_points;
return Ok(());
}
}
}
}
}
Err(JsValue::from_str(&format!("Plot {} not found", plot_id)))
}
#[wasm_bindgen]
pub fn update_plot(&mut self, plot_id: u64, json: &str) -> Result<(), JsValue> {
let new_plot: Plot = serde_json::from_str(json)
.map_err(|e| JsValue::from_str(&format!("Failed to parse plot JSON: {}", e)))?;
let mut dashboard = self.dashboard.lock();
for plot in dashboard.plots.iter_mut() {
let id = match plot {
Plot::Graph2D(g) => g.id.0,
Plot::Graph3D(g) => g.id.0,
_ => continue,
};
if id == plot_id {
*plot = new_plot;
return Ok(());
}
}
for tab in dashboard.tabs.iter_mut() {
for plot in tab.plots.iter_mut() {
let id = match plot {
Plot::Graph2D(g) => g.id.0,
Plot::Graph3D(g) => g.id.0,
_ => continue,
};
if id == plot_id {
*plot = new_plot;
return Ok(());
}
}
}
Err(JsValue::from_str(&format!("Plot {} not found", plot_id)))
}
#[wasm_bindgen]
pub fn to_json(&self) -> Result<String, JsValue> {
let dashboard = self.dashboard.lock();
serde_json::to_string(&*dashboard)
.map_err(|e| JsValue::from_str(&format!("Failed to serialize dashboard: {}", e)))
}
#[wasm_bindgen(getter)]
pub fn canvas_id(&self) -> String {
self.canvas_id.clone()
}
#[wasm_bindgen(getter)]
pub fn is_started(&self) -> bool {
self.started
}
}