@@ -3,25 +3,44 @@ import { IWaterfallGraphProps } from '../types/types';
33import { useWaterfallChart } from './utils' ;
44import styles from './styles.module.scss' ;
55import '../index.css' ;
6- import { DEFAULT_BAR_WIDTH , DEFAULT_PIXELS_PER_Y_UNIT } from '../constants' ;
6+ import { DEFAULT_BAR_WIDTH ,
7+ DEFAULT_PIXELS_PER_Y_UNIT ,
8+ DEFAULT_SUMMARY_LABEL ,
9+ FINAL_SUMMARY_GRAPH_KEY ,
10+ FINAL_SUMMARY_X_LABEL_KEY
11+ } from '../constants' ;
712
813const WaterFallChart : FC < IWaterfallGraphProps > = ( props ) => {
9- const { transactions, barWidth } = props ;
14+ const {
15+ transactions,
16+ barWidth,
17+ showBridgeLines = true ,
18+ showYAxisScaleLines = false ,
19+ yAxisPixelsPerUnit = DEFAULT_PIXELS_PER_Y_UNIT ,
20+ showFinalSummary = true ,
21+ summaryXLabel = DEFAULT_SUMMARY_LABEL ,
22+ summaryBarStyles = { } ,
23+ positiveBarStyles = { } ,
24+ negativeBarStyles = { } ,
25+ onChartClick
26+ } = props ;
1027
1128 const wrapperRef = useRef < HTMLDivElement | null > ( null ) ;
1229 const [ wrapperHeight , setWrapperHeight ] = useState ( 0 ) ;
1330 const [ barWidthVal , setBarWidthVal ] = useState ( barWidth ?? DEFAULT_BAR_WIDTH ) ;
1431
1532 const { chartElements, yValueForZeroLine, yAxisPoints, yAxisScale, calculateBarWidth } = useWaterfallChart (
1633 transactions ,
17- wrapperHeight
34+ wrapperHeight ,
35+ yAxisPixelsPerUnit ,
36+ showFinalSummary
1837 ) ;
1938
2039 useEffect ( ( ) => {
2140 const onWrapperDimensionsChange = ( ) : void => {
2241 if ( wrapperRef . current ) {
2342 setWrapperHeight ( wrapperRef ?. current ?. offsetHeight ) ;
24- if ( ! barWidth ) setBarWidthVal ( calculateBarWidth ( wrapperRef ?. current ?. offsetWidth ) ) ;
43+ if ( ! barWidth || barWidth <= 0 ) setBarWidthVal ( calculateBarWidth ( wrapperRef ?. current ?. offsetWidth ) ) ;
2544 }
2645 } ;
2746
@@ -32,21 +51,45 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
3251 return ( ) => window . removeEventListener ( 'resize' , onWrapperDimensionsChange ) ;
3352 } , [ barWidth , calculateBarWidth ] ) ;
3453
54+ const renderSummaryBar = ( ) : JSX . Element => {
55+ const value = Math . abs ( chartElements [ chartElements ?. length - 1 ] ?. cumulativeSum ) ;
56+ const barHeight = Math . abs ( ( value / yAxisScale ) * yAxisPixelsPerUnit ) ;
57+ const chartElement = {
58+ name : summaryXLabel ,
59+ value,
60+ yVal : yValueForZeroLine - ( value / yAxisScale ) * yAxisPixelsPerUnit ,
61+ cumulativeSum : 0 ,
62+ barHeight : barHeight
63+ }
64+
65+ return (
66+ < rect
67+ key = { FINAL_SUMMARY_GRAPH_KEY }
68+ width = { barWidthVal }
69+ height = { chartElement ?. barHeight }
70+ y = { chartElement ?. yVal }
71+ x = { ( 2 * chartElements ?. length + 1 ) * barWidthVal }
72+ className = { `${ styles . graphBar } ${ styles . summaryGraphBar } ` }
73+ onClick = { ( ) : void => onChartClick && onChartClick ( chartElement ) }
74+ />
75+ )
76+ } ;
77+
3578 return (
3679 < div ref = { wrapperRef } className = { styles . chartWrapper } >
3780 < svg className = { styles . svgContainer } >
3881 { /* y-axis */ }
3982 < line x1 = '0' y1 = '0' x2 = '0' y2 = '100%' className = { styles . axisLines } />
4083 { /* x-axis */ }
4184 < line x1 = '0' y1 = '100%' x2 = '100%' y2 = '100%' className = { styles . axisLines } />
42- { /* zero line if negative values present */ }
43- { yAxisPoints ?. map ( ( yPoint , index ) => (
85+ { /*y axis scale lines */ }
86+ { showYAxisScaleLines && yAxisPoints ?. map ( ( yPoint , index ) => (
4487 < line
4588 key = { yPoint }
4689 x1 = '0'
47- y1 = { wrapperHeight - index * DEFAULT_PIXELS_PER_Y_UNIT }
90+ y1 = { wrapperHeight - index * yAxisPixelsPerUnit }
4891 x2 = '100%'
49- y2 = { wrapperHeight - index * DEFAULT_PIXELS_PER_Y_UNIT }
92+ y2 = { wrapperHeight - index * yAxisPixelsPerUnit }
5093 className = { `${ styles . axisLines } ` }
5194 />
5295 ) ) }
@@ -55,37 +98,61 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
5598 < rect
5699 key = { chartElement ?. name }
57100 width = { barWidthVal }
58- height = { ( Math . abs ( chartElement ?. value ) / yAxisScale ) * DEFAULT_PIXELS_PER_Y_UNIT }
101+ height = { chartElement ?. barHeight }
59102 y = { chartElement ?. yVal }
60103 x = { ( 2 * index + 1 ) * barWidthVal }
61104 className = { `${ styles . graphBar } ${ chartElement ?. value >= 0 ? styles . positiveGraph : styles . negativeGraph } ` }
105+ style = { chartElement ?. value >= 0 ? positiveBarStyles : negativeBarStyles }
106+ onClick = { ( ) : void => onChartClick && onChartClick ( chartElement ) }
62107 />
63- < line
64- key = { chartElement ?. name }
65- x1 = { ( 2 * index + 2 ) * barWidthVal }
66- y1 = {
67- wrapperHeight -
68- ( chartElement ?. cumulativeSum / yAxisScale ) * DEFAULT_PIXELS_PER_Y_UNIT -
69- ( wrapperHeight - yValueForZeroLine )
70- }
71- x2 = { ( 2 * index + 3 ) * barWidthVal }
72- y2 = {
73- wrapperHeight -
74- ( chartElement ?. cumulativeSum / yAxisScale ) * DEFAULT_PIXELS_PER_Y_UNIT -
75- ( wrapperHeight - yValueForZeroLine )
76- }
77- className = { styles . bridgeLine }
78- />
108+ { showBridgeLines
109+ && ( showFinalSummary
110+ || index !== chartElements ?. length - 1 )
111+ && (
112+ < line
113+ key = { chartElement ?. name }
114+ className = { styles . bridgeLine }
115+ x1 = { ( 2 * index + 2 ) * barWidthVal }
116+ y1 = { yValueForZeroLine - ( chartElement ?. cumulativeSum / yAxisScale ) * yAxisPixelsPerUnit }
117+ x2 = { ( 2 * index + 3 ) * barWidthVal }
118+ y2 = { yValueForZeroLine - ( chartElement ?. cumulativeSum / yAxisScale ) * yAxisPixelsPerUnit }
119+ />
120+ ) }
79121 </ >
80122 ) ) }
123+ { showFinalSummary && renderSummaryBar ( ) }
81124 </ svg >
82125 < div className = { styles . yPoints } >
83126 { yAxisPoints ?. map ( ( yAxisPoint , index ) => (
84- < div key = { yAxisPoint } className = { styles . yPoint } style = { { bottom : index * DEFAULT_PIXELS_PER_Y_UNIT - 8 } } >
127+ < div
128+ key = { yAxisPoint }
129+ className = { styles . yPoint }
130+ style = { { bottom : index * yAxisPixelsPerUnit - 8 } }
131+ >
85132 { yAxisPoint }
86133 </ div >
87134 ) ) }
88135 </ div >
136+ < div className = { styles . xPoints } >
137+ { transactions ?. map ( ( transaction , index ) => (
138+ < div
139+ key = { transaction ?. label }
140+ className = { styles . xPoint }
141+ style = { { left : ( 2 * index + 1.25 ) * barWidthVal } }
142+ >
143+ { transaction ?. label }
144+ </ div >
145+ ) ) }
146+ { showFinalSummary && (
147+ < div
148+ key = { FINAL_SUMMARY_X_LABEL_KEY }
149+ className = { styles . xPoint }
150+ style = { { ...summaryBarStyles , left : ( 2 * chartElements ?. length + 1.25 ) * barWidthVal } }
151+ >
152+ { summaryXLabel }
153+ </ div >
154+ ) }
155+ </ div >
89156 </ div >
90157 ) ;
91158} ;
0 commit comments