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!(
98                    "{} widgets",
99                    self.widgets.read().expect("Operation failed").len()
100                ),
101            )
102            .field(
103                "data_sources",
104                &format!(
105                    "{} data sources",
106                    self.data_sources.read().expect("Operation failed").len()
107                ),
108            )
109            .field("event_system", &"<event_system>")
110            .field("layout_manager", &"<layout_manager>")
111            .field("renderer", &"<renderer>")
112            .field("update_manager", &"<update_manager>")
113            .field("collaboration", &"<collaboration>")
114            .field("state", &"<state>")
115            .finish()
116    }
117}
118
119/// Dashboard state
120#[derive(Debug, Clone, Serialize, Deserialize, Default)]
121pub struct DashboardState {
122    /// Current view state
123    pub view_state: ViewState,
124    /// Filter state
125    pub filters: HashMap<String, Value>,
126    /// Selection state
127    pub selections: Vec<String>,
128    /// Zoom and pan state
129    pub viewport: ViewportState,
130    /// Time range state
131    pub time_range: Option<TimeRange>,
132    /// Custom state variables
133    pub custom_state: HashMap<String, Value>,
134}
135
136/// View state
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct ViewState {
139    /// Current view mode
140    pub mode: ViewMode,
141    /// Visible widgets
142    pub visible_widgets: Vec<String>,
143    /// Widget z-order
144    pub z_order: Vec<String>,
145    /// Layout mode
146    pub layout_mode: String,
147}
148
149/// View mode enumeration
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub enum ViewMode {
152    /// Normal view
153    Normal,
154    /// Full-screen view
155    FullScreen,
156    /// Presentation mode
157    Presentation,
158    /// Edit mode
159    Edit,
160    /// Preview mode
161    Preview,
162}
163
164/// Viewport state for zoom and pan
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct ViewportState {
167    /// Zoom level
168    pub zoom: f64,
169    /// Pan offset X
170    pub pan_x: f64,
171    /// Pan offset Y
172    pub pan_y: f64,
173    /// Viewport bounds
174    pub bounds: ViewportBounds,
175}
176
177/// Viewport bounds
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct ViewportBounds {
180    /// Minimum X
181    pub min_x: f64,
182    /// Maximum X
183    pub max_x: f64,
184    /// Minimum Y
185    pub min_y: f64,
186    /// Maximum Y
187    pub max_y: f64,
188}
189
190/// Time range for temporal data
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct TimeRange {
193    /// Start time
194    pub start: std::time::SystemTime,
195    /// End time
196    pub end: std::time::SystemTime,
197    /// Time zone
198    pub timezone: Option<String>,
199}
200
201impl InteractiveDashboard {
202    /// Create new interactive dashboard
203    pub fn new(
204        config: DashboardConfig,
205        renderer: Box<dyn RenderingEngine + Send + Sync>,
206    ) -> Result<Self> {
207        let container_constraints = ContainerConstraints {
208            width: config.width as f64,
209            height: config.height as f64,
210            ..Default::default()
211        };
212
213        let layout_manager = LayoutManager::new(config.layout.clone(), container_constraints);
214        let event_system = EventSystem::new(events::EventSystemConfig::default());
215        let update_manager = UpdateManager::new(rendering::UpdateConfig::default());
216
217        let collaboration = if let Some(collab_config) = &config.collaboration_config {
218            CollaborationManager::new(collab_config.clone())
219        } else {
220            // Create a disabled collaboration manager
221            CollaborationManager::new(CollaborationConfig {
222                enabled: false,
223                auth: core::AuthConfig {
224                    method: core::AuthMethod::None,
225                    session_timeout: std::time::Duration::from_secs(3600),
226                    guest_access: true,
227                    required_permissions: Vec::new(),
228                },
229                sharing: core::ShareConfig {
230                    public_sharing: false,
231                    default_permission: core::PermissionLevel::ReadOnly,
232                    link_expiration: None,
233                    password_protection: false,
234                },
235                sync: core::SyncConfig {
236                    sync_interval: std::time::Duration::from_secs(5),
237                    conflict_resolution: core::ConflictResolution::LastWriterWins,
238                    operational_transforms: false,
239                    history_retention: std::time::Duration::from_secs(3600),
240                },
241                max_collaborators: 1,
242            })
243        };
244
245        Ok(Self {
246            config,
247            widgets: Arc::new(RwLock::new(HashMap::new())),
248            data_sources: Arc::new(RwLock::new(HashMap::new())),
249            event_system: Arc::new(Mutex::new(event_system)),
250            layout_manager: Arc::new(Mutex::new(layout_manager)),
251            renderer: Arc::new(Mutex::new(renderer)),
252            update_manager: Arc::new(Mutex::new(update_manager)),
253            collaboration: Arc::new(Mutex::new(collaboration)),
254            state: Arc::new(RwLock::new(DashboardState::default())),
255        })
256    }
257
258    /// Add widget to dashboard
259    pub fn add_widget(&self, widget: Box<dyn InteractiveWidget + Send + Sync>) -> Result<()> {
260        let widget_id = widget.id().to_string();
261        let widget_config = widget.config().clone();
262
263        // Add to widgets collection
264        self.widgets
265            .write()
266            .expect("Operation failed")
267            .insert(widget_id.clone(), widget);
268
269        // Update layout
270        self.layout_manager
271            .lock()
272            .expect("Operation failed")
273            .add_widget(&widget_config)?;
274
275        // Update view state
276        let mut state = self.state.write().expect("Operation failed");
277        state.view_state.visible_widgets.push(widget_id.clone());
278        state.view_state.z_order.push(widget_id);
279
280        Ok(())
281    }
282
283    /// Remove widget from dashboard
284    pub fn remove_widget(&self, widget_id: &str) -> Result<()> {
285        // Remove from widgets collection
286        self.widgets
287            .write()
288            .expect("Operation failed")
289            .remove(widget_id);
290
291        // Update layout
292        self.layout_manager
293            .lock()
294            .expect("Operation failed")
295            .remove_widget(widget_id)?;
296
297        // Update view state
298        let mut state = self.state.write().expect("Operation failed");
299        state
300            .view_state
301            .visible_widgets
302            .retain(|id| id != widget_id);
303        state.view_state.z_order.retain(|id| id != widget_id);
304
305        Ok(())
306    }
307
308    /// Register data source
309    pub fn register_data_source(&self, source: Box<dyn DataSource + Send + Sync>) -> Result<()> {
310        let source_id = source.id().to_string();
311        self.data_sources
312            .write()
313            .expect("Operation failed")
314            .insert(source_id, source);
315        Ok(())
316    }
317
318    /// Handle user interaction
319    pub fn handle_interaction(&self, event: WidgetEvent) -> Result<()> {
320        // Convert to dashboard event
321        let dashboard_event = DashboardEvent {
322            id: event.id.clone(),
323            event_type: format!("{:?}", event.event_type),
324            source: event.source_widget,
325            target: event.target,
326            timestamp: event.timestamp,
327            data: event.data,
328            metadata: EventMetadata::default(),
329        };
330
331        // Queue event for processing
332        self.event_system
333            .lock()
334            .expect("Operation failed")
335            .queue_event(dashboard_event)?;
336
337        Ok(())
338    }
339
340    /// Update dashboard state
341    pub fn update_state(&self, updates: HashMap<String, Value>) -> Result<()> {
342        let mut state = self.state.write().expect("Operation failed");
343
344        for (key, value) in updates {
345            state.custom_state.insert(key, value);
346        }
347
348        Ok(())
349    }
350
351    /// Render dashboard
352    pub fn render(&self, context: &RenderContext) -> Result<()> {
353        let widgets = self.widgets.read().expect("Operation failed");
354        let renderer = self.renderer.lock().expect("Operation failed");
355
356        // Clear render target
357        renderer.clear([0.0, 0.0, 0.0, 1.0])?;
358
359        // Get visible widgets in z-order
360        let state = self.state.read().expect("Operation failed");
361        let mut visible_widgets: Vec<_> = state
362            .view_state
363            .z_order
364            .iter()
365            .filter(|id| state.view_state.visible_widgets.contains(id))
366            .filter_map(|id| widgets.get(id))
367            .collect();
368
369        // Sort by z-index
370        visible_widgets.sort_by_key(|widget| widget.config().z_index);
371
372        // Render each widget
373        for widget in visible_widgets {
374            if let Ok(widget_render) = widget.render(context) {
375                renderer.render_widget(&widget_render, context)?;
376            }
377        }
378
379        // Present frame
380        renderer.present()?;
381
382        Ok(())
383    }
384
385    /// Process real-time updates
386    pub fn process_updates(&self) -> Result<()> {
387        // Process events
388        let _responses = self
389            .event_system
390            .lock()
391            .expect("Operation failed")
392            .process_events()?;
393
394        // Process data updates
395        let _update_requests = self
396            .update_manager
397            .lock()
398            .expect("Operation failed")
399            .process_updates()?;
400
401        // Apply collaboration updates
402        if self
403            .config
404            .collaboration_config
405            .as_ref()
406            .is_some_and(|c| c.enabled)
407        {
408            let _resolved_operations = self
409                .collaboration
410                .lock()
411                .expect("Operation failed")
412                .resolve_conflicts()?;
413        }
414
415        Ok(())
416    }
417
418    /// Get dashboard configuration
419    pub fn config(&self) -> &DashboardConfig {
420        &self.config
421    }
422
423    /// Get current dashboard state
424    pub fn state(&self) -> DashboardState {
425        self.state.read().expect("Operation failed").clone()
426    }
427
428    /// Export dashboard configuration
429    pub fn export_config(&self) -> Result<Value> {
430        serde_json::to_value(&self.config).map_err(|e| MetricsError::InvalidInput(e.to_string()))
431    }
432
433    /// Import dashboard configuration
434    pub fn import_config(&mut self, config_data: Value) -> Result<()> {
435        self.config = serde_json::from_value(config_data)
436            .map_err(|e| MetricsError::InvalidInput(e.to_string()))?;
437        Ok(())
438    }
439}
440
441impl Default for ViewState {
442    fn default() -> Self {
443        Self {
444            mode: ViewMode::Normal,
445            visible_widgets: Vec::new(),
446            z_order: Vec::new(),
447            layout_mode: "grid".to_string(),
448        }
449    }
450}
451
452impl Default for ViewportState {
453    fn default() -> Self {
454        Self {
455            zoom: 1.0,
456            pan_x: 0.0,
457            pan_y: 0.0,
458            bounds: ViewportBounds::default(),
459        }
460    }
461}
462
463impl Default for ViewportBounds {
464    fn default() -> Self {
465        Self {
466            min_x: 0.0,
467            max_x: 1200.0,
468            min_y: 0.0,
469            max_y: 800.0,
470        }
471    }
472}