use super::*;
pub(super) fn legend_reserve(entries: usize, gap: f64) -> f64 {
if entries >= 2 {
LABEL_SIZE * 0.7 + gap
} else {
0.0
}
}
pub(super) type LegendEntry = (String, ResolvedValue, Option<ResolvedValue>);
pub(super) fn legend_entries(chart: &Chart) -> Vec<LegendEntry> {
chart
.series
.iter()
.filter_map(|s| {
s.label
.clone()
.map(|l| (l, s.color.clone(), swatch_edge(s)))
})
.collect()
}
fn swatch_edge(s: &Series) -> Option<ResolvedValue> {
let explicit = s.outline.as_ref().map(|(c, _)| c.clone());
match s.kind {
SeriesKind::Area => Some(explicit.unwrap_or_else(|| palette::deepen(&s.color))),
_ => explicit,
}
}
pub(super) fn lay_out_legend(
entries: &[LegendEntry],
cy: f64,
kind: crate::font::Kind,
out: &mut Vec<PlacedNode>,
) {
const SW: f64 = 11.0; const GAP: f64 = 5.0; const ITEM_GAP: f64 = 16.0; let widths: Vec<f64> = entries
.iter()
.map(|(l, _, _)| prim::text_width(l, LABEL_SIZE, crate::font::Font::bold(kind)))
.collect();
let per: f64 = widths.iter().map(|w| SW + GAP + w).sum();
let total = per + ITEM_GAP * widths.len().saturating_sub(1) as f64;
let mut x = -total / 2.0;
for ((label, fill, edge), &tw) in entries.iter().zip(&widths) {
let mut swatch = prim::rect(x + SW / 2.0, cy, SW, SW, fill.clone(), 1.0);
prim::round(&mut swatch, 2.0); if let Some(edge) = edge {
prim::outline(&mut swatch, edge.clone(), 1.0); }
out.push(swatch);
out.push(prim::text(
label,
x + SW + GAP + tw / 2.0,
cy,
LABEL_SIZE,
None,
true,
kind,
));
x += SW + GAP + tw + ITEM_GAP;
}
}