Skip to main content

use_svg/
view_box.rs

1#[derive(Debug, Clone, Copy, PartialEq)]
2pub struct SvgViewBox {
3    pub min_x: f64,
4    pub min_y: f64,
5    pub width: f64,
6    pub height: f64,
7}
8
9impl SvgViewBox {
10    #[must_use]
11    pub fn new(min_x: f64, min_y: f64, width: f64, height: f64) -> Self {
12        Self {
13            min_x,
14            min_y,
15            width,
16            height,
17        }
18    }
19}
20
21#[must_use]
22pub fn parse_view_box(input: &str) -> Option<SvgViewBox> {
23    let components: Vec<_> = input
24        .split(|ch: char| ch.is_ascii_whitespace() || ch == ',')
25        .filter(|component| !component.is_empty())
26        .collect();
27
28    if components.len() != 4 {
29        return None;
30    }
31
32    let min_x = components[0].parse::<f64>().ok()?;
33    let min_y = components[1].parse::<f64>().ok()?;
34    let width = components[2].parse::<f64>().ok()?;
35    let height = components[3].parse::<f64>().ok()?;
36
37    if !min_x.is_finite()
38        || !min_y.is_finite()
39        || !width.is_finite()
40        || !height.is_finite()
41        || width < 0.0
42        || height < 0.0
43    {
44        return None;
45    }
46
47    Some(SvgViewBox::new(min_x, min_y, width, height))
48}
49
50#[must_use]
51pub fn format_view_box(view_box: SvgViewBox) -> String {
52    format!(
53        "{} {} {} {}",
54        format_number(view_box.min_x),
55        format_number(view_box.min_y),
56        format_number(view_box.width),
57        format_number(view_box.height)
58    )
59}
60
61pub(crate) fn format_number(value: f64) -> String {
62    if value.abs() < f64::EPSILON {
63        return "0".to_string();
64    }
65
66    let rounded = value.round();
67    if (value - rounded).abs() < 1.0e-12 {
68        return format!("{}", rounded as i64);
69    }
70
71    let mut formatted = value.to_string();
72    if formatted.contains('.') {
73        while formatted.ends_with('0') {
74            formatted.pop();
75        }
76        if formatted.ends_with('.') {
77            formatted.pop();
78        }
79    }
80
81    formatted
82}