From 58968594408369474e51225dfdd02e157056df85 Mon Sep 17 00:00:00 2001 From: Harrison Booth <73434116+Harrison-Booth@users.noreply.github.com> Date: Tue, 27 Oct 2026 19:31:45 -0500 Subject: [PATCH] Charts: tickLblPos none hides value-axis labels and unfilled gridlines are not drawn (refs #1366) --- crates/pptx/src/read/chart.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/crates/pptx/src/read/chart.rs b/crates/pptx/src/read/chart.rs index 76158af3..65be9fe4 100644 --- a/crates/pptx/src/read/chart.rs +++ b/crates/pptx/src/read/chart.rs @@ -327,7 +327,11 @@ fn chart_within(root: &El, mut budget: usize) -> Option { Some(n) if n.attr("sourceLinked") != Some("1") => n.attr("formatCode").map(str::to_string), n => source_format(a).or_else(|| n.and_then(|n| n.attr("formatCode")).map(str::to_string)), }; - let deleted = |a: &El| a.child("delete").and_then(|d| d.bool("val")) == Some(true); + // `c:tickLblPos val="none"` hides the labels just as `c:delete` does. + let deleted = |a: &El| a.child("delete").and_then(|d| d.bool("val")) == Some(true) || a.child_val("tickLblPos") == Some("none"); + // A gridline whose `c:spPr/a:ln` has `a:noFill` is not drawn, though the element is there. + let grid = + |a: &El, k: &str| a.child(k).is_some_and(|g| !g.child("spPr").and_then(|p| p.child("ln")).is_some_and(|l| l.child("noFill").is_some())); if c.kind == ChartType::Combo && c.series.iter().any(|s| s.secondary_axis) { let primary_id = val_ax.and_then(|a| a.child_val("axId")); // The other vertical value axis is the secondary one. @@ -342,8 +346,8 @@ fn chart_within(root: &El, mut budget: usize) -> Option { } let cat_ax = pa.child("catAx").or_else(|| pa.child("dateAx")).or_else(|| pa.children_named("valAx").find(|a| !vertical(a))); if let Some(v) = val_ax { - c.gridlines = v.child("majorGridlines").is_some(); - c.minor_gridlines = v.child("minorGridlines").is_some(); + c.gridlines = grid(v, "majorGridlines"); + c.minor_gridlines = grid(v, "minorGridlines"); let sc = v.child("scaling"); c.y_min = sc.and_then(|s| s.child_val("min")).and_then(|v| v.parse().ok()).filter(|v: &f64| v.is_finite()); c.y_max = sc.and_then(|s| s.child_val("max")).and_then(|v| v.parse().ok()).filter(|v: &f64| v.is_finite()); @@ -732,6 +736,26 @@ mod tests { assert_eq!(read_chart_xml(xml.as_bytes()).unwrap().text_size, None, "no sizes: the renderer picks one"); } + #[test] + fn hidden_labels_and_unfilled_gridlines_are_read() { + let xml = |ax: &str| { + format!( + r#"{ax}"# + ) + }; + let no_fill = r#""#; + let c = read_chart_xml(xml(r#""#).as_bytes()).unwrap(); + assert!(c.gridlines && c.minor_gridlines && !c.y_hidden); + let c = read_chart_xml( + xml(&format!( + r#"{no_fill}{no_fill}"# + )) + .as_bytes(), + ) + .unwrap(); + assert!(!c.gridlines && !c.minor_gridlines && c.y_hidden); + } + #[test] fn trendlines_are_read() { let xml = br#"Spend