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
This commit is contained in:
autocraft-bot[bot]
2026-11-11 13:47:42 +00:00
parent a55457ee53
commit 6df9331b52
2 changed files with 29 additions and 7 deletions
+9 -7
View File
@@ -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 `<c:dPt>` 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));
@@ -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");
}