use crate::{
layout::{GridLayoutInfo, LayoutOutput},
model::ChartModel,
visual::Color,
};
#[derive(Debug, Clone)]
pub struct SeriesComponentBase {
pub series_index: usize,
pub grid_index: usize,
}
impl SeriesComponentBase {
pub fn new(series_index: usize, grid_index: usize) -> Self {
Self {
series_index,
grid_index,
}
}
pub fn get_grid_info<'a>(&self, layout: &'a LayoutOutput) -> Option<&'a GridLayoutInfo> {
layout
.grids
.iter()
.find(|g| g.grid_index == self.grid_index)
}
pub fn get_series_color(&self, resolved: &ChartModel, item_color: Option<Color>) -> Color {
item_color.unwrap_or_else(|| {
resolved
.colors
.get(self.series_index % resolved.colors.len())
.copied()
.unwrap_or_else(|| Color::new(0, 0, 0))
})
}
pub fn get_series_color_with_opacity(
&self,
resolved: &ChartModel,
item_color: Option<Color>,
opacity: f64,
) -> Color {
let mut color = self.get_series_color(resolved, item_color);
color.a = (color.a as f64 * opacity).clamp(0.0, 255.0) as u8;
color
}
pub fn create_border_stroke(
&self,
border_color: Option<Color>,
border_width: f64,
_fill_color: Color,
) -> Option<crate::visual::Stroke> {
border_color.map(|c| crate::visual::Stroke {
color: c,
width: border_width,
})
}
}
pub trait SeriesComponentExt {
fn base(&self) -> &SeriesComponentBase;
fn is_empty(&self) -> bool;
fn grid_index(&self) -> usize {
self.base().grid_index
}
fn series_index(&self) -> usize {
self.base().series_index
}
fn get_grid_info<'a>(&self, layout: &'a LayoutOutput) -> Option<&'a GridLayoutInfo> {
self.base().get_grid_info(layout)
}
fn get_color(&self, resolved: &ChartModel, item_color: Option<Color>) -> Color {
self.base().get_series_color(resolved, item_color)
}
}