Skip to main content

scirs2_cluster/native_plotting/
svg.rs

1//! SVG rendering primitives — canvas, elements, animation engine, and interactive controller.
2
3use super::types::{AnimationEngine, InteractiveController, SvgCanvas, SvgElement};
4use std::collections::HashMap;
5
6impl SvgCanvas {
7    pub fn new(width: usize, height: usize) -> Self {
8        Self {
9            width,
10            height,
11            elements: Vec::new(),
12            styles: HashMap::new(),
13        }
14    }
15
16    pub fn clear(&mut self) {
17        self.elements.clear();
18    }
19
20    pub fn add_element(&mut self, element: SvgElement) {
21        self.elements.push(element);
22    }
23
24    pub fn to_svg(&self) -> String {
25        let mut svg = format!(
26            r#"<svg width="{}" height="{}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">"#,
27            self.width, self.height
28        );
29
30        // Add styles
31        svg.push_str("<defs><style>");
32        for (selector, style) in &self.styles {
33            svg.push_str(&format!("{} {{ {} }}", selector, style));
34        }
35        svg.push_str("</style></defs>");
36
37        // Add main group
38        svg.push_str(r#"<g class="main-group">"#);
39
40        // Add elements
41        for element in &self.elements {
42            svg.push_str(&element.to_svg());
43        }
44
45        svg.push_str("</g></svg>");
46        svg
47    }
48}
49
50impl SvgElement {
51    pub fn to_svg(&self) -> String {
52        match self {
53            SvgElement::Circle {
54                cx,
55                cy,
56                r,
57                fill,
58                stroke,
59                stroke_width,
60                opacity,
61            } => {
62                format!(
63                    r#"<circle cx="{}" cy="{}" r="{}" fill="{}" stroke="{}" stroke-width="{}" opacity="{}" />"#,
64                    cx, cy, r, fill, stroke, stroke_width, opacity
65                )
66            }
67            SvgElement::Line {
68                x1,
69                y1,
70                x2,
71                y2,
72                stroke,
73                stroke_width,
74                opacity,
75            } => {
76                format!(
77                    r#"<line x1="{}" y1="{}" x2="{}" y2="{}" stroke="{}" stroke-width="{}" opacity="{}" />"#,
78                    x1, y1, x2, y2, stroke, stroke_width, opacity
79                )
80            }
81            SvgElement::Path {
82                d,
83                fill,
84                stroke,
85                stroke_width,
86                opacity,
87            } => {
88                format!(
89                    r#"<path d="{}" fill="{}" stroke="{}" stroke-width="{}" opacity="{}" />"#,
90                    d, fill, stroke, stroke_width, opacity
91                )
92            }
93            SvgElement::Text {
94                x,
95                y,
96                content,
97                font_size,
98                fill,
99                text_anchor,
100            } => {
101                format!(
102                    r#"<text x="{}" y="{}" font-size="{}" fill="{}" text-anchor="{}">{}</text>"#,
103                    x, y, font_size, fill, text_anchor, content
104                )
105            }
106            SvgElement::Group {
107                id,
108                elements,
109                transform,
110            } => {
111                let mut group = format!(r#"<g id="{}" transform="{}">"#, id, transform);
112                for element in elements {
113                    group.push_str(&element.to_svg());
114                }
115                group.push_str("</g>");
116                group
117            }
118        }
119    }
120}
121
122impl AnimationEngine {
123    pub fn new(fps: f64) -> Self {
124        Self {
125            frames: Vec::new(),
126            current_frame: 0,
127            frame_duration: 1000.0 / fps,
128            total_duration: 0.0,
129        }
130    }
131}
132
133impl InteractiveController {
134    pub fn new() -> Self {
135        Self {
136            zoom_level: 1.0,
137            pan_offset: (0.0, 0.0),
138            selected_elements: Vec::new(),
139            hover_element: None,
140        }
141    }
142}