From 1d1f3f211bba611287e4686552a2490a25503f2d Mon Sep 17 00:00:00 2001 From: Edoardo Sabadelli Date: Fri, 25 Aug 2023 16:10:17 +0200 Subject: [PATCH] feat: implement cumulative values DHIS2-5497 --- src/__demo__/PivotTable.stories.js | 40 +++++++++++++++++ src/modules/pivotTable/PivotTableEngine.js | 50 +++++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/__demo__/PivotTable.stories.js b/src/__demo__/PivotTable.stories.js index b4c46f346..925b41b34 100644 --- a/src/__demo__/PivotTable.stories.js +++ b/src/__demo__/PivotTable.stories.js @@ -784,6 +784,26 @@ storiesOf('PivotTable', module).add( } ) +storiesOf('PivotTable', module).add( + 'cumulative + empty columns (weekly) - shown', + (_, { pivotTableOptions }) => { + const visualization = { + ...weeklyColumnsVisualization, + ...pivotTableOptions, + hideEmptyColumns: false, + cumulativeValues: true, + } + return ( +
+ +
+ ) + } +) + storiesOf('PivotTable', module).add( 'empty columns (weekly) - hidden', (_, { pivotTableOptions }) => { @@ -803,6 +823,26 @@ storiesOf('PivotTable', module).add( } ) +storiesOf('PivotTable', module).add( + 'cumulative + empty columns (weekly) - hidden', + (_, { pivotTableOptions }) => { + const visualization = { + ...weeklyColumnsVisualization, + ...pivotTableOptions, + hideEmptyColumns: true, + cumulativeValues: true, + } + return ( +
+ +
+ ) + } +) + storiesOf('PivotTable', module).add( 'empty columns + assigned cats (shown)', (_, { pivotTableOptions }) => { diff --git a/src/modules/pivotTable/PivotTableEngine.js b/src/modules/pivotTable/PivotTableEngine.js index 46f8cc0fa..3cfbda23b 100644 --- a/src/modules/pivotTable/PivotTableEngine.js +++ b/src/modules/pivotTable/PivotTableEngine.js @@ -53,6 +53,7 @@ const defaultOptions = { showColumnSubtotals: false, fixColumnHeaders: false, fixRowHeaders: false, + cumulativeValues: false, } const defaultVisualizationProps = { @@ -266,6 +267,7 @@ export class PivotTableEngine { data = [] rowMap = [] columnMap = [] + accumulators = { rows: {} } constructor(visualization, data, legendSets) { this.visualization = Object.assign( @@ -304,6 +306,7 @@ export class PivotTableEngine { fixRowHeaders: this.dimensionLookup.rows.length ? visualization.fixRowHeaders : false, + cumulativeValues: visualization.cumulativeValues, } this.adaptiveClippingController = new AdaptiveClippingController(this) @@ -395,6 +398,10 @@ export class PivotTableEngine { } } + getCumulative({ row, column }) { + return this.accumulators.rows[row][column] + } + get({ row, column }) { const mappedRow = this.rowMap[row], mappedColumn = this.columnMap[column] @@ -405,7 +412,27 @@ export class PivotTableEngine { return undefined } - return this.getRaw({ row: mappedRow, column: mappedColumn }) + const value = this.getRaw({ row: mappedRow, column: mappedColumn }) + + // XXX cannot be done directly in getRaw because of the resetAccumulators function + if (this.options.cumulativeValues) { + // some duplicated code here, see if there's a better way + const dxDimension = this.getRawCellDxDimension({ row, column }) + + // XXX this doesn't make much sense, it has to be numeric for accumulation + value.valueType = dxDimension?.valueType || VALUE_TYPE_TEXT + value.empty = false + value.renderedValue = renderValue( + this.getCumulative({ + row: mappedRow, + column: mappedColumn, + }), + value.valueType, + this.visualization + ) + } + + return value } getRawCellType({ row, column }) { @@ -957,6 +984,25 @@ export class PivotTableEngine { : times(this.dataWidth, (n) => n) } + resetAccumulators() { + if (this.options.cumulativeValues) { + this.rowMap.forEach((row) => { + this.accumulators.rows[row] = {} + this.columnMap.reduce((acc, column) => { + const value = this.getRaw({ row, column }) + + acc += value.empty ? 0 : value.rawValue + + this.accumulators.rows[row][column] = acc + + return acc + }, 0) + }) + } else { + this.accumulators = { rows: {} } + } + } + get cellPadding() { switch (this.visualization.displayDensity) { case DISPLAY_DENSITY_OPTION_COMPACT: @@ -1062,6 +1108,8 @@ export class PivotTableEngine { this.resetRowMap() this.resetColumnMap() + this.resetAccumulators() + this.height = this.rowMap.length this.width = this.columnMap.length