Skip to content

Commit 20c5ae3

Browse files
committed
changes as per PR comments
1 parent 92c7ff8 commit 20c5ae3

File tree

3 files changed

+90
-91
lines changed

3 files changed

+90
-91
lines changed

src/waterfall-chart/WaterFallChart.tsx

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React, { FC, useEffect, useRef, useState } from 'react';
22
import { IWaterfallGraphProps } from '../types/types';
3-
import { useWaterfallChart } from './utils';
3+
import useWaterfallChart from './useWaterFallChart';
44
import styles from './styles.module.scss';
5-
import '../index.css';
5+
66
import {
77
DEFAULT_BAR_WIDTH,
88
DEFAULT_PIXELS_PER_Y_UNIT,
@@ -52,28 +52,14 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
5252
return () => window.removeEventListener('resize', onWrapperDimensionsChange);
5353
}, [barWidth, calculateBarWidth]);
5454

55-
const renderSummaryBar = (): JSX.Element => {
56-
const value = Math.abs(chartElements[chartElements?.length - 1]?.cumulativeSum);
57-
const barHeight = Math.abs((value / yAxisScale) * yAxisPixelsPerUnit);
58-
const chartElement = {
59-
name: summaryXLabel,
60-
value,
61-
yVal: yValueForZeroLine - (value / yAxisScale) * yAxisPixelsPerUnit,
62-
cumulativeSum: 0,
63-
barHeight: barHeight
64-
};
65-
66-
return (
67-
<rect
68-
key={FINAL_SUMMARY_GRAPH_KEY}
69-
width={barWidthVal}
70-
height={chartElement?.barHeight}
71-
y={chartElement?.yVal}
72-
x={(2 * chartElements?.length + 1) * barWidthVal}
73-
className={`${styles.graphBar} ${styles.summaryGraphBar}`}
74-
onClick={(): void => onChartClick && onChartClick(chartElement)}
75-
/>
76-
);
55+
const summaryValue = Math.abs(chartElements[chartElements?.length - 1]?.cumulativeSum);
56+
const summaryBarHeight = Math.abs((summaryValue / yAxisScale) * yAxisPixelsPerUnit);
57+
const summaryChartElement = {
58+
name: summaryXLabel,
59+
value: summaryValue,
60+
yVal: yValueForZeroLine - (summaryValue / yAxisScale) * yAxisPixelsPerUnit,
61+
cumulativeSum: 0,
62+
barHeight: summaryBarHeight
7763
};
7864

7965
return (
@@ -97,7 +83,7 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
9783
{chartElements?.map((chartElement, index) => (
9884
<>
9985
<rect
100-
key={chartElement?.name}
86+
key={`${chartElement?.name}-bar-graph`}
10187
width={barWidthVal}
10288
height={chartElement?.barHeight}
10389
y={chartElement?.yVal}
@@ -108,7 +94,7 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
10894
/>
10995
{showBridgeLines && (showFinalSummary || index !== chartElements?.length - 1) && (
11096
<line
111-
key={chartElement?.name}
97+
key={`${chartElement?.name}-bridge-line`}
11298
className={styles.bridgeLine}
11399
x1={(2 * index + 2) * barWidthVal}
114100
y1={yValueForZeroLine - (chartElement?.cumulativeSum / yAxisScale) * yAxisPixelsPerUnit}
@@ -118,7 +104,17 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
118104
)}
119105
</>
120106
))}
121-
{showFinalSummary && renderSummaryBar()}
107+
{showFinalSummary && (
108+
<rect
109+
key={FINAL_SUMMARY_GRAPH_KEY}
110+
width={barWidthVal}
111+
height={summaryChartElement?.barHeight}
112+
y={summaryChartElement?.yVal}
113+
x={(2 * chartElements?.length + 1) * barWidthVal}
114+
className={`${styles.graphBar} ${styles.summaryGraphBar}`}
115+
onClick={(): void => onChartClick && onChartClick(summaryChartElement)}
116+
/>
117+
)}
122118
</svg>
123119
<div className={styles.yPoints}>
124120
{yAxisPoints?.map((yAxisPoint, index) => (
@@ -137,6 +133,7 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
137133
key={transaction?.label}
138134
className={styles.xPoint}
139135
style={{ left: (2 * index + 1.25) * barWidthVal }}
136+
// the 1.25 is to reduce chances for the label to overflow to right
140137
>
141138
{transaction?.label}
142139
</div>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { IChartElement, ITransaction, IUseWaterfallChartReturnType } from "../types/types";
2+
import { getIntervalAndYPoints, getLargestCumulativeSum, getSmallestCumulativeSum } from "./utils";
3+
4+
const useWaterfallChart = (
5+
transactions: Array<ITransaction>,
6+
chartHeight: number,
7+
yAxisPixelsPerUnit: number,
8+
showFinalSummary: boolean
9+
): IUseWaterfallChartReturnType => {
10+
const largestCumulativeVal = getLargestCumulativeSum(transactions); // this will be the highest y point in the graph
11+
const smallestCumulativeVal = getSmallestCumulativeSum(transactions);
12+
let chartElements: Array<IChartElement> = [];
13+
14+
const maxLabelsCount = Math.ceil(chartHeight / yAxisPixelsPerUnit);
15+
16+
let yAxisPoints: Array<number> = [];
17+
let yAxisScale = 0;
18+
let lowestYAxisValue = 0;
19+
let yValueForZeroLine = 0;
20+
21+
if (chartHeight && chartHeight > 0) {
22+
const InterValAndYPoints = getIntervalAndYPoints(smallestCumulativeVal, largestCumulativeVal, maxLabelsCount);
23+
yAxisPoints = InterValAndYPoints?.yAxisPoints;
24+
yAxisScale = InterValAndYPoints?.yAxisScale;
25+
lowestYAxisValue = InterValAndYPoints?.yAxisPoints[0];
26+
// yAxisScale is the number of Y units per 30px
27+
// lowestYAxisValue is the yAxisValue for origin (0, 0)
28+
29+
yValueForZeroLine = chartHeight - (Math.abs(lowestYAxisValue) / yAxisScale) * yAxisPixelsPerUnit;
30+
let cumulativeSum = 0;
31+
32+
chartElements = transactions.map((transaction) => {
33+
const { label, value } = transaction;
34+
let yVal = 0;
35+
const barHeight = (value / yAxisScale) * yAxisPixelsPerUnit;
36+
const offsetHeight = (cumulativeSum / yAxisScale) * yAxisPixelsPerUnit;
37+
// minimum distance from zero line to the floating bar for the transaction
38+
if (value < 0) {
39+
yVal = yValueForZeroLine - offsetHeight;
40+
} else yVal = yValueForZeroLine - (offsetHeight + barHeight);
41+
42+
cumulativeSum += value;
43+
44+
return { name: label, value, yVal, cumulativeSum, barHeight: Math.abs(barHeight) };
45+
});
46+
}
47+
48+
const calculateBarWidth = (chartWidth: number): number => {
49+
let barWidth = 0;
50+
if (chartWidth && transactions?.length > 0) {
51+
if (showFinalSummary) barWidth = chartWidth / (2 * transactions?.length + 2);
52+
else barWidth = chartWidth / (2 * transactions?.length + 1);
53+
}
54+
return barWidth;
55+
};
56+
57+
return { chartElements, yValueForZeroLine, yAxisPoints, yAxisScale, calculateBarWidth };
58+
};
59+
60+
export default useWaterfallChart;

src/waterfall-chart/utils.ts

Lines changed: 6 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,9 @@
11
import {
2-
IChartElement,
32
IGetIntervalAndYPointsReturnType,
4-
ITransaction,
5-
IUseWaterfallChartReturnType
3+
ITransaction
64
} from '../types/types';
75

8-
export const useWaterfallChart = (
9-
transactions: Array<ITransaction>,
10-
chartHeight: number,
11-
yAxisPixelsPerUnit: number,
12-
showFinalSummary: boolean
13-
): IUseWaterfallChartReturnType => {
14-
const largestCumulativeVal = getLargestCumulativeSum(transactions); // this will be the highest y point in the graph
15-
const smallestCumulativeVal = getSmallestCumulativeSum(transactions);
16-
let chartElements: Array<IChartElement> = [];
17-
18-
const maxLabelsCount = Math.ceil(chartHeight / yAxisPixelsPerUnit);
19-
20-
let yAxisPoints: Array<number> = [];
21-
let yAxisScale = 0;
22-
let lowestYAxisValue = 0;
23-
let yValueForZeroLine = 0;
24-
25-
if (chartHeight && chartHeight > 0) {
26-
const InterValAndYPoints = getIntervalAndYPoints(smallestCumulativeVal, largestCumulativeVal, maxLabelsCount);
27-
yAxisPoints = InterValAndYPoints?.yAxisPoints;
28-
yAxisScale = InterValAndYPoints?.yAxisScale;
29-
lowestYAxisValue = InterValAndYPoints?.yAxisPoints[0];
30-
// yAxisScale is the number of Y units per 30px
31-
// lowestYAxisValue is the yAxisValue for origin (0, 0)
32-
33-
yValueForZeroLine = chartHeight - (Math.abs(lowestYAxisValue) / yAxisScale) * yAxisPixelsPerUnit;
34-
let cumulativeSum = 0;
35-
36-
chartElements = transactions.map((transaction) => {
37-
const { label, value } = transaction;
38-
let yVal = 0;
39-
const barHeight = (value / yAxisScale) * yAxisPixelsPerUnit;
40-
const offsetHeight = (cumulativeSum / yAxisScale) * yAxisPixelsPerUnit;
41-
// minimum distance from zero line to the floating bar for the transaction
42-
if (value < 0) {
43-
yVal = yValueForZeroLine - offsetHeight;
44-
} else yVal = yValueForZeroLine - (offsetHeight + barHeight);
45-
46-
cumulativeSum += value;
47-
48-
return { name: label, value, yVal, cumulativeSum, barHeight: Math.abs(barHeight) };
49-
});
50-
}
51-
52-
const calculateBarWidth = (chartWidth: number): number => {
53-
let barWidth = 0;
54-
if (chartWidth && transactions?.length > 0) {
55-
if (showFinalSummary) barWidth = chartWidth / (2 * transactions?.length + 2);
56-
else barWidth = chartWidth / (2 * transactions?.length + 1);
57-
}
58-
return barWidth;
59-
};
60-
61-
return { chartElements, yValueForZeroLine, yAxisPoints, yAxisScale, calculateBarWidth };
62-
};
63-
64-
function getLargestCumulativeSum(arr: Array<ITransaction>): number {
6+
export function getLargestCumulativeSum(arr: Array<ITransaction>): number {
657
let maxSum = arr[0]?.value; // Initialize maxSum and currentSum with the first element of the array
668
let currentSum = arr[0]?.value;
679

@@ -74,7 +16,7 @@ function getLargestCumulativeSum(arr: Array<ITransaction>): number {
7416
return maxSum;
7517
}
7618

77-
function getSmallestCumulativeSum(arr: Array<ITransaction>): number {
19+
export function getSmallestCumulativeSum(arr: Array<ITransaction>): number {
7820
let minSum = arr[0]?.value; // Initialize minSum and currentSum with the first element of the array
7921
let currentSum = arr[0]?.value;
8022

@@ -89,15 +31,15 @@ function getSmallestCumulativeSum(arr: Array<ITransaction>): number {
8931
return minSum;
9032
}
9133

92-
function roundMinVal(minVal: number, range: number): number {
34+
export function roundMinVal(minVal: number, range: number): number {
9335
return Math.floor(minVal / range) * range;
9436
}
9537

9638
function roundMaxVal(maxVal: number, range: number): number {
9739
return Math.ceil(maxVal / range) * range;
9840
}
9941

100-
function getIntervalAndYPoints(
42+
export function getIntervalAndYPoints(
10143
minVal: number,
10244
maxVal: number,
10345
maxLabelsCount: number
@@ -129,7 +71,7 @@ function getIntervalAndYPoints(
12971
return { yAxisScale, yAxisPoints };
13072
}
13173

132-
function checkIfScaleSufficient(scale: number, maxLabelsCount: number, valueRange: number): boolean {
74+
export function checkIfScaleSufficient(scale: number, maxLabelsCount: number, valueRange: number): boolean {
13375
if (maxLabelsCount === 0) return true; // to stop the while loop from checking for sufficient scale with zero maxLabelsCount
13476
if (scale * maxLabelsCount >= valueRange) return true;
13577
return false;

0 commit comments

Comments
 (0)