Skip to content

Commit

Permalink
feat: accumulate-relative stacked bar chart stack mode
Browse files Browse the repository at this point in the history
new stack mode was implemented

closes #1167
  • Loading branch information
dangreen committed Nov 2, 2022
1 parent 1438bad commit 65febba
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 15 deletions.
21 changes: 21 additions & 0 deletions src/charts/BarChart/BarChart.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,3 +424,24 @@ export function PeakCircles() {

return root;
}

export function AccumulateRelativeStack() {
const root = document.createElement('div');

new BarChart(
root,
{
labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday'],
series: [
[5, 4, -3, -5],
[5, -4, 3, -5]
]
},
{
stackBars: true,
stackMode: 'accumulate-relative'
}
);

return root;
}
39 changes: 26 additions & 13 deletions src/charts/BarChart/BarChart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,9 @@ const defaultOptions = {
seriesBarDistance: 15,
// If set to true this property will cause the series bars to be stacked. Check the `stackMode` option for further stacking options.
stackBars: false,
// If set to 'overlap' this property will force the stacked bars to draw from the zero line.
// If set to true this property will force the stacked bars to draw from the zero line.
// If set to 'accumulate' this property will form a total for each series point. This will also influence the y-axis and the overall bounds of the chart. In stacked mode the seriesBarDistance property will have no effect.
// If set to 'accumulate-relative' positive and negative values will be handled separately.
stackMode: 'accumulate' as const,
// Inverts the axes of the bar chart in order to draw a horizontal bar chart. Be aware that you also need to invert your axis settings as the Y Axis will now display the labels and the X Axis the values.
horizontalBars: false,
Expand Down Expand Up @@ -344,8 +345,13 @@ export class BarChart extends BaseChart<BarChartEventsTypes> {
const zeroPoint = options.horizontalBars
? chartRect.x1 + valueAxis.projectValue(0)
: chartRect.y1 - valueAxis.projectValue(0);
const isAccumulateStackMode = options.stackMode === 'accumulate';
const isAccumulateRelativeStackMode =
options.stackMode === 'accumulate-relative';
// Used to track the screen coordinates of stacked bars
const stackedBarValues: number[] = [];
const posStackedBarValues: number[] = [];
const negStackedBarValues: number[] = [];
let stackedBarValues = posStackedBarValues;

labelAxis.createGridAndLabels(
gridGroup,
Expand Down Expand Up @@ -428,6 +434,8 @@ export class BarChart extends BaseChart<BarChartEventsTypes> {
);

normalizedData.series[seriesIndex].forEach((value, valueIndex) => {
const valueX = safeHasProperty(value, 'x') && value.x;
const valueY = safeHasProperty(value, 'y') && value.y;
let labelAxisValueIndex;
// We need to set labelAxisValueIndex based on some options combinations
if (options.distributeSeries && !options.stackBars) {
Expand All @@ -450,14 +458,14 @@ export class BarChart extends BaseChart<BarChartEventsTypes> {
x:
chartRect.x1 +
valueAxis.projectValue(
safeHasProperty(value, 'x') ? value.x : 0,
valueX || 0,
valueIndex,
normalizedData.series[seriesIndex]
),
y:
chartRect.y1 -
labelAxis.projectValue(
safeHasProperty(value, 'y') ? value.y : 0,
valueY || 0,
labelAxisValueIndex,
normalizedData.series[seriesIndex]
)
Expand All @@ -467,14 +475,14 @@ export class BarChart extends BaseChart<BarChartEventsTypes> {
x:
chartRect.x1 +
labelAxis.projectValue(
safeHasProperty(value, 'x') ? value.x : 0,
valueX || 0,
labelAxisValueIndex,
normalizedData.series[seriesIndex]
),
y:
chartRect.y1 -
valueAxis.projectValue(
safeHasProperty(value, 'y') ? value.y : 0,
valueY || 0,
valueIndex,
normalizedData.series[seriesIndex]
)
Expand All @@ -500,6 +508,14 @@ export class BarChart extends BaseChart<BarChartEventsTypes> {
(options.horizontalBars ? -1 : 1);
}

// distinguish between positive and negative values in relative stack mode
if (isAccumulateRelativeStackMode) {
stackedBarValues =
valueY >= 0 || valueX >= 0
? posStackedBarValues
: negStackedBarValues;
}

// Enter value in stacked bar values used to remember previous screen value for stacking up bars
const previousStack = stackedBarValues[valueIndex] || zeroPoint;
stackedBarValues[valueIndex] =
Expand All @@ -517,7 +533,9 @@ export class BarChart extends BaseChart<BarChartEventsTypes> {

if (
options.stackBars &&
(options.stackMode === 'accumulate' || !options.stackMode)
(isAccumulateStackMode ||
isAccumulateRelativeStackMode ||
!options.stackMode)
) {
// Stack mode: accumulate (default)
// If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line
Expand Down Expand Up @@ -558,12 +576,7 @@ export class BarChart extends BaseChart<BarChartEventsTypes> {
const bar = seriesElement
.elem('line', positions, options.classNames.bar)
.attr({
'ct:value': [
safeHasProperty(value, 'x') && value.x,
safeHasProperty(value, 'y') && value.y
]
.filter(isNumeric)
.join(','),
'ct:value': [valueX, valueY].filter(isNumeric).join(','),
'ct:meta': serialize(metaData)
});

Expand Down
5 changes: 3 additions & 2 deletions src/charts/BarChart/BarChart.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ export interface BarChartOptions<
*/
stackBars?: boolean;
/**
* If set to 'overlap' this property will force the stacked bars to draw from the zero line.
* If set to true this property will force the stacked bars to draw from the zero line.
* If set to 'accumulate' this property will form a total for each series point. This will also influence the y-axis and the overall bounds of the chart. In stacked mode the seriesBarDistance property will have no effect.
* If set to 'accumulate-relative' positive and negative values will be handled separately.
*/
stackMode?: 'accumulate' | boolean;
stackMode?: 'accumulate' | 'accumulate-relative' | boolean;
/**
* Inverts the axes of the bar chart in order to draw a horizontal bar chart. Be aware that you also need to invert your axis settings as the Y Axis will now display the labels and the X Axis the values.
*/
Expand Down

0 comments on commit 65febba

Please sign in to comment.