Skip to main content

esoc_chart/grammar/
annotation.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! Chart annotations: reference lines, bands, text labels.
3
4use esoc_color::Color;
5
6/// An annotation overlaid on the plot area.
7#[derive(Clone, Debug)]
8pub enum Annotation {
9    /// Horizontal reference line at a given y value.
10    HLine {
11        /// Y data value.
12        y: f64,
13        /// Line color.
14        color: Color,
15        /// Line width.
16        width: f32,
17        /// Dash pattern (None = solid).
18        dash: Option<Vec<f32>>,
19        /// Optional label.
20        label: Option<String>,
21    },
22    /// Vertical reference line at a given x value.
23    VLine {
24        /// X data value.
25        x: f64,
26        /// Line color.
27        color: Color,
28        /// Line width.
29        width: f32,
30        /// Dash pattern (None = solid).
31        dash: Option<Vec<f32>>,
32        /// Optional label.
33        label: Option<String>,
34    },
35    /// Horizontal band between y_min and y_max.
36    Band {
37        /// Lower y value.
38        y_min: f64,
39        /// Upper y value.
40        y_max: f64,
41        /// Fill color (typically semi-transparent).
42        color: Color,
43        /// Optional label.
44        label: Option<String>,
45    },
46    /// Free-form text annotation.
47    Text {
48        /// X data value.
49        x: f64,
50        /// Y data value.
51        y: f64,
52        /// Text content.
53        text: String,
54        /// Text color.
55        color: Color,
56        /// Font size.
57        font_size: f32,
58    },
59}
60
61/// Convenience constructors.
62impl Annotation {
63    /// Create a horizontal reference line.
64    pub fn hline(y: f64) -> Self {
65        Self::HLine {
66            y,
67            color: Color::new(0.5, 0.5, 0.5, 1.0),
68            width: 1.0,
69            dash: Some(vec![4.0, 4.0]),
70            label: None,
71        }
72    }
73
74    /// Create a vertical reference line.
75    pub fn vline(x: f64) -> Self {
76        Self::VLine {
77            x,
78            color: Color::new(0.5, 0.5, 0.5, 1.0),
79            width: 1.0,
80            dash: Some(vec![4.0, 4.0]),
81            label: None,
82        }
83    }
84
85    /// Create a horizontal band.
86    pub fn band(y_min: f64, y_max: f64) -> Self {
87        Self::Band {
88            y_min,
89            y_max,
90            color: Color::new(0.5, 0.5, 0.5, 0.15),
91            label: None,
92        }
93    }
94
95    /// Create a text annotation.
96    pub fn text(x: f64, y: f64, text: impl Into<String>) -> Self {
97        Self::Text {
98            x,
99            y,
100            text: text.into(),
101            color: Color::BLACK,
102            font_size: 11.0,
103        }
104    }
105
106    /// Set the color of this annotation.
107    pub fn with_color(mut self, color: Color) -> Self {
108        match &mut self {
109            Self::HLine { color: c, .. }
110            | Self::VLine { color: c, .. }
111            | Self::Band { color: c, .. }
112            | Self::Text { color: c, .. } => *c = color,
113        }
114        self
115    }
116
117    /// Set the label for reference lines.
118    pub fn with_label(mut self, label: impl Into<String>) -> Self {
119        match &mut self {
120            Self::HLine { label: l, .. }
121            | Self::VLine { label: l, .. }
122            | Self::Band { label: l, .. } => {
123                *l = Some(label.into());
124            }
125            Self::Text { .. } => {}
126        }
127        self
128    }
129}