Skip to main content

esoc_chart/
series.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! Series trait and data bounds for chart rendering.
3
4use esoc_gfx::canvas::Canvas;
5use esoc_gfx::transform::CoordinateTransform;
6
7use crate::theme::Theme;
8
9/// Axis-aligned bounding box for data in a series.
10#[derive(Clone, Copy, Debug)]
11pub struct DataBounds {
12    /// Minimum X value.
13    pub x_min: f64,
14    /// Maximum X value.
15    pub x_max: f64,
16    /// Minimum Y value.
17    pub y_min: f64,
18    /// Maximum Y value.
19    pub y_max: f64,
20}
21
22impl DataBounds {
23    /// Create new data bounds.
24    pub fn new(x_min: f64, x_max: f64, y_min: f64, y_max: f64) -> Self {
25        Self {
26            x_min,
27            x_max,
28            y_min,
29            y_max,
30        }
31    }
32
33    /// Merge with another bounds, taking the union.
34    pub fn union(self, other: Self) -> Self {
35        Self {
36            x_min: self.x_min.min(other.x_min),
37            x_max: self.x_max.max(other.x_max),
38            y_min: self.y_min.min(other.y_min),
39            y_max: self.y_max.max(other.y_max),
40        }
41    }
42
43    /// Add padding as a fraction of the range.
44    pub fn pad(self, fraction: f64) -> Self {
45        let x_pad = (self.x_max - self.x_min) * fraction;
46        let y_pad = (self.y_max - self.y_min) * fraction;
47        Self {
48            x_min: self.x_min - x_pad,
49            x_max: self.x_max + x_pad,
50            y_min: self.y_min - y_pad,
51            y_max: self.y_max + y_pad,
52        }
53    }
54}
55
56/// Trait implemented by all chart series types.
57pub trait SeriesRenderer {
58    /// Compute the data bounds for this series.
59    fn data_bounds(&self) -> DataBounds;
60
61    /// Render this series onto a canvas using the given coordinate transform.
62    fn render(
63        &self,
64        canvas: &mut Canvas,
65        transform: &CoordinateTransform,
66        theme: &Theme,
67        series_index: usize,
68    );
69
70    /// Optional label for the legend.
71    fn label(&self) -> Option<&str>;
72}