mod annot;
mod axis;
mod bars;
mod bubble;
mod frame;
mod labels;
mod legend;
mod marks;
pub(crate) mod metrics;
mod model;
mod palette;
mod pie;
use super::prim;
mod project;
mod radial;
mod scale;
mod tooltip;
pub(super) use pie::{is_pie, layout_pie};
use crate::error::Error;
use crate::layout::{Bbox, PlacedNode};
use crate::resolve::{AttrMap, ResolvedInst, ResolvedValue};
use metrics::{AXIS_TITLE_SIZE, LABEL_SIZE, TITLE_SIZE};
use model::{Chart, Series, SeriesKind, Side};
use project::{Dir, Plot};
use frame::{plot_rect, title_reserve};
use legend::{LegendEntry, lay_out_legend, legend_entries, legend_reserve};
pub(super) fn is_chart(attrs: &AttrMap) -> bool {
matches!(attrs.get("layout"), Some(ResolvedValue::Ident(s)) if s == "chart")
}
pub(super) fn layout_chart(
inst: &ResolvedInst,
funcs: &crate::expr::FuncTable,
) -> Result<PlacedNode, Error> {
let chart = model::build(inst, funcs)?;
let square = chart.dir == Dir::Radial;
let w = inst
.attrs
.number("width")
.unwrap_or(if square { 280.0 } else { 360.0 });
let h = inst
.attrs
.number("height")
.unwrap_or(if square { 280.0 } else { 220.0 });
let plot = plot_rect(&chart, w, h);
let mut kids = Vec::new();
let mut reqs = Vec::new();
match plot.dir {
Dir::Radial => radial::gridlines(&plot, &chart, &mut kids),
Dir::Column | Dir::Row => {
annot::band_shades(&plot, &chart, &mut kids);
axis::gridlines(&plot, &chart, &mut kids);
}
}
marks::areas(&plot, &chart, &mut kids);
bars::lay_out(&plot, &chart, &mut kids);
marks::lines(&plot, &chart, &mut kids);
marks::dots(&plot, &chart, &mut kids);
bubble::lay_out(&plot, &chart, &mut kids, &mut reqs);
match plot.dir {
Dir::Radial => radial::labels(&plot, &chart, &mut kids),
Dir::Column | Dir::Row => {
annot::marks(&plot, &chart, &mut kids, &mut reqs);
axis::labels(&plot, &chart, &mut kids);
annot::band_ticks(&plot, &chart, &mut kids);
}
}
if let Some(t) = &chart.title {
kids.push(prim::text_classed(
t,
0.0,
-h / 2.0 + 8.0 + TITLE_SIZE * 0.7,
TITLE_SIZE,
"chart-title",
crate::font::Font::semibold(chart.font_kind),
));
}
let legend = legend_entries(&chart);
if legend.len() >= 2 {
lay_out_legend(
&legend,
h / 2.0 - LABEL_SIZE * 0.9,
chart.font_kind,
&mut kids,
);
}
labels::collect_series(&plot, &chart, &mut reqs);
let lines = labels::series_lines(&plot, &chart);
kids.extend(labels::place(&reqs, &plot, &lines, chart.font_kind));
let kids = tooltip::apply(kids, chart.tooltip, w, h, chart.font_kind);
Ok(chart_box(inst, w, h, kids))
}
pub(super) fn chart_box(inst: &ResolvedInst, w: f64, h: f64, kids: Vec<PlacedNode>) -> PlacedNode {
prim::container(inst, Bbox::centered(w, h), kids)
}
#[cfg(test)]
mod tests;