domrs/svg/document.rs
1use crate::common::ToText;
2use crate::svg::{DEFAULT_SVG_INDENT, DEFAULT_SVG_OFFSET};
3use crate::{HtmlElement, SvgNumber};
4use std::fmt;
5use std::fmt::Display;
6
7/// Default namespace for SVG document.
8pub const DEFAULT_SVG_NAMESPACE: &str = "http://www.w3.org/2000/svg";
9
10/// A structure representing the outermost [`svg`] element of SVG document.
11///
12/// [`svg`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
13#[derive(Debug, Default, Clone)]
14pub struct SvgDocument {
15 /// CSS document's [`namespace`].
16 ///
17 /// [`namespace`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course
18 namespace: Option<String>,
19 /// The [`position and dimension`], in user space, of an SVG viewport.
20 ///
21 /// [`position and dimension`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
22 view_box: Option<(SvgNumber, SvgNumber, SvgNumber, SvgNumber)>,
23 /// The displayed [`width`] of the rectangular viewport (not the width of its coordinate system).
24 ///
25 /// [`width`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width
26 width: Option<SvgNumber>,
27 /// The displayed [`height`] of the rectangular viewport (not the height of its coordinate system).
28 ///
29 /// [`height`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height
30 height: Option<SvgNumber>,
31}
32
33impl SvgDocument {
34 /// Creates an empty SVG document.
35 ///
36 /// # Example
37 ///
38 /// ```
39 /// use domrs::SvgDocument;
40 ///
41 /// assert_eq!("<svg/>", SvgDocument::new().to_string());
42 /// ```
43 pub fn new() -> Self {
44 Self::default()
45 }
46
47 /// Sets the default SVG [`namespace`].
48 ///
49 /// [`namespace`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course
50 pub fn default_namespace(mut self) -> Self {
51 self.set_default_namespace();
52 self
53 }
54
55 /// Sets the default SVG [`namespace`].
56 ///
57 /// [`namespace`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course
58 pub fn set_default_namespace(&mut self) {
59 self.namespace = DEFAULT_SVG_NAMESPACE.to_string().into();
60 }
61
62 /// Sets custom SVG [`namespace`].
63 ///
64 /// [`namespace`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course
65 pub fn namespace<T: ToString>(mut self, namespace: T) -> Self {
66 self.set_namespace(namespace);
67 self
68 }
69
70 /// Sets custom SVG [`namespace`].
71 ///
72 /// [`namespace`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course
73 pub fn set_namespace<T: ToString>(&mut self, namespace: T) {
74 self.namespace = namespace.to_string().into();
75 }
76
77 /// Sets the [`position and dimension`], in user space, of an SVG viewport.
78 ///
79 /// [`position and dimension`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
80 pub fn view_box<T: Into<SvgNumber>>(mut self, min_x: T, min_y: T, width: T, height: T) -> Self {
81 self.set_view_box(min_x, min_y, width, height);
82 self
83 }
84
85 /// Sets the [`position and dimension`], in user space, of an SVG viewport.
86 ///
87 /// [`position and dimension`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
88 pub fn set_view_box<T: Into<SvgNumber>>(&mut self, min_x: T, min_y: T, width: T, height: T) {
89 self.view_box = Some((min_x.into(), min_y.into(), width.into(), height.into()));
90 }
91
92 /// Sets the displayed [`width`] attribute.
93 ///
94 /// [`width`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width
95 pub fn width<T: Into<SvgNumber>>(mut self, width: T) -> Self {
96 self.set_width(width);
97 self
98 }
99
100 /// Sets the displayed [`width`] attribute.
101 ///
102 /// [`width`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width
103 pub fn set_width<T: Into<SvgNumber>>(&mut self, width: T) {
104 self.width = Some(width.into());
105 }
106
107 /// Sets the displayed [`height`] attribute.
108 ///
109 /// [`height`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height
110 pub fn height<T: Into<SvgNumber>>(mut self, height: T) -> Self {
111 self.set_height(height);
112 self
113 }
114
115 /// Sets the displayed [`height`] attribute.
116 ///
117 /// [`height`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height
118 pub fn set_height<T: Into<SvgNumber>>(&mut self, height: T) {
119 self.height = Some(height.into());
120 }
121}
122
123impl ToText for SvgDocument {
124 /// Converts [SvgDocument] to a textual representation with provided offset and indent.
125 fn to_text(&self, offset: usize, indent: usize) -> String {
126 let svg: HtmlElement = (*self).clone().into();
127 svg.to_text(offset, indent)
128 }
129}
130
131impl Display for SvgDocument {
132 /// Implements [Display] for [SvgDocument].
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 write!(f, "{}", self.to_text(DEFAULT_SVG_OFFSET, DEFAULT_SVG_INDENT))
135 }
136}
137
138impl From<SvgDocument> for HtmlElement {
139 /// Creates [HtmlElement] from [SvgDocument].
140 fn from(value: SvgDocument) -> Self {
141 let mut svg = HtmlElement::new("svg");
142 if let Some(width) = value.width {
143 svg.set_attribute("width", width.to_string());
144 }
145 if let Some(height) = value.height {
146 svg.set_attribute("height", height.to_string());
147 }
148 if let Some(namespace) = value.namespace {
149 svg.set_attribute("xmlns", namespace);
150 }
151 if let Some((min_x, min_y, width, height)) = value.view_box {
152 svg.set_attribute("viewBox", format!("{} {} {} {}", min_x, min_y, width, height));
153 }
154 svg
155 }
156}