From 6df9331b52ee04e9d09a5d3467e85a2e686099ed Mon Sep 17 00:00:00 2001 From: "autocraft-bot[bot]" <354215646+autocraft-bot[bot]@users.noreply.github.com> Date: Wed, 11 Nov 2026 13:47:42 +0000 Subject: [PATCH] Fix chart legend ignores per-point colours (c:dPt) on pie charts Fixes #2028. - crates/render/src/chart.rs - crates/render/tests/autocraft_regression_2028.rs --- crates/render/src/chart.rs | 16 ++++++++------- .../render/tests/autocraft_regression_2028.rs | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 crates/render/tests/autocraft_regression_2028.rs diff --git a/crates/render/src/chart.rs b/crates/render/src/chart.rs index 53794987a..56a390dd1 100644 --- a/crates/render/src/chart.rs +++ b/crates/render/src/chart.rs @@ -97,6 +97,13 @@ fn bar_paint(ctx: &Ctx, c: &Chart, si: usize, pi: usize, s: &deckcraft_model::ch paint_of(ctx, s.fill.as_ref(), series_color(ctx, c, si)) } +/// Colour of pie slice `i`: its `` solid fill, else the palette's. Slices and legend keys share it. +fn pie_slice_color(ctx: &Ctx, c: &Chart, s: Option<&deckcraft_model::chart::Series>, i: usize) -> Rgba { + s.and_then(|s| s.point_fills.iter().find(|(k, _)| *k == i)) + .and_then(|(_, f)| if let Fill::Solid { color: cc } = f { Some(ctx.color(cc, None)) } else { None }) + .unwrap_or_else(|| series_color(ctx, c, i)) +} + fn polyline(pts: &[Point]) -> BezPath { let mut p = BezPath::new(); for (k, q) in pts.iter().enumerate() { @@ -583,7 +590,7 @@ fn build_legend_items(rctx: &Ctx, c: &Chart, pie: bool, waterfall: bool) -> Vec< // A map draws its own colour scale. vec![] } else if pie { - c.categories.iter().enumerate().map(|(i, n)| (n.clone(), Paint::Color(series_color(rctx, c, i)), None)).collect() + c.categories.iter().enumerate().map(|(i, n)| (n.clone(), Paint::Color(pie_slice_color(rctx, c, c.series.first(), i)), None)).collect() } else { c.series .iter() @@ -1128,12 +1135,7 @@ fn draw_pie(ctx: &mut RenderContext, rctx: &Ctx, c: &Chart, m: Affine, area: Rec p.extend(arc.append_iter(0.1)); p.close_path(); ctx.set_transform(m); - let col = s - .point_fills - .iter() - .find(|(k, _)| *k == i) - .and_then(|(_, f)| if let Fill::Solid { color: cc } = f { Some(rctx.color(cc, None)) } else { None }) - .unwrap_or_else(|| series_color(rctx, c, i)); + let col = pie_slice_color(rctx, c, Some(s), i); ctx.set_paint(color(col, 1.0)); ctx.fill_path(&p); ctx.set_paint(color(Rgba::WHITE, 1.0)); diff --git a/crates/render/tests/autocraft_regression_2028.rs b/crates/render/tests/autocraft_regression_2028.rs new file mode 100644 index 000000000..966c7c029 --- /dev/null +++ b/crates/render/tests/autocraft_regression_2028.rs @@ -0,0 +1,20 @@ +use deckcraft_color::Rgba; +use deckcraft_model::chart::ChartType; +use deckcraft_model::style::{ColorRef, Fill}; +use deckcraft_model::{Chart, Presentation, Shape, ShapeId, ShapeKind, Xfrm}; +use deckcraft_render::{RenderOpts, render_slide}; + +#[test] +fn pie_legend_keys_take_the_point_colours() { + let mut c = Chart::sample(ChartType::Pie); + c.title = None; + c.legend = Some("r".into()); + c.series[0].point_fills = vec![(0, Fill::solid(ColorRef::rgb(Rgba::rgb(255, 0, 255))))]; + let sh = Shape { id: ShapeId(2028), xfrm: Some(Xfrm::new(0.0, 0.0, 960.0, 540.0)), kind: ShapeKind::Chart(Box::new(c)), ..Default::default() }; + let mut p = Presentation::default(); + std::sync::Arc::make_mut(&mut p.slides[0]).shapes = vec![sh]; + let img = render_slide(&p, 0, &RenderOpts { scale: 1.0, ..Default::default() }); + // The pie stays well left of x = 850; only the legend column lies beyond it. + let key = (850..img.width).flat_map(|x| (0..img.height).map(move |y| (x, y))).filter(|(x, y)| img.pixel(*x, *y)[..3] == [255, 0, 255]).count(); + assert!(key > 20, "the legend key of the overridden slice is drawn in its colour: {key} px"); +}