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, Eq)]
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, Eq)]
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, Eq)]
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, Eq)]
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, Eq)]
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, Eq)]
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, Eq)]
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, Eq)]
438pub enum PageSize {
439 A4,
440 A3,
441 Letter,
442 Legal,
443 Custom { width: u32, height: u32 },
444}
445
446#[derive(Debug, Clone, PartialEq, Eq)]
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, Eq)]
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),
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_or_default()
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 const 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 const 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 const 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 Default for ExportEngine {
894 fn default() -> Self {
895 Self::new()
896 }
897}
898
899impl ExportEngine {
900 pub fn new() -> Self {
901 Self {
902 export_formats: vec![ExportFormat::PDF, ExportFormat::PNG, ExportFormat::HTML],
903 template_engine: TemplateEngine::new(),
904 format_converters: HashMap::new(),
905 }
906 }
907
908 pub async fn export(
909 &self,
910 content: &ExportContent,
911 options: &ExportOptions,
912 ) -> DeviceResult<Vec<u8>> {
913 Ok(b"Exported content".to_vec())
915 }
916}
917
918impl Default for TemplateEngine {
919 fn default() -> Self {
920 Self::new()
921 }
922}
923
924impl TemplateEngine {
925 pub fn new() -> Self {
926 Self {
927 templates: HashMap::new(),
928 template_cache: HashMap::new(),
929 variable_resolver: VariableResolver::new(),
930 }
931 }
932}
933
934impl Default for VariableResolver {
935 fn default() -> Self {
936 Self::new()
937 }
938}
939
940impl VariableResolver {
941 pub fn new() -> Self {
942 Self {
943 resolvers: HashMap::new(),
944 }
945 }
946}
947
948impl ThemeManager {
949 pub fn new(color_scheme: ColorScheme) -> Self {
950 let theme = Self::create_theme_from_scheme(color_scheme);
951 let mut available_themes = HashMap::new();
952 available_themes.insert(theme.theme_id.clone(), theme.clone());
953
954 Self {
955 current_theme: theme,
956 available_themes,
957 custom_css: HashMap::new(),
958 }
959 }
960
961 pub const fn get_current_theme(&self) -> &Theme {
962 &self.current_theme
963 }
964
965 fn create_theme_from_scheme(scheme: ColorScheme) -> Theme {
966 let (primary, background, text) = match scheme {
967 ColorScheme::Dark => (
968 "#BB86FC".to_string(),
969 "#121212".to_string(),
970 "#FFFFFF".to_string(),
971 ),
972 ColorScheme::Light => (
973 "#6200EE".to_string(),
974 "#FFFFFF".to_string(),
975 "#000000".to_string(),
976 ),
977 ColorScheme::Scientific => (
978 "#1976D2".to_string(),
979 "#F5F5F5".to_string(),
980 "#212121".to_string(),
981 ),
982 _ => (
983 "#6200EE".to_string(),
984 "#FFFFFF".to_string(),
985 "#000000".to_string(),
986 ),
987 };
988
989 Theme {
990 theme_id: format!("{scheme:?}").to_lowercase(),
991 theme_name: format!("{scheme:?} Theme"),
992 color_palette: ColorPalette {
993 primary,
994 secondary: "#03DAC6".to_string(),
995 accent: "#FF5722".to_string(),
996 background,
997 surface: "#FFFFFF".to_string(),
998 text_primary: text,
999 text_secondary: "#757575".to_string(),
1000 success: "#4CAF50".to_string(),
1001 warning: "#FF9800".to_string(),
1002 error: "#F44336".to_string(),
1003 info: "#2196F3".to_string(),
1004 chart_colors: vec![
1005 "#1976D2".to_string(),
1006 "#388E3C".to_string(),
1007 "#F57C00".to_string(),
1008 "#7B1FA2".to_string(),
1009 "#D32F2F".to_string(),
1010 "#0097A7".to_string(),
1011 ],
1012 },
1013 typography: Typography::default(),
1014 spacing: Spacing::default(),
1015 borders: BorderStyles::default(),
1016 shadows: ShadowStyles::default(),
1017 }
1018 }
1019}
1020
1021impl Default for ChartData {
1023 fn default() -> Self {
1024 Self {
1025 data_type: ChartDataType::TimeSeries,
1026 series: Vec::new(),
1027 metadata: ChartMetadata {
1028 title: "Chart".to_string(),
1029 subtitle: None,
1030 x_axis_label: "X".to_string(),
1031 y_axis_label: "Y".to_string(),
1032 data_source: "Dashboard".to_string(),
1033 last_updated: SystemTime::now(),
1034 chart_id: "chart".to_string(),
1035 },
1036 }
1037 }
1038}
1039
1040impl Default for SeriesStyling {
1041 fn default() -> Self {
1042 Self {
1043 color: "#1976D2".to_string(),
1044 line_width: 2.0,
1045 marker_size: 4.0,
1046 opacity: 1.0,
1047 fill_pattern: None,
1048 custom_styles: HashMap::new(),
1049 }
1050 }
1051}
1052
1053impl Default for AxisOptions {
1054 fn default() -> Self {
1055 Self {
1056 show: true,
1057 title: String::new(),
1058 min: None,
1059 max: None,
1060 tick_interval: None,
1061 tick_format: "auto".to_string(),
1062 logarithmic: false,
1063 grid_lines: true,
1064 }
1065 }
1066}
1067
1068impl Default for GridOptions {
1069 fn default() -> Self {
1070 Self {
1071 show: true,
1072 major_lines: true,
1073 minor_lines: false,
1074 line_style: "solid".to_string(),
1075 color: "#E0E0E0".to_string(),
1076 opacity: 0.5,
1077 }
1078 }
1079}
1080
1081impl Default for TooltipOptions {
1082 fn default() -> Self {
1083 Self {
1084 show: true,
1085 format: "auto".to_string(),
1086 background_color: "#333333".to_string(),
1087 border_color: "#666666".to_string(),
1088 follow_mouse: true,
1089 }
1090 }
1091}
1092
1093impl Default for GridConfiguration {
1094 fn default() -> Self {
1095 Self {
1096 columns: 2,
1097 rows: 2,
1098 gap: 16.0,
1099 padding: 16.0,
1100 responsive_breakpoints: vec![
1101 Breakpoint {
1102 width: 768,
1103 columns: 1,
1104 chart_height: 300,
1105 },
1106 Breakpoint {
1107 width: 1024,
1108 columns: 2,
1109 chart_height: 400,
1110 },
1111 ],
1112 }
1113 }
1114}
1115
1116impl Default for Typography {
1117 fn default() -> Self {
1118 Self {
1119 font_family: "Roboto, sans-serif".to_string(),
1120 font_sizes: [
1121 ("small".to_string(), 12),
1122 ("medium".to_string(), 14),
1123 ("large".to_string(), 16),
1124 ("title".to_string(), 20),
1125 ]
1126 .iter()
1127 .cloned()
1128 .collect(),
1129 font_weights: [("normal".to_string(), 400), ("bold".to_string(), 700)]
1130 .iter()
1131 .cloned()
1132 .collect(),
1133 line_heights: [("normal".to_string(), 1.4), ("tight".to_string(), 1.2)]
1134 .iter()
1135 .cloned()
1136 .collect(),
1137 }
1138 }
1139}
1140
1141impl Default for Spacing {
1142 fn default() -> Self {
1143 Self {
1144 base_unit: 8,
1145 small: 4,
1146 medium: 8,
1147 large: 16,
1148 extra_large: 32,
1149 }
1150 }
1151}
1152
1153impl Default for BorderStyles {
1154 fn default() -> Self {
1155 Self {
1156 width: [("thin".to_string(), 1), ("medium".to_string(), 2)]
1157 .iter()
1158 .cloned()
1159 .collect(),
1160 style: [("solid".to_string(), "solid".to_string())]
1161 .iter()
1162 .cloned()
1163 .collect(),
1164 color: [("default".to_string(), "#E0E0E0".to_string())]
1165 .iter()
1166 .cloned()
1167 .collect(),
1168 radius: [("small".to_string(), 4), ("medium".to_string(), 8)]
1169 .iter()
1170 .cloned()
1171 .collect(),
1172 }
1173 }
1174}
1175
1176impl Default for ShadowStyles {
1177 fn default() -> Self {
1178 Self {
1179 box_shadows: [
1180 ("small".to_string(), "0 2px 4px rgba(0,0,0,0.1)".to_string()),
1181 (
1182 "medium".to_string(),
1183 "0 4px 8px rgba(0,0,0,0.1)".to_string(),
1184 ),
1185 ]
1186 .iter()
1187 .cloned()
1188 .collect(),
1189 text_shadows: HashMap::new(),
1190 }
1191 }
1192}