use crate::engine::{resolve_color, resolve_series_color, BarGeometry};
use crate::{AxisDef, ColorScaleKind, OrbitalChartPalette, SeriesDef};
pub fn resolve_mark_color(
series_index: usize,
series: &SeriesDef,
palette: &OrbitalChartPalette,
category: Option<&str>,
value: Option<f64>,
category_axis: Option<&AxisDef>,
value_axis: Option<&AxisDef>,
) -> String {
if let Some(color) = &series.color {
return color.clone();
}
if let (Some(cat), Some(axis)) = (category, category_axis) {
if let Some(scale) = axis.color_scale.as_ref() {
if scale.kind == ColorScaleKind::Ordinal {
if let Some(idx) = axis
.data
.as_ref()
.and_then(|data| data.iter().position(|c| c == cat))
{
if let Some(color) = scale.colors.get(idx) {
return color.clone();
}
}
}
}
}
if let (Some(v), Some(axis)) = (value, value_axis) {
if let Some(scale) = axis.color_scale.as_ref() {
let domain = value_domain(axis, v);
return resolve_color(v, scale, domain);
}
}
resolve_series_color(series_index, series, palette)
}
pub fn resolve_bar_color(
bar: &BarGeometry,
series_index: usize,
series: &SeriesDef,
palette: &OrbitalChartPalette,
categories: &[String],
category_axis: Option<&AxisDef>,
value_axis: Option<&AxisDef>,
) -> String {
let category = categories.get(bar.data_index).map(String::as_str);
resolve_mark_color(
series_index,
series,
palette,
category,
Some(bar.value),
category_axis,
value_axis,
)
}
fn value_domain(axis: &AxisDef, value: f64) -> (f64, f64) {
if let Some(thresholds) = axis
.color_scale
.as_ref()
.and_then(|s| s.thresholds.as_ref())
{
if let (Some(min), Some(max)) = (thresholds.first(), thresholds.last()) {
return (*min, *max);
}
}
let pad = value.abs().max(1.0) * 0.1;
(value - pad, value + pad)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{ColorScale, ColorScaleKind};
#[test]
fn explicit_series_color_wins() {
let series = SeriesDef {
id: "a".into(),
color: Some("#abc".into()),
..Default::default()
};
let color = resolve_mark_color(
0,
&series,
&OrbitalChartPalette::default(),
None,
None,
None,
None,
);
assert_eq!(color, "#abc");
}
#[test]
fn ordinal_axis_color_maps_category() {
let axis = AxisDef {
id: "x".into(),
data: Some(vec!["A".into(), "B".into()]),
color_scale: Some(ColorScale {
kind: ColorScaleKind::Ordinal,
colors: vec!["#111".into(), "#222".into()],
thresholds: None,
}),
..Default::default()
};
let series = SeriesDef {
id: "a".into(),
..Default::default()
};
let color = resolve_mark_color(
0,
&series,
&OrbitalChartPalette::default(),
Some("B"),
None,
Some(&axis),
None,
);
assert_eq!(color, "#222");
}
}