use super::metrics::LABEL_SIZE;
use super::model::Chart;
use super::project::Plot;
use super::scale::{self, Scale};
use crate::layout::PlacedNode;
use crate::layout::prim;
use crate::resolve::ResolvedValue;
fn live(name: &str) -> ResolvedValue {
ResolvedValue::LiveVar {
name: name.into(),
raw: false,
}
}
pub fn gridlines(plot: &Plot, chart: &Chart, out: &mut Vec<PlacedNode>) {
let Scale::Band { n } = chart.x.scale else {
return;
};
if n == 0 {
return;
}
let xs = &chart.x.scale;
let vs = &chart.values[0].scale; let grid = live("grid");
for &t in vs.ticks() {
if vs.frac(t) * plot.radius() < 1.0 {
continue; }
let mut poly: Vec<(f64, f64)> = (0..n).map(|i| plot.project(xs, i as f64, vs, t)).collect();
if let Some(&p0) = poly.first() {
poly.push(p0); }
out.push(prim::line(poly, grid.clone(), 1.0));
}
let (cx, cy) = plot.center();
for i in 0..n {
let a = plot.spoke_angle(xs, i as f64);
let rim = (cx + plot.radius() * a.sin(), cy - plot.radius() * a.cos());
out.push(prim::line(vec![(cx, cy), rim], grid.clone(), 1.0));
}
}
pub fn labels(plot: &Plot, chart: &Chart, out: &mut Vec<PlacedNode>) {
let Scale::Band { n } = chart.x.scale else {
return;
};
let xs = &chart.x.scale;
let vs = &chart.values[0].scale;
let (cx, cy) = plot.center();
let muted = live("muted");
let lr = plot.radius() + LABEL_SIZE * 0.9;
for i in 0..n {
let a = plot.spoke_angle(xs, i as f64);
let label = chart
.x
.labels
.get(i)
.cloned()
.unwrap_or_else(|| (i + 1).to_string());
let lx = cx + lr * a.sin();
let ly = cy - lr * a.cos();
out.push(prim::text(
&label,
lx,
ly,
LABEL_SIZE,
Some(muted.clone()),
false,
chart.font_kind,
));
}
for &t in vs.ticks() {
let r = vs.frac(t) * plot.radius();
if r < 1.0 {
continue; }
let label = scale::label(t, &chart.values[0].unit);
out.push(prim::text_left(
&label,
cx + 3.0,
cy - r,
LABEL_SIZE,
Some(muted.clone()),
chart.font_kind,
));
}
}