mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-25 11:16:49 -06:00
Merge pull request #613 from MarekSpodBiedry:issue-545
This commit is contained in:
@@ -970,6 +970,8 @@ fn cartesian(ctx: &mut Ctx, chart: &Chart, data: &ChartData, area: Bx, horizonta
|
||||
let nslots = slot_keys.len().max(1) as f32;
|
||||
let bw = cw / (nslots + 1.5);
|
||||
let labels_on = chart.data_labels && ncat <= MAX_LABELS;
|
||||
// Area labels wait until every area is filled, so a later (stacked) area can't paint over them.
|
||||
let mut area_labels = Vec::new();
|
||||
|
||||
// Areas first, then columns, then lines on top.
|
||||
for pass in 0..3 {
|
||||
@@ -998,6 +1000,10 @@ fn cartesian(ctx: &mut Ctx, chart: &Chart, data: &ChartData, area: Bx, horizonta
|
||||
let c = center(j);
|
||||
top.push([c, vpos(t, &sc)]);
|
||||
base.push([c, vpos(b, &sc)]);
|
||||
// Source values (not stack totals), just above the top edge like the line labels.
|
||||
if labels_on && sp.is_some() && let Some(v) = s.values.get(j).copied().flatten() {
|
||||
area_labels.push((c, vpos(t, &sc) - 5.0, fmt.format(v, None)));
|
||||
}
|
||||
}
|
||||
if top.len() == 1 {
|
||||
// A single point: give it some width.
|
||||
@@ -1072,6 +1078,9 @@ fn cartesian(ctx: &mut Ctx, chart: &Chart, data: &ChartData, area: Bx, horizonta
|
||||
}
|
||||
}
|
||||
}
|
||||
for (x, y, t) in area_labels.drain(..) {
|
||||
ctx.text(x, y, &t, LABEL_SIZE, TEXT, HAlign::Center, VAlign::Bottom);
|
||||
}
|
||||
}
|
||||
// Trendlines on top: x is the category number 1..n.
|
||||
let mut trend_labels = Vec::new();
|
||||
|
||||
@@ -924,3 +924,29 @@ fn union_series_references() {
|
||||
c.series[0].values = format!("{}Sheet1!$B$1,Sheet1!$B$2{}", "(".repeat(5000), ")".repeat(5000));
|
||||
let _ = resolve(&wb, 0, &c);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn area_charts_draw_source_value_labels_only_when_enabled() {
|
||||
for kind in [ChartKind::Area, ChartKind::AreaStacked] {
|
||||
let d = sample(kind);
|
||||
let mut c = chart(kind);
|
||||
c.data_labels = false;
|
||||
let off = render(&c, &d, 640.0, 400.0, &ApproxMeasure);
|
||||
c.data_labels = true;
|
||||
let on = render(&c, &d, 640.0, 400.0, &ApproxMeasure);
|
||||
let count = |p: &[Prim], v: &str| texts(p).iter().filter(|t| **t == v).count();
|
||||
// One label per point: 3 series x 6 categories.
|
||||
assert_eq!(texts(&on).len(), texts(&off).len() + 18, "{kind:?}");
|
||||
for v in ["$12,000", "$38,000", "$9,000", "$27,000"] {
|
||||
assert_eq!(count(&on, v), count(&off, v) + 1, "{kind:?}: {v}");
|
||||
}
|
||||
// Stacked areas label the source values, not cumulative totals (12,000 + 38,000).
|
||||
assert_eq!(count(&on, "$50,000"), count(&off, "$50,000"), "{kind:?}: cumulative total shown");
|
||||
let polys = |p: &[Prim]| p.iter().filter(|p| matches!(p, Prim::Polygon { .. })).cloned().collect::<Vec<_>>();
|
||||
assert_eq!(polys(&on), polys(&off));
|
||||
// The first series' labels are drawn after every area, so the next area can't cover them.
|
||||
let last_poly = on.iter().rposition(|p| matches!(p, Prim::Polygon { .. }));
|
||||
let first_label = on.iter().position(|p| matches!(p, Prim::Text { text, .. } if text == "$12,000"));
|
||||
assert!(first_label > last_poly, "{kind:?}: label drawn under a later area");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user