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}