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}