From f1e9e37e430a1c51a102d76ee357ee77ce67a325 Mon Sep 17 00:00:00 2001 From: chschan Date: Thu, 2 Jul 2026 12:16:02 +1000 Subject: [PATCH 1/4] RS-22447 Export grid line type to PowerPoint/Excel chart settings The MajorGridLine Style for both axes was hardcoded to "Solid" (or "None" when width is 0), so the Grid line type control (Solid/Dot/Dash) was not reflected in exported charts even after the on-screen fix. Derive the style from values.grid.dash / categories.grid.dash via the existing getLineStyle() helper, which already returns "None" for a zero-width line and falls back to "Solid" when no dash is supplied (so existing behaviour is unchanged when the control is absent). Co-Authored-By: Claude Opus 4.8 (1M context) --- R/cchart.R | 4 ++-- tests/testthat/test-chartsettings.R | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/R/cchart.R b/R/cchart.R index aec2f1c..58a7444 100644 --- a/R/cchart.R +++ b/R/cchart.R @@ -845,7 +845,7 @@ getPPTSettings <- function(chart.type, args, data) Crosses = categories.axis.line$crosses, MajorGridLine = list(Color = args$categories.grid.color, Width = px2pt(args$categories.grid.width), - Style = if (isTRUE(args$categories.grid.width == 0)) "None" else "Solid"), + Style = getLineStyle(list(width = args$categories.grid.width, dash = args$categories.grid.dash))), RotateLabels = isTRUE(args$categories.tick.angle == 90), LabelPosition = "Low") if (any(nzchar(args$categories.bounds.maximum))) @@ -866,7 +866,7 @@ getPPTSettings <- function(chart.type, args, data) Crosses = values.axis.line$crosses, MajorGridLine = list(Color = args$values.grid.color, Width = px2pt(args$values.grid.width), - Style = if (isTRUE(args$values.grid.width == 0)) "None" else "Solid")) + Style = getLineStyle(list(width = args$values.grid.width, dash = args$values.grid.dash)))) if (any(nzchar(args$values.bounds.maximum))) res$ValueAxis$Maximum <- args$values.bounds.maximum if (any(nzchar(args$values.bounds.minimum))) diff --git a/tests/testthat/test-chartsettings.R b/tests/testthat/test-chartsettings.R index d79dacf..14b9966 100644 --- a/tests/testthat/test-chartsettings.R +++ b/tests/testthat/test-chartsettings.R @@ -341,3 +341,22 @@ test_that("Color opacity", expect_equal(attr(viz, "ChartSettings")$TemplateSeries[[3]]$OutlineColor, "#22222280") expect_equal(attr(viz, "ChartSettings")$TemplateSeries[[3]]$OutlineWidth, 1.500, tol = 1e-3) }) + +test_that("Grid line type is exported to PowerPoint settings (RS-22447)", +{ + res <- suppressWarnings(CChart("Column", dat.1d, append.data = TRUE, + values.grid.width = 1, values.grid.dash = "Dot", + categories.grid.width = 1, categories.grid.dash = "Dash")) + expect_equal(attr(res, "ChartSettings")$ValueAxis$MajorGridLine$Style, "Dot") + expect_equal(attr(res, "ChartSettings")$PrimaryAxis$MajorGridLine$Style, "Dash") + + # A zero-width grid is still "None" regardless of the dash setting. + res0 <- suppressWarnings(CChart("Column", dat.1d, append.data = TRUE, + values.grid.width = 0, values.grid.dash = "Dot")) + expect_equal(attr(res0, "ChartSettings")$ValueAxis$MajorGridLine$Style, "None") + + # Backwards compatible: no dash supplied still exports as "Solid". + res1 <- suppressWarnings(CChart("Column", dat.1d, append.data = TRUE, + values.grid.width = 1)) + expect_equal(attr(res1, "ChartSettings")$ValueAxis$MajorGridLine$Style, "Solid") +}) From 17e509debc8351822a7230882832b217a10e740e Mon Sep 17 00:00:00 2001 From: chschan Date: Thu, 2 Jul 2026 13:52:42 +1000 Subject: [PATCH 2/4] Update version and dependencies --- DESCRIPTION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 771a1ca..3d8ca98 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: flipChart Type: Package Title: Single function for calling charts - CChart -Version: 1.12.11 +Version: 1.12.12 Author: Displayr Maintainer: Displayr Description: Wrapper for other chart functions, such that they can be access via a @@ -23,7 +23,7 @@ Imports: flipChartBasics, flipData (>= 1.2.7), flipFormat, - flipStandardCharts (>= 1.30.2), + flipStandardCharts (>= 1.32.12), flipStatistics, flipTables (>= 2.8.8), flipTime, From cada096824644e1f79ffed67cca04a9d1e30f4a5 Mon Sep 17 00:00:00 2001 From: chschan Date: Thu, 2 Jul 2026 15:18:08 +1000 Subject: [PATCH 3/4] RS-22447 Preserve "Solid" grid style when width is omitted/NA Review follow-up. getPPTSettings() sees the raw user args before chart defaults are applied, so grid.width is NULL when a caller doesn't pass it (e.g. direct R/API callers of a chart with a default grid). Routing that through getLineStyle() flipped the exported MajorGridLine Style from "Solid" to "None" (grid vanished), and an NA width threw. Add getGridLineStyle(width, dash): only an explicit width of 0 hides the grid; a missing/NA width keeps the previous "Solid" default (NA-safe via isTRUE), while an explicit dash still maps to Dot/Dash. Add a test for the omitted-width case. Co-Authored-By: Claude Opus 4.8 (1M context) --- R/cchart.R | 17 +++++++++++++++-- tests/testthat/test-chartsettings.R | 6 ++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/R/cchart.R b/R/cchart.R index 58a7444..03d6cf4 100644 --- a/R/cchart.R +++ b/R/cchart.R @@ -845,7 +845,7 @@ getPPTSettings <- function(chart.type, args, data) Crosses = categories.axis.line$crosses, MajorGridLine = list(Color = args$categories.grid.color, Width = px2pt(args$categories.grid.width), - Style = getLineStyle(list(width = args$categories.grid.width, dash = args$categories.grid.dash))), + Style = getGridLineStyle(args$categories.grid.width, args$categories.grid.dash)), RotateLabels = isTRUE(args$categories.tick.angle == 90), LabelPosition = "Low") if (any(nzchar(args$categories.bounds.maximum))) @@ -866,7 +866,7 @@ getPPTSettings <- function(chart.type, args, data) Crosses = values.axis.line$crosses, MajorGridLine = list(Color = args$values.grid.color, Width = px2pt(args$values.grid.width), - Style = getLineStyle(list(width = args$values.grid.width, dash = args$values.grid.dash)))) + Style = getGridLineStyle(args$values.grid.width, args$values.grid.dash))) if (any(nzchar(args$values.bounds.maximum))) res$ValueAxis$Maximum <- args$values.bounds.maximum if (any(nzchar(args$values.bounds.minimum))) @@ -934,6 +934,19 @@ getLineStyle <- function (line) { return (line$dash) } +# Grid line style for PPT/Excel export. Unlike getLineStyle(), a missing width +# does NOT mean "no line" here: getPPTSettings() sees the raw user args before +# the chart-function defaults are applied, so an omitted grid.width just means +# "use the chart default" (the grid is typically shown). Only an explicit width +# of 0 hides the grid. isTRUE() keeps this NA-safe. +getGridLineStyle <- function (width, dash) { + if (isTRUE(width == 0)) + return ("None") + if (is.null(dash)) + return ("Solid") + return (dash) +} + # Fix minimum axes bounds if they are not already set # This is performed only because PPT will set the minimum to 0 if not specified diff --git a/tests/testthat/test-chartsettings.R b/tests/testthat/test-chartsettings.R index 14b9966..65be979 100644 --- a/tests/testthat/test-chartsettings.R +++ b/tests/testthat/test-chartsettings.R @@ -359,4 +359,10 @@ test_that("Grid line type is exported to PowerPoint settings (RS-22447)", res1 <- suppressWarnings(CChart("Column", dat.1d, append.data = TRUE, values.grid.width = 1)) expect_equal(attr(res1, "ChartSettings")$ValueAxis$MajorGridLine$Style, "Solid") + + # Backwards compatible: grid.width omitted entirely (NULL in the raw user + # args seen by getPPTSettings) must keep the previous "Solid" default, not + # collapse to "None". + res2 <- suppressWarnings(CChart("Column", dat.1d, append.data = TRUE)) + expect_equal(attr(res2, "ChartSettings")$ValueAxis$MajorGridLine$Style, "Solid") }) From 507a68b0067453fee667a3a9e2b47b233a74519d Mon Sep 17 00:00:00 2001 From: chschan Date: Thu, 2 Jul 2026 15:24:38 +1000 Subject: [PATCH 4/4] RS-22447 Add direct unit tests for getGridLineStyle edge cases The regression escaped because every existing chart-settings test passed grid.width explicitly, leaving the default/omitted path uncovered. Add a direct unit test of getGridLineStyle spanning width 0/positive/NULL/NA x dash present/absent, locking in the NULL/NA-safe "Solid" default the reviewer flagged. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/testthat/test-chartsettings.R | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/testthat/test-chartsettings.R b/tests/testthat/test-chartsettings.R index 65be979..c4248e3 100644 --- a/tests/testthat/test-chartsettings.R +++ b/tests/testthat/test-chartsettings.R @@ -366,3 +366,18 @@ test_that("Grid line type is exported to PowerPoint settings (RS-22447)", res2 <- suppressWarnings(CChart("Column", dat.1d, append.data = TRUE)) expect_equal(attr(res2, "ChartSettings")$ValueAxis$MajorGridLine$Style, "Solid") }) + +test_that("getGridLineStyle handles missing/NA widths (RS-22447)", +{ + # Only an explicit width of 0 hides the grid. + expect_equal(getGridLineStyle(0, "Dot"), "None") + expect_equal(getGridLineStyle(0, NULL), "None") + # A visible grid uses the dash if given, otherwise "Solid". + expect_equal(getGridLineStyle(1, "Dash"), "Dash") + expect_equal(getGridLineStyle(1, NULL), "Solid") + # Missing/NA width must not hide the grid or error - it keeps "Solid" + # (the previous default) unless an explicit dash is supplied. + expect_equal(getGridLineStyle(NULL, NULL), "Solid") + expect_equal(getGridLineStyle(NA, NULL), "Solid") + expect_equal(getGridLineStyle(NULL, "Dot"), "Dot") +})