Skip to main content

svgplot/
common_attributes.rs

1use std::io::Write;
2
3use crate::escape::escape_xml;
4
5/// Common attributes to all SVG elements.
6///
7/// <https://oreillymedia.github.io/Using_SVG/guide/markup.html#common-attributes/>
8#[derive(Default)]
9pub struct CommonAttributes {
10    pub(crate) style: Option<String>,
11    pub(crate) classes: Vec<String>,
12    pub(crate) transform: Option<SvgTransform>,
13    pub(crate) fill: Option<SvgColor>,
14    pub(crate) stroke_linecap: Option<SvgStrokeLinecap>,
15    pub(crate) title: Option<String>,
16}
17
18impl CommonAttributes {
19    pub(crate) const fn new() -> Self {
20        Self {
21            style: None,
22            classes: Vec::new(),
23            transform: None,
24            fill: None,
25            stroke_linecap: None,
26            title: None,
27        }
28    }
29    pub(crate) fn write<W: Write>(&self, writer: &mut W) {
30        #![allow(clippy::unwrap_used)]
31        if let Some(style) = &self.style {
32            writer
33                .write_all(format!(" style=\"{}\"", escape_xml(style)).as_bytes())
34                .unwrap();
35        }
36        if let Some(fill) = &self.fill {
37            fill.write_fill(writer);
38        }
39        if let Some(transform) = &self.transform {
40            transform.write(writer);
41        }
42        if let Some(stroke_linecap) = &self.stroke_linecap {
43            stroke_linecap.write(writer);
44        }
45        if !self.classes.is_empty() {
46            writer.write_all(b" class=\"").unwrap();
47            for (idx, class) in self.classes.iter().enumerate() {
48                writer
49                    .write_all(format!("{}{}", if idx == 0 { "" } else { " " }, class).as_bytes())
50                    .unwrap();
51            }
52            writer.write_all(b"\"").unwrap();
53        }
54    }
55}
56
57macro_rules! implement_common_attributes {
58    ($element_name:ident) => {
59        impl $element_name {
60            pub fn style<S: ToString>(mut self, style: S) -> Self {
61                self.common_attributes.style = Some(style.to_string());
62                self
63            }
64            pub fn class<S: ToString>(mut self, class: S) -> Self {
65                self.common_attributes.classes.push(class.to_string());
66                self
67            }
68            pub const fn transform(mut self, transform: SvgTransform) -> Self {
69                self.common_attributes.transform = Some(transform);
70                self
71            }
72            pub const fn fill(mut self, color: SvgColor) -> Self {
73                self.common_attributes.fill = Some(color);
74                self
75            }
76            pub const fn stroke_linecap(mut self, stroke_linecap: SvgStrokeLinecap) -> Self {
77                self.common_attributes.stroke_linecap = Some(stroke_linecap);
78                self
79            }
80
81            #[allow(clippy::missing_const_for_fn)]
82            pub fn title(mut self, title: String) -> Self {
83                self.common_attributes.title = Some(title);
84                self
85            }
86        }
87    };
88}
89
90use crate::{SvgColor, SvgStrokeLinecap, SvgTransform};
91pub(crate) use implement_common_attributes;