1use super::config::{
7 ChartType, ColorScheme, CustomVisualization, DashboardLayout, ExportFormat, ReportTemplate,
8 VisualizationConfig,
9};
10use super::data::{DashboardData, RealtimeMetrics, TimeSeriesData};
11use crate::DeviceResult;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::time::{Duration, SystemTime};
15
16pub struct DashboardRenderer {
18 config: VisualizationConfig,
19 chart_generators: HashMap<ChartType, Box<dyn ChartGenerator + Send + Sync>>,
20 layout_manager: LayoutManager,
21 export_engine: ExportEngine,
22 theme_manager: ThemeManager,
23}
24
25pub trait ChartGenerator {
27 fn generate(&self, data: &ChartData, options: &ChartOptions) -> DeviceResult<Chart>;
28 fn supports_interactivity(&self) -> bool;
29 fn get_supported_formats(&self) -> Vec<ChartFormat>;
30}
31
32#[derive(Debug, Clone)]
34pub struct ChartData {
35 pub data_type: ChartDataType,
36 pub series: Vec<DataSeries>,
37 pub metadata: ChartMetadata,
38}
39
40#[derive(Debug, Clone, PartialEq)]
42pub enum ChartDataType {
43 TimeSeries,
44 Categorical,
45 Numerical,
46 Correlation,
47 Distribution,
48 Geospatial,
49 Custom(String),
50}
51
52#[derive(Debug, Clone)]
54pub struct DataSeries {
55 pub name: String,
56 pub data_points: Vec<DataPoint>,
57 pub series_type: SeriesType,
58 pub styling: SeriesStyling,
59}
60
61#[derive(Debug, Clone)]
63pub struct DataPoint {
64 pub x: DataValue,
65 pub y: DataValue,
66 pub z: Option<DataValue>, pub metadata: HashMap<String, String>,
68}
69
70#[derive(Debug, Clone)]
72pub enum DataValue {
73 Number(f64),
74 Text(String),
75 Timestamp(SystemTime),
76 Boolean(bool),
77 Array(Vec<f64>),
78}
79
80#[derive(Debug, Clone, PartialEq)]
82pub enum SeriesType {
83 Line,
84 Bar,
85 Scatter,
86 Area,
87 Candlestick,
88 Bubble,
89 Custom(String),
90}
91
92#[derive(Debug, Clone)]
94pub struct SeriesStyling {
95 pub color: String,
96 pub line_width: f64,
97 pub marker_size: f64,
98 pub opacity: f64,
99 pub fill_pattern: Option<String>,
100 pub custom_styles: HashMap<String, String>,
101}
102
103#[derive(Debug, Clone)]
105pub struct ChartMetadata {
106 pub title: String,
107 pub subtitle: Option<String>,
108 pub x_axis_label: String,
109 pub y_axis_label: String,
110 pub data_source: String,
111 pub last_updated: SystemTime,
112 pub chart_id: String,
113}
114
115#[derive(Debug, Clone)]
117pub struct ChartOptions {
118 pub width: u32,
119 pub height: u32,
120 pub interactive: bool,
121 pub animation: bool,
122 pub legend: LegendOptions,
123 pub axes: AxesOptions,
124 pub grid: GridOptions,
125 pub tooltip: TooltipOptions,
126 pub custom_options: HashMap<String, String>,
127}
128
129#[derive(Debug, Clone)]
131pub struct LegendOptions {
132 pub show: bool,
133 pub position: LegendPosition,
134 pub orientation: LegendOrientation,
135 pub styling: HashMap<String, String>,
136}
137
138#[derive(Debug, Clone, PartialEq)]
140pub enum LegendPosition {
141 Top,
142 Bottom,
143 Left,
144 Right,
145 TopLeft,
146 TopRight,
147 BottomLeft,
148 BottomRight,
149 Custom { x: f64, y: f64 },
150}
151
152#[derive(Debug, Clone, PartialEq)]
154pub enum LegendOrientation {
155 Horizontal,
156 Vertical,
157}
158
159#[derive(Debug, Clone)]
161pub struct AxesOptions {
162 pub x_axis: AxisOptions,
163 pub y_axis: AxisOptions,
164 pub y2_axis: Option<AxisOptions>, }
166
167#[derive(Debug, Clone)]
169pub struct AxisOptions {
170 pub show: bool,
171 pub title: String,
172 pub min: Option<f64>,
173 pub max: Option<f64>,
174 pub tick_interval: Option<f64>,
175 pub tick_format: String,
176 pub logarithmic: bool,
177 pub grid_lines: bool,
178}
179
180#[derive(Debug, Clone)]
182pub struct GridOptions {
183 pub show: bool,
184 pub major_lines: bool,
185 pub minor_lines: bool,
186 pub line_style: String,
187 pub color: String,
188 pub opacity: f64,
189}
190
191#[derive(Debug, Clone)]
193pub struct TooltipOptions {
194 pub show: bool,
195 pub format: String,
196 pub background_color: String,
197 pub border_color: String,
198 pub follow_mouse: bool,
199}
200
201#[derive(Debug, Clone)]
203pub struct Chart {
204 pub chart_id: String,
205 pub chart_type: ChartType,
206 pub format: ChartFormat,
207 pub content: ChartContent,
208 pub metadata: ChartMetadata,
209 pub interactive_features: Vec<InteractiveFeature>,
210}
211
212#[derive(Debug, Clone, PartialEq)]
214pub enum ChartFormat {
215 SVG,
216 PNG,
217 JPEG,
218 HTML,
219 Canvas,
220 WebGL,
221 PDF,
222 Custom(String),
223}
224
225#[derive(Debug, Clone)]
227pub enum ChartContent {
228 Image(Vec<u8>),
229 SVG(String),
230 HTML(String),
231 JSON(String),
232 Custom(String, Vec<u8>),
233}
234
235#[derive(Debug, Clone)]
237pub enum InteractiveFeature {
238 Zoom,
239 Pan,
240 Hover,
241 Click,
242 Brush,
243 Crossfilter,
244 Animation,
245 Custom(String),
246}
247
248pub struct LayoutManager {
250 layout_type: DashboardLayout,
251 grid_config: GridConfiguration,
252 responsive_rules: Vec<ResponsiveRule>,
253 layout_cache: HashMap<String, LayoutResult>,
254}
255
256#[derive(Debug, Clone)]
258pub struct GridConfiguration {
259 pub columns: usize,
260 pub rows: usize,
261 pub gap: f64,
262 pub padding: f64,
263 pub responsive_breakpoints: Vec<Breakpoint>,
264}
265
266#[derive(Debug, Clone)]
268pub struct Breakpoint {
269 pub width: u32,
270 pub columns: usize,
271 pub chart_height: u32,
272}
273
274#[derive(Debug, Clone)]
276pub struct ResponsiveRule {
277 pub condition: ResponsiveCondition,
278 pub action: ResponsiveAction,
279}
280
281#[derive(Debug, Clone)]
283pub enum ResponsiveCondition {
284 ScreenWidth { min: Option<u32>, max: Option<u32> },
285 ScreenHeight { min: Option<u32>, max: Option<u32> },
286 DeviceType(DeviceType),
287 Custom(String),
288}
289
290#[derive(Debug, Clone, PartialEq)]
292pub enum DeviceType {
293 Desktop,
294 Tablet,
295 Mobile,
296 TV,
297 Custom(String),
298}
299
300#[derive(Debug, Clone)]
302pub enum ResponsiveAction {
303 ChangeLayout(DashboardLayout),
304 AdjustChartSize { width: u32, height: u32 },
305 HideCharts(Vec<String>),
306 ReorderCharts(Vec<String>),
307 Custom(String),
308}
309
310#[derive(Debug, Clone)]
312pub struct LayoutResult {
313 pub layout_type: DashboardLayout,
314 pub chart_positions: Vec<ChartPosition>,
315 pub total_width: u32,
316 pub total_height: u32,
317 pub responsive_applied: Vec<String>,
318}
319
320#[derive(Debug, Clone)]
322pub struct ChartPosition {
323 pub chart_id: String,
324 pub x: u32,
325 pub y: u32,
326 pub width: u32,
327 pub height: u32,
328 pub z_index: i32,
329}
330
331pub struct ExportEngine {
333 export_formats: Vec<ExportFormat>,
334 template_engine: TemplateEngine,
335 format_converters: HashMap<ExportFormat, Box<dyn FormatConverter + Send + Sync>>,
336}
337
338pub trait FormatConverter {
340 fn convert(&self, content: &ExportContent, options: &ExportOptions) -> DeviceResult<Vec<u8>>;
341 fn get_mime_type(&self) -> String;
342 fn get_file_extension(&self) -> String;
343}
344
345#[derive(Debug, Clone)]
347pub struct ExportContent {
348 pub charts: Vec<Chart>,
349 pub data_tables: Vec<DataTable>,
350 pub text_sections: Vec<TextSection>,
351 pub metadata: ExportMetadata,
352}
353
354#[derive(Debug, Clone)]
356pub struct DataTable {
357 pub table_id: String,
358 pub title: String,
359 pub headers: Vec<String>,
360 pub rows: Vec<Vec<String>>,
361 pub formatting: TableFormatting,
362}
363
364#[derive(Debug, Clone)]
366pub struct TableFormatting {
367 pub header_style: HashMap<String, String>,
368 pub row_style: HashMap<String, String>,
369 pub alternating_rows: bool,
370 pub borders: bool,
371}
372
373#[derive(Debug, Clone)]
375pub struct TextSection {
376 pub section_id: String,
377 pub title: String,
378 pub content: String,
379 pub format_type: TextFormatType,
380 pub styling: HashMap<String, String>,
381}
382
383#[derive(Debug, Clone, PartialEq)]
385pub enum TextFormatType {
386 PlainText,
387 Markdown,
388 HTML,
389 LaTeX,
390 Custom(String),
391}
392
393#[derive(Debug, Clone)]
395pub struct ExportMetadata {
396 pub title: String,
397 pub author: String,
398 pub creation_date: SystemTime,
399 pub description: String,
400 pub version: String,
401 pub custom_fields: HashMap<String, String>,
402}
403
404#[derive(Debug, Clone)]
406pub struct ExportOptions {
407 pub format: ExportFormat,
408 pub quality: ExportQuality,
409 pub compression: bool,
410 pub include_data: bool,
411 pub include_metadata: bool,
412 pub page_settings: PageSettings,
413 pub custom_options: HashMap<String, String>,
414}
415
416#[derive(Debug, Clone, PartialEq)]
418pub enum ExportQuality {
419 Low,
420 Medium,
421 High,
422 Maximum,
423 Custom(u32),
424}
425
426#[derive(Debug, Clone)]
428pub struct PageSettings {
429 pub page_size: PageSize,
430 pub orientation: PageOrientation,
431 pub margins: PageMargins,
432 pub header: Option<String>,
433 pub footer: Option<String>,
434}
435
436#[derive(Debug, Clone, PartialEq)]
438pub enum PageSize {
439 A4,
440 A3,
441 Letter,
442 Legal,
443 Custom { width: u32, height: u32 },
444}
445
446#[derive(Debug, Clone, PartialEq)]
448pub enum PageOrientation {
449 Portrait,
450 Landscape,
451}
452
453#[derive(Debug, Clone)]
455pub struct PageMargins {
456 pub top: u32,
457 pub bottom: u32,
458 pub left: u32,
459 pub right: u32,
460}
461
462pub struct TemplateEngine {
464 templates: HashMap<String, ReportTemplate>,
465 template_cache: HashMap<String, CompiledTemplate>,
466 variable_resolver: VariableResolver,
467}
468
469#[derive(Debug, Clone)]
471pub struct CompiledTemplate {
472 pub template_id: String,
473 pub template_content: String,
474 pub variables: Vec<TemplateVariable>,
475 pub sections: Vec<TemplateSection>,
476}
477
478#[derive(Debug, Clone)]
480pub struct TemplateVariable {
481 pub name: String,
482 pub variable_type: VariableType,
483 pub default_value: Option<String>,
484 pub required: bool,
485}
486
487#[derive(Debug, Clone, PartialEq)]
489pub enum VariableType {
490 Text,
491 Number,
492 Date,
493 Chart,
494 Table,
495 Image,
496 Custom(String),
497}
498
499#[derive(Debug, Clone)]
501pub struct TemplateSection {
502 pub section_id: String,
503 pub section_type: String,
504 pub content: String,
505 pub variables: Vec<String>,
506 pub conditional: Option<String>,
507}
508
509pub struct VariableResolver {
511 resolvers: HashMap<String, Box<dyn VariableProvider + Send + Sync>>,
512}
513
514pub trait VariableProvider {
516 fn resolve(&self, variable_name: &str, context: &ResolverContext) -> DeviceResult<String>;
517 fn get_supported_variables(&self) -> Vec<String>;
518}
519
520#[derive(Debug, Clone)]
522pub struct ResolverContext {
523 pub dashboard_data: DashboardData,
524 pub export_options: ExportOptions,
525 pub user_variables: HashMap<String, String>,
526}
527
528pub struct ThemeManager {
530 current_theme: Theme,
531 available_themes: HashMap<String, Theme>,
532 custom_css: HashMap<String, String>,
533}
534
535#[derive(Debug, Clone)]
537pub struct Theme {
538 pub theme_id: String,
539 pub theme_name: String,
540 pub color_palette: ColorPalette,
541 pub typography: Typography,
542 pub spacing: Spacing,
543 pub borders: BorderStyles,
544 pub shadows: ShadowStyles,
545}
546
547#[derive(Debug, Clone)]
549pub struct ColorPalette {
550 pub primary: String,
551 pub secondary: String,
552 pub accent: String,
553 pub background: String,
554 pub surface: String,
555 pub text_primary: String,
556 pub text_secondary: String,
557 pub success: String,
558 pub warning: String,
559 pub error: String,
560 pub info: String,
561 pub chart_colors: Vec<String>,
562}
563
564#[derive(Debug, Clone)]
566pub struct Typography {
567 pub font_family: String,
568 pub font_sizes: HashMap<String, u32>,
569 pub font_weights: HashMap<String, u32>,
570 pub line_heights: HashMap<String, f64>,
571}
572
573#[derive(Debug, Clone)]
575pub struct Spacing {
576 pub base_unit: u32,
577 pub small: u32,
578 pub medium: u32,
579 pub large: u32,
580 pub extra_large: u32,
581}
582
583#[derive(Debug, Clone)]
585pub struct BorderStyles {
586 pub width: HashMap<String, u32>,
587 pub style: HashMap<String, String>,
588 pub color: HashMap<String, String>,
589 pub radius: HashMap<String, u32>,
590}
591
592#[derive(Debug, Clone)]
594pub struct ShadowStyles {
595 pub box_shadows: HashMap<String, String>,
596 pub text_shadows: HashMap<String, String>,
597}
598
599impl DashboardRenderer {
600 pub fn new(config: VisualizationConfig) -> Self {
601 let mut chart_generators: HashMap<ChartType, Box<dyn ChartGenerator + Send + Sync>> =
602 HashMap::new();
603
604 chart_generators.insert(ChartType::LineChart, Box::new(LineChartGenerator::new()));
606 chart_generators.insert(ChartType::BarChart, Box::new(BarChartGenerator::new()));
607 chart_generators.insert(ChartType::HeatMap, Box::new(HeatMapGenerator::new()));
608
609 Self {
610 config: config.clone(),
611 chart_generators,
612 layout_manager: LayoutManager::new(config.dashboard_layout.clone()),
613 export_engine: ExportEngine::new(),
614 theme_manager: ThemeManager::new(config.color_scheme.clone()),
615 }
616 }
617
618 pub async fn render_dashboard(&self, data: &DashboardData) -> DeviceResult<DashboardView> {
619 let mut charts = Vec::new();
620
621 for chart_type in &self.config.chart_types {
623 if let Some(generator) = self.chart_generators.get(chart_type) {
624 let chart_data = self.prepare_chart_data(data, chart_type)?;
625 let chart_options = self.create_chart_options(chart_type)?;
626 let chart = generator.generate(&chart_data, &chart_options)?;
627 charts.push(chart);
628 }
629 }
630
631 let layout = self.layout_manager.arrange_charts(&charts).await?;
633
634 Ok(DashboardView {
636 view_id: format!(
637 "dashboard-{}",
638 SystemTime::now()
639 .duration_since(std::time::UNIX_EPOCH)
640 .unwrap()
641 .as_secs()
642 ),
643 title: "Performance Analytics Dashboard".to_string(),
644 charts,
645 layout,
646 theme: self.theme_manager.get_current_theme().clone(),
647 last_updated: SystemTime::now(),
648 })
649 }
650
651 pub async fn export_dashboard(
652 &self,
653 data: &DashboardData,
654 export_options: &ExportOptions,
655 ) -> DeviceResult<Vec<u8>> {
656 let export_content = self.prepare_export_content(data).await?;
657 self.export_engine
658 .export(&export_content, export_options)
659 .await
660 }
661
662 fn prepare_chart_data(
663 &self,
664 data: &DashboardData,
665 chart_type: &ChartType,
666 ) -> DeviceResult<ChartData> {
667 match chart_type {
668 ChartType::LineChart => self.prepare_line_chart_data(data),
669 ChartType::BarChart => self.prepare_bar_chart_data(data),
670 ChartType::HeatMap => self.prepare_heatmap_data(data),
671 _ => Ok(ChartData::default()),
672 }
673 }
674
675 fn prepare_line_chart_data(&self, data: &DashboardData) -> DeviceResult<ChartData> {
676 let series = vec![DataSeries {
678 name: "Fidelity".to_string(),
679 data_points: vec![DataPoint {
680 x: DataValue::Timestamp(SystemTime::now()),
681 y: DataValue::Number(data.realtime_metrics.device_metrics.fidelity),
682 z: None,
683 metadata: HashMap::new(),
684 }],
685 series_type: SeriesType::Line,
686 styling: SeriesStyling::default(),
687 }];
688
689 Ok(ChartData {
690 data_type: ChartDataType::TimeSeries,
691 series,
692 metadata: ChartMetadata {
693 title: "Device Performance".to_string(),
694 subtitle: Some("Real-time metrics".to_string()),
695 x_axis_label: "Time".to_string(),
696 y_axis_label: "Value".to_string(),
697 data_source: "Performance Dashboard".to_string(),
698 last_updated: SystemTime::now(),
699 chart_id: "device-performance".to_string(),
700 },
701 })
702 }
703
704 fn prepare_bar_chart_data(&self, _data: &DashboardData) -> DeviceResult<ChartData> {
705 Ok(ChartData::default())
707 }
708
709 fn prepare_heatmap_data(&self, _data: &DashboardData) -> DeviceResult<ChartData> {
710 Ok(ChartData::default())
712 }
713
714 fn create_chart_options(&self, _chart_type: &ChartType) -> DeviceResult<ChartOptions> {
715 Ok(ChartOptions {
716 width: 800,
717 height: 400,
718 interactive: self.config.enable_interactive_charts,
719 animation: true,
720 legend: LegendOptions {
721 show: true,
722 position: LegendPosition::Right,
723 orientation: LegendOrientation::Vertical,
724 styling: HashMap::new(),
725 },
726 axes: AxesOptions {
727 x_axis: AxisOptions::default(),
728 y_axis: AxisOptions::default(),
729 y2_axis: None,
730 },
731 grid: GridOptions::default(),
732 tooltip: TooltipOptions::default(),
733 custom_options: HashMap::new(),
734 })
735 }
736
737 async fn prepare_export_content(&self, data: &DashboardData) -> DeviceResult<ExportContent> {
738 Ok(ExportContent {
740 charts: Vec::new(),
741 data_tables: Vec::new(),
742 text_sections: Vec::new(),
743 metadata: ExportMetadata {
744 title: "Performance Analytics Report".to_string(),
745 author: "QuantRS Dashboard".to_string(),
746 creation_date: SystemTime::now(),
747 description: "Automated performance report".to_string(),
748 version: "1.0".to_string(),
749 custom_fields: HashMap::new(),
750 },
751 })
752 }
753}
754
755#[derive(Debug, Clone)]
757pub struct DashboardView {
758 pub view_id: String,
759 pub title: String,
760 pub charts: Vec<Chart>,
761 pub layout: LayoutResult,
762 pub theme: Theme,
763 pub last_updated: SystemTime,
764}
765
766struct LineChartGenerator;
768struct BarChartGenerator;
769struct HeatMapGenerator;
770
771impl LineChartGenerator {
772 fn new() -> Self {
773 Self
774 }
775}
776
777impl ChartGenerator for LineChartGenerator {
778 fn generate(&self, data: &ChartData, options: &ChartOptions) -> DeviceResult<Chart> {
779 Ok(Chart {
781 chart_id: data.metadata.chart_id.clone(),
782 chart_type: ChartType::LineChart,
783 format: ChartFormat::SVG,
784 content: ChartContent::SVG("<svg>Line Chart</svg>".to_string()),
785 metadata: data.metadata.clone(),
786 interactive_features: if options.interactive {
787 vec![
788 InteractiveFeature::Zoom,
789 InteractiveFeature::Pan,
790 InteractiveFeature::Hover,
791 ]
792 } else {
793 Vec::new()
794 },
795 })
796 }
797
798 fn supports_interactivity(&self) -> bool {
799 true
800 }
801 fn get_supported_formats(&self) -> Vec<ChartFormat> {
802 vec![ChartFormat::SVG, ChartFormat::PNG, ChartFormat::HTML]
803 }
804}
805
806impl BarChartGenerator {
807 fn new() -> Self {
808 Self
809 }
810}
811
812impl ChartGenerator for BarChartGenerator {
813 fn generate(&self, data: &ChartData, _options: &ChartOptions) -> DeviceResult<Chart> {
814 Ok(Chart {
815 chart_id: data.metadata.chart_id.clone(),
816 chart_type: ChartType::BarChart,
817 format: ChartFormat::SVG,
818 content: ChartContent::SVG("<svg>Bar Chart</svg>".to_string()),
819 metadata: data.metadata.clone(),
820 interactive_features: Vec::new(),
821 })
822 }
823
824 fn supports_interactivity(&self) -> bool {
825 true
826 }
827 fn get_supported_formats(&self) -> Vec<ChartFormat> {
828 vec![ChartFormat::SVG, ChartFormat::PNG]
829 }
830}
831
832impl HeatMapGenerator {
833 fn new() -> Self {
834 Self
835 }
836}
837
838impl ChartGenerator for HeatMapGenerator {
839 fn generate(&self, data: &ChartData, _options: &ChartOptions) -> DeviceResult<Chart> {
840 Ok(Chart {
841 chart_id: data.metadata.chart_id.clone(),
842 chart_type: ChartType::HeatMap,
843 format: ChartFormat::SVG,
844 content: ChartContent::SVG("<svg>Heat Map</svg>".to_string()),
845 metadata: data.metadata.clone(),
846 interactive_features: Vec::new(),
847 })
848 }
849
850 fn supports_interactivity(&self) -> bool {
851 false
852 }
853 fn get_supported_formats(&self) -> Vec<ChartFormat> {
854 vec![ChartFormat::SVG, ChartFormat::PNG]
855 }
856}
857
858impl LayoutManager {
859 pub fn new(layout_type: DashboardLayout) -> Self {
860 Self {
861 layout_type,
862 grid_config: GridConfiguration::default(),
863 responsive_rules: Vec::new(),
864 layout_cache: HashMap::new(),
865 }
866 }
867
868 pub async fn arrange_charts(&self, charts: &[Chart]) -> DeviceResult<LayoutResult> {
869 let chart_positions = charts
871 .iter()
872 .enumerate()
873 .map(|(i, chart)| ChartPosition {
874 chart_id: chart.chart_id.clone(),
875 x: (i % 2) as u32 * 400,
876 y: (i / 2) as u32 * 300,
877 width: 400,
878 height: 300,
879 z_index: i as i32,
880 })
881 .collect();
882
883 Ok(LayoutResult {
884 layout_type: self.layout_type.clone(),
885 chart_positions,
886 total_width: 800,
887 total_height: 600,
888 responsive_applied: Vec::new(),
889 })
890 }
891}
892
893impl ExportEngine {
894 pub fn new() -> Self {
895 Self {
896 export_formats: vec![ExportFormat::PDF, ExportFormat::PNG, ExportFormat::HTML],
897 template_engine: TemplateEngine::new(),
898 format_converters: HashMap::new(),
899 }
900 }
901
902 pub async fn export(
903 &self,
904 content: &ExportContent,
905 options: &ExportOptions,
906 ) -> DeviceResult<Vec<u8>> {
907 Ok(b"Exported content".to_vec())
909 }
910}
911
912impl TemplateEngine {
913 pub fn new() -> Self {
914 Self {
915 templates: HashMap::new(),
916 template_cache: HashMap::new(),
917 variable_resolver: VariableResolver::new(),
918 }
919 }
920}
921
922impl VariableResolver {
923 pub fn new() -> Self {
924 Self {
925 resolvers: HashMap::new(),
926 }
927 }
928}
929
930impl ThemeManager {
931 pub fn new(color_scheme: ColorScheme) -> Self {
932 let theme = Self::create_theme_from_scheme(color_scheme);
933 let mut available_themes = HashMap::new();
934 available_themes.insert(theme.theme_id.clone(), theme.clone());
935
936 Self {
937 current_theme: theme,
938 available_themes,
939 custom_css: HashMap::new(),
940 }
941 }
942
943 pub fn get_current_theme(&self) -> &Theme {
944 &self.current_theme
945 }
946
947 fn create_theme_from_scheme(scheme: ColorScheme) -> Theme {
948 let (primary, background, text) = match scheme {
949 ColorScheme::Dark => (
950 "#BB86FC".to_string(),
951 "#121212".to_string(),
952 "#FFFFFF".to_string(),
953 ),
954 ColorScheme::Light => (
955 "#6200EE".to_string(),
956 "#FFFFFF".to_string(),
957 "#000000".to_string(),
958 ),
959 ColorScheme::Scientific => (
960 "#1976D2".to_string(),
961 "#F5F5F5".to_string(),
962 "#212121".to_string(),
963 ),
964 _ => (
965 "#6200EE".to_string(),
966 "#FFFFFF".to_string(),
967 "#000000".to_string(),
968 ),
969 };
970
971 Theme {
972 theme_id: format!("{:?}", scheme).to_lowercase(),
973 theme_name: format!("{:?} Theme", scheme),
974 color_palette: ColorPalette {
975 primary,
976 secondary: "#03DAC6".to_string(),
977 accent: "#FF5722".to_string(),
978 background,
979 surface: "#FFFFFF".to_string(),
980 text_primary: text,
981 text_secondary: "#757575".to_string(),
982 success: "#4CAF50".to_string(),
983 warning: "#FF9800".to_string(),
984 error: "#F44336".to_string(),
985 info: "#2196F3".to_string(),
986 chart_colors: vec![
987 "#1976D2".to_string(),
988 "#388E3C".to_string(),
989 "#F57C00".to_string(),
990 "#7B1FA2".to_string(),
991 "#D32F2F".to_string(),
992 "#0097A7".to_string(),
993 ],
994 },
995 typography: Typography::default(),
996 spacing: Spacing::default(),
997 borders: BorderStyles::default(),
998 shadows: ShadowStyles::default(),
999 }
1000 }
1001}
1002
1003impl Default for ChartData {
1005 fn default() -> Self {
1006 Self {
1007 data_type: ChartDataType::TimeSeries,
1008 series: Vec::new(),
1009 metadata: ChartMetadata {
1010 title: "Chart".to_string(),
1011 subtitle: None,
1012 x_axis_label: "X".to_string(),
1013 y_axis_label: "Y".to_string(),
1014 data_source: "Dashboard".to_string(),
1015 last_updated: SystemTime::now(),
1016 chart_id: "chart".to_string(),
1017 },
1018 }
1019 }
1020}
1021
1022impl Default for SeriesStyling {
1023 fn default() -> Self {
1024 Self {
1025 color: "#1976D2".to_string(),
1026 line_width: 2.0,
1027 marker_size: 4.0,
1028 opacity: 1.0,
1029 fill_pattern: None,
1030 custom_styles: HashMap::new(),
1031 }
1032 }
1033}
1034
1035impl Default for AxisOptions {
1036 fn default() -> Self {
1037 Self {
1038 show: true,
1039 title: String::new(),
1040 min: None,
1041 max: None,
1042 tick_interval: None,
1043 tick_format: "auto".to_string(),
1044 logarithmic: false,
1045 grid_lines: true,
1046 }
1047 }
1048}
1049
1050impl Default for GridOptions {
1051 fn default() -> Self {
1052 Self {
1053 show: true,
1054 major_lines: true,
1055 minor_lines: false,
1056 line_style: "solid".to_string(),
1057 color: "#E0E0E0".to_string(),
1058 opacity: 0.5,
1059 }
1060 }
1061}
1062
1063impl Default for TooltipOptions {
1064 fn default() -> Self {
1065 Self {
1066 show: true,
1067 format: "auto".to_string(),
1068 background_color: "#333333".to_string(),
1069 border_color: "#666666".to_string(),
1070 follow_mouse: true,
1071 }
1072 }
1073}
1074
1075impl Default for GridConfiguration {
1076 fn default() -> Self {
1077 Self {
1078 columns: 2,
1079 rows: 2,
1080 gap: 16.0,
1081 padding: 16.0,
1082 responsive_breakpoints: vec![
1083 Breakpoint {
1084 width: 768,
1085 columns: 1,
1086 chart_height: 300,
1087 },
1088 Breakpoint {
1089 width: 1024,
1090 columns: 2,
1091 chart_height: 400,
1092 },
1093 ],
1094 }
1095 }
1096}
1097
1098impl Default for Typography {
1099 fn default() -> Self {
1100 Self {
1101 font_family: "Roboto, sans-serif".to_string(),
1102 font_sizes: [
1103 ("small".to_string(), 12),
1104 ("medium".to_string(), 14),
1105 ("large".to_string(), 16),
1106 ("title".to_string(), 20),
1107 ]
1108 .iter()
1109 .cloned()
1110 .collect(),
1111 font_weights: [("normal".to_string(), 400), ("bold".to_string(), 700)]
1112 .iter()
1113 .cloned()
1114 .collect(),
1115 line_heights: [("normal".to_string(), 1.4), ("tight".to_string(), 1.2)]
1116 .iter()
1117 .cloned()
1118 .collect(),
1119 }
1120 }
1121}
1122
1123impl Default for Spacing {
1124 fn default() -> Self {
1125 Self {
1126 base_unit: 8,
1127 small: 4,
1128 medium: 8,
1129 large: 16,
1130 extra_large: 32,
1131 }
1132 }
1133}
1134
1135impl Default for BorderStyles {
1136 fn default() -> Self {
1137 Self {
1138 width: [("thin".to_string(), 1), ("medium".to_string(), 2)]
1139 .iter()
1140 .cloned()
1141 .collect(),
1142 style: [("solid".to_string(), "solid".to_string())]
1143 .iter()
1144 .cloned()
1145 .collect(),
1146 color: [("default".to_string(), "#E0E0E0".to_string())]
1147 .iter()
1148 .cloned()
1149 .collect(),
1150 radius: [("small".to_string(), 4), ("medium".to_string(), 8)]
1151 .iter()
1152 .cloned()
1153 .collect(),
1154 }
1155 }
1156}
1157
1158impl Default for ShadowStyles {
1159 fn default() -> Self {
1160 Self {
1161 box_shadows: [
1162 ("small".to_string(), "0 2px 4px rgba(0,0,0,0.1)".to_string()),
1163 (
1164 "medium".to_string(),
1165 "0 4px 8px rgba(0,0,0,0.1)".to_string(),
1166 ),
1167 ]
1168 .iter()
1169 .cloned()
1170 .collect(),
1171 text_shadows: HashMap::new(),
1172 }
1173 }
1174}