scirs2_metrics/visualization/advanced_interactive/
mod.rs

1//! Advanced interactive visualization with real-time capabilities
2//!
3//! This module provides sophisticated interactive visualization features including:
4//! - Float-time data streaming and updates
5//! - Advanced widget systems (sliders, dropdowns, filters)
6//! - Multi-dimensional visualization support
7//! - Interactive dashboard components
8//! - Collaborative visualization features
9//! - WebGL-accelerated rendering
10
11#![allow(clippy::too_many_arguments)]
12#![allow(dead_code)]
13
14use crate::error::{MetricsError, Result};
15use serde::{Deserialize, Serialize};
16use serde_json::Value;
17use std::collections::HashMap;
18use std::sync::{Arc, Mutex, RwLock};
19use std::time::Instant;
20
21// Module declarations
22pub mod collaboration;
23pub mod core;
24pub mod data_sources;
25pub mod events;
26pub mod layout;
27pub mod rendering;
28pub mod widgets;
29
30// Re-export core types
31pub use core::*;
32
33// Re-export widget system
34pub use widgets::{
35    BorderConfig, ChartType, DataBindingConfig, EventType, FontConfig, InputType,
36    InteractiveWidget, RenderContent, RenderContext, ShaderProgram, StyleConfig, WidgetConfig,
37    WidgetEvent, WidgetEventResponse, WidgetType,
38};
39
40// Re-export data sources
41pub use data_sources::{
42    ChangeType, ConnectionConfig, DataFormat, DataSource, DataSourceConfig, DataSourceManager,
43    DataSourceType, DataUpdate, ValidationConfig,
44};
45
46// Re-export event system
47pub use events::{
48    DashboardEvent, EventAction, EventHandler, EventMetadata, EventPriority, EventResponse,
49    EventSystem, NotificationLevel,
50};
51
52// Re-export layout management
53pub use layout::{
54    ContainerConstraints, GridPosition, LayoutConstraints, LayoutManager, Margin, WidgetLayout,
55};
56
57// Re-export rendering
58pub use rendering::{
59    PerformanceMonitor, RenderStatistics, RenderingBackend, RenderingConfig, RenderingEngine,
60    UpdateManager, UpdateRequest, UpdateType,
61};
62
63// Re-export collaboration
64pub use collaboration::{
65    CollaborationManager, Conflict, ConflictResolver, ConflictType, CursorPosition, Operation,
66    OperationType, Selection, SharedState, UserSession,
67};
68
69/// Advanced interactive dashboard for real-time metrics visualization
70pub struct InteractiveDashboard {
71    /// Dashboard configuration
72    config: DashboardConfig,
73    /// Collection of widgets
74    widgets: Arc<RwLock<HashMap<String, Box<dyn InteractiveWidget + Send + Sync>>>>,
75    /// Data sources for real-time updates
76    data_sources: Arc<RwLock<HashMap<String, Box<dyn DataSource + Send + Sync>>>>,
77    /// Event system for widget interactions
78    event_system: Arc<Mutex<EventSystem>>,
79    /// Layout manager
80    layout_manager: Arc<Mutex<LayoutManager>>,
81    /// Rendering engine
82    renderer: Arc<Mutex<Box<dyn RenderingEngine + Send + Sync>>>,
83    /// Float-time update manager
84    update_manager: Arc<Mutex<UpdateManager>>,
85    /// Collaboration manager
86    collaboration: Arc<Mutex<CollaborationManager>>,
87    /// Dashboard state
88    state: Arc<RwLock<DashboardState>>,
89}
90
91impl std::fmt::Debug for InteractiveDashboard {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        f.debug_struct("InteractiveDashboard")
94            .field("config", &self.config)
95            .field(
96                "widgets",
97                &format!("{} widgets", self.widgets.read().unwrap().len()),
98            )
99            .field(
100                "data_sources",
101                &format!("{} data sources", self.data_sources.read().unwrap().len()),
102            )
103            .field("event_system", &"<event_system>")
104            .field("layout_manager", &"<layout_manager>")
105            .field("renderer", &"<renderer>")
106            .field("update_manager", &"<update_manager>")
107            .field("collaboration", &"<collaboration>")
108            .field("state", &"<state>")
109            .finish()
110    }
111}
112
113/// Dashboard state
114#[derive(Debug, Clone, Serialize, Deserialize, Default)]
115pub struct DashboardState {
116    /// Current view state
117    pub view_state: ViewState,
118    /// Filter state
119    pub filters: HashMap<String, Value>,
120    /// Selection state
121    pub selections: Vec<String>,
122    /// Zoom and pan state
123    pub viewport: ViewportState,
124    /// Time range state
125    pub time_range: Option<TimeRange>,
126    /// Custom state variables
127    pub custom_state: HashMap<String, Value>,
128}
129
130/// View state
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct ViewState {
133    /// Current view mode
134    pub mode: ViewMode,
135    /// Visible widgets
136    pub visible_widgets: Vec<String>,
137    /// Widget z-order
138    pub z_order: Vec<String>,
139    /// Layout mode
140    pub layout_mode: String,
141}
142
143/// View mode enumeration
144#[derive(Debug, Clone, Serialize, Deserialize)]
145pub enum ViewMode {
146    /// Normal view
147    Normal,
148    /// Full-screen view
149    FullScreen,
150    /// Presentation mode
151    Presentation,
152    /// Edit mode
153    Edit,
154    /// Preview mode
155    Preview,
156}
157
158/// Viewport state for zoom and pan
159#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct ViewportState {
161    /// Zoom level
162    pub zoom: f64,
163    /// Pan offset X
164    pub pan_x: f64,
165    /// Pan offset Y
166    pub pan_y: f64,
167    /// Viewport bounds
168    pub bounds: ViewportBounds,
169}
170
171/// Viewport bounds
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct ViewportBounds {
174    /// Minimum X
175    pub min_x: f64,
176    /// Maximum X
177    pub max_x: f64,
178    /// Minimum Y
179    pub min_y: f64,
180    /// Maximum Y
181    pub max_y: f64,
182}
183
184/// Time range for temporal data
185#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct TimeRange {
187    /// Start time
188    pub start: std::time::SystemTime,
189    /// End time
190    pub end: std::time::SystemTime,
191    /// Time zone
192    pub timezone: Option<String>,
193}
194
195impl InteractiveDashboard {
196    /// Create new interactive dashboard
197    pub fn new(
198        config: DashboardConfig,
199        renderer: Box<dyn RenderingEngine + Send + Sync>,
200    ) -> Result<Self> {
201        let container_constraints = ContainerConstraints {
202            width: config.width as f64,
203            height: config.height as f64,
204            ..Default::default()
205        };
206
207        let layout_manager = LayoutManager::new(config.layout.clone(), container_constraints);
208        let event_system = EventSystem::new(events::EventSystemConfig::default());
209        let update_manager = UpdateManager::new(rendering::UpdateConfig::default());
210
211        let collaboration = if let Some(collab_config) = &config.collaboration_config {
212            CollaborationManager::new(collab_config.clone())
213        } else {
214            // Create a disabled collaboration manager
215            CollaborationManager::new(CollaborationConfig {
216                enabled: false,
217                auth: core::AuthConfig {
218                    method: core::AuthMethod::None,
219                    session_timeout: std::time::Duration::from_secs(3600),
220                    guest_access: true,
221                    required_permissions: Vec::new(),
222                },
223                sharing: core::ShareConfig {
224                    public_sharing: false,
225                    default_permission: core::PermissionLevel::ReadOnly,
226                    link_expiration: None,
227                    password_protection: false,
228                },
229                sync: core::SyncConfig {
230                    sync_interval: std::time::Duration::from_secs(5),
231                    conflict_resolution: core::ConflictResolution::LastWriterWins,
232                    operational_transforms: false,
233                    history_retention: std::time::Duration::from_secs(3600),
234                },
235                max_collaborators: 1,
236            })
237        };
238
239        Ok(Self {
240            config,
241            widgets: Arc::new(RwLock::new(HashMap::new())),
242            data_sources: Arc::new(RwLock::new(HashMap::new())),
243            event_system: Arc::new(Mutex::new(event_system)),
244            layout_manager: Arc::new(Mutex::new(layout_manager)),
245            renderer: Arc::new(Mutex::new(renderer)),
246            update_manager: Arc::new(Mutex::new(update_manager)),
247            collaboration: Arc::new(Mutex::new(collaboration)),
248            state: Arc::new(RwLock::new(DashboardState::default())),
249        })
250    }
251
252    /// Add widget to dashboard
253    pub fn add_widget(&self, widget: Box<dyn InteractiveWidget + Send + Sync>) -> Result<()> {
254        let widget_id = widget.id().to_string();
255        let widget_config = widget.config().clone();
256
257        // Add to widgets collection
258        self.widgets
259            .write()
260            .unwrap()
261            .insert(widget_id.clone(), widget);
262
263        // Update layout
264        self.layout_manager
265            .lock()
266            .unwrap()
267            .add_widget(&widget_config)?;
268
269        // Update view state
270        let mut state = self.state.write().unwrap();
271        state.view_state.visible_widgets.push(widget_id.clone());
272        state.view_state.z_order.push(widget_id);
273
274        Ok(())
275    }
276
277    /// Remove widget from dashboard
278    pub fn remove_widget(&self, widget_id: &str) -> Result<()> {
279        // Remove from widgets collection
280        self.widgets.write().unwrap().remove(widget_id);
281
282        // Update layout
283        self.layout_manager
284            .lock()
285            .unwrap()
286            .remove_widget(widget_id)?;
287
288        // Update view state
289        let mut state = self.state.write().unwrap();
290        state
291            .view_state
292            .visible_widgets
293            .retain(|id| id != widget_id);
294        state.view_state.z_order.retain(|id| id != widget_id);
295
296        Ok(())
297    }
298
299    /// Register data source
300    pub fn register_data_source(&self, source: Box<dyn DataSource + Send + Sync>) -> Result<()> {
301        let source_id = source.id().to_string();
302        self.data_sources.write().unwrap().insert(source_id, source);
303        Ok(())
304    }
305
306    /// Handle user interaction
307    pub fn handle_interaction(&self, event: WidgetEvent) -> Result<()> {
308        // Convert to dashboard event
309        let dashboard_event = DashboardEvent {
310            id: event.id.clone(),
311            event_type: format!("{:?}", event.event_type),
312            source: event.source_widget,
313            target: event.target,
314            timestamp: event.timestamp,
315            data: event.data,
316            metadata: EventMetadata::default(),
317        };
318
319        // Queue event for processing
320        self.event_system
321            .lock()
322            .unwrap()
323            .queue_event(dashboard_event)?;
324
325        Ok(())
326    }
327
328    /// Update dashboard state
329    pub fn update_state(&self, updates: HashMap<String, Value>) -> Result<()> {
330        let mut state = self.state.write().unwrap();
331
332        for (key, value) in updates {
333            state.custom_state.insert(key, value);
334        }
335
336        Ok(())
337    }
338
339    /// Render dashboard
340    pub fn render(&self, context: &RenderContext) -> Result<()> {
341        let widgets = self.widgets.read().unwrap();
342        let renderer = self.renderer.lock().unwrap();
343
344        // Clear render target
345        renderer.clear([0.0, 0.0, 0.0, 1.0])?;
346
347        // Get visible widgets in z-order
348        let state = self.state.read().unwrap();
349        let mut visible_widgets: Vec<_> = state
350            .view_state
351            .z_order
352            .iter()
353            .filter(|id| state.view_state.visible_widgets.contains(id))
354            .filter_map(|id| widgets.get(id))
355            .collect();
356
357        // Sort by z-index
358        visible_widgets.sort_by_key(|widget| widget.config().z_index);
359
360        // Render each widget
361        for widget in visible_widgets {
362            if let Ok(widget_render) = widget.render(context) {
363                renderer.render_widget(&widget_render, context)?;
364            }
365        }
366
367        // Present frame
368        renderer.present()?;
369
370        Ok(())
371    }
372
373    /// Process real-time updates
374    pub fn process_updates(&self) -> Result<()> {
375        // Process events
376        let _responses = self.event_system.lock().unwrap().process_events()?;
377
378        // Process data updates
379        let _update_requests = self.update_manager.lock().unwrap().process_updates()?;
380
381        // Apply collaboration updates
382        if self
383            .config
384            .collaboration_config
385            .as_ref()
386            .is_some_and(|c| c.enabled)
387        {
388            let _resolved_operations = self.collaboration.lock().unwrap().resolve_conflicts()?;
389        }
390
391        Ok(())
392    }
393
394    /// Get dashboard configuration
395    pub fn config(&self) -> &DashboardConfig {
396        &self.config
397    }
398
399    /// Get current dashboard state
400    pub fn state(&self) -> DashboardState {
401        self.state.read().unwrap().clone()
402    }
403
404    /// Export dashboard configuration
405    pub fn export_config(&self) -> Result<Value> {
406        serde_json::to_value(&self.config).map_err(|e| MetricsError::InvalidInput(e.to_string()))
407    }
408
409    /// Import dashboard configuration
410    pub fn import_config(&mut self, config_data: Value) -> Result<()> {
411        self.config = serde_json::from_value(config_data)
412            .map_err(|e| MetricsError::InvalidInput(e.to_string()))?;
413        Ok(())
414    }
415}
416
417impl Default for ViewState {
418    fn default() -> Self {
419        Self {
420            mode: ViewMode::Normal,
421            visible_widgets: Vec::new(),
422            z_order: Vec::new(),
423            layout_mode: "grid".to_string(),
424        }
425    }
426}
427
428impl Default for ViewportState {
429    fn default() -> Self {
430        Self {
431            zoom: 1.0,
432            pan_x: 0.0,
433            pan_y: 0.0,
434            bounds: ViewportBounds::default(),
435        }
436    }
437}
438
439impl Default for ViewportBounds {
440    fn default() -> Self {
441        Self {
442            min_x: 0.0,
443            max_x: 1200.0,
444            min_y: 0.0,
445            max_y: 800.0,
446        }
447    }
448}