1- import React , { FC , useEffect , useRef , useState } from 'react' ;
1+ import React , { FC , Fragment , useEffect , useRef , useState } from 'react' ;
22import { IWaterfallGraphProps } from '../types/types' ;
33import useWaterfallChart from './useWaterFallChart' ;
44import classes from './styles.module.scss' ;
@@ -14,21 +14,30 @@ import {
1414const WaterFallChart : FC < IWaterfallGraphProps > = ( props ) => {
1515 const {
1616 dataPoints,
17- barWidth,
17+ barWidth : initialBarWidth = DEFAULT_BAR_WIDTH ,
1818 showBridgeLines = true ,
1919 showYAxisScaleLines = false ,
20- yAxisPixelsPerUnit = DEFAULT_PIXELS_PER_Y_UNIT ,
20+ yAxisPixelsPerUnit : initialYAxisPixelsPerUnit ,
2121 showFinalSummary = true ,
2222 summaryXLabel = DEFAULT_SUMMARY_LABEL ,
2323 styles = { } ,
24- onChartClick
24+ onChartClick,
25+ onMouseEnter,
26+ onMouseLeave
2527 } = props ;
2628
2729 const wrapperRef = useRef < HTMLDivElement | null > ( null ) ;
2830 const [ wrapperHeight , setWrapperHeight ] = useState ( 0 ) ;
29- const [ barWidthVal , setBarWidthVal ] = useState ( barWidth ?? DEFAULT_BAR_WIDTH ) ;
31+ const [ barWidth , setBarWidth ] = useState ( initialBarWidth ) ;
32+ const yAxisPixelsPerUnit = initialYAxisPixelsPerUnit ? initialYAxisPixelsPerUnit : DEFAULT_PIXELS_PER_Y_UNIT ;
3033
31- const { chartElements, yValueForZeroLine, yAxisPoints, yAxisScale, calculateBarWidth } = useWaterfallChart (
34+ const {
35+ chartElements,
36+ yValueForZeroLine,
37+ yAxisPoints,
38+ yAxisScale,
39+ calculateBarWidth
40+ } = useWaterfallChart (
3241 dataPoints ,
3342 wrapperHeight ,
3443 yAxisPixelsPerUnit ,
@@ -39,7 +48,9 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
3948 const onWrapperDimensionsChange = ( ) : void => {
4049 if ( wrapperRef . current ) {
4150 setWrapperHeight ( wrapperRef ?. current ?. offsetHeight ) ;
42- if ( ! barWidth || barWidth <= 0 ) setBarWidthVal ( calculateBarWidth ( wrapperRef ?. current ?. offsetWidth ) ) ;
51+ if ( ! initialBarWidth || initialBarWidth <= 0 ) {
52+ setBarWidth ( calculateBarWidth ( wrapperRef ?. current ?. offsetWidth ) ) ;
53+ }
4354 }
4455 } ;
4556
@@ -48,7 +59,8 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
4859 window . addEventListener ( 'resize' , onWrapperDimensionsChange ) ;
4960
5061 return ( ) => window . removeEventListener ( 'resize' , onWrapperDimensionsChange ) ;
51- } , [ barWidth , calculateBarWidth ] ) ;
62+ // eslint-disable-next-line react-hooks/exhaustive-deps
63+ } , [ initialBarWidth ] ) ;
5264
5365 const summaryValue = Math . abs ( chartElements [ chartElements ?. length - 1 ] ?. cumulativeSum ) ;
5466 const summaryBarHeight = Math . abs ( ( summaryValue / yAxisScale ) * yAxisPixelsPerUnit ) ;
@@ -61,7 +73,7 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
6173 } ;
6274
6375 return (
64- < div ref = { wrapperRef } className = { classes . chartWrapper } >
76+ < div ref = { wrapperRef } className = { classes . chartWrapper } id = 'graph-svg-wrapper' >
6577 < svg className = { classes . svgContainer } >
6678 { /* y-axis */ }
6779 < line x1 = '0' y1 = '0' x2 = '0' y2 = '100%' className = { classes . axisLines } id = 'yAxisLine' />
@@ -80,51 +92,54 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
8092 />
8193 ) ) }
8294 { chartElements ?. map ( ( chartElement , index ) => (
83- < >
95+ < Fragment key = { ` ${ chartElement ?. name } -bar-graph` } >
8496 < rect
85- key = { `${ chartElement ?. name } -bar-graph` }
86- width = { barWidthVal }
97+ width = { barWidth }
8798 height = { chartElement ?. barHeight }
8899 y = { chartElement ?. yVal }
89- x = { ( 2 * index + 1 ) * barWidthVal }
90- className = { `${ classes . graphBar } ${ chartElement ?. value >= 0 ? classes . positiveGraph : classes . negativeGraph } ` }
100+ x = { ( 2 * index + 1 ) * barWidth }
101+ className = { `${ classes . graphBar } ${
102+ chartElement ?. value >= 0 ? classes . positiveGraph : classes . negativeGraph
103+ } `}
91104 style = { chartElement ?. value >= 0 ? styles ?. positiveBar : styles ?. negativeBar }
92105 onClick = { ( ) : void => onChartClick && onChartClick ( chartElement ) }
106+ onMouseEnter = { ( e : React . MouseEvent < SVGRectElement , MouseEvent > ) :void => onMouseEnter && onMouseEnter ( e , chartElement ) }
107+ onMouseLeave = { ( e : React . MouseEvent < SVGRectElement , MouseEvent > ) :void => onMouseLeave && onMouseLeave ( e , chartElement ) }
93108 id = { `chartBar-${ index } ` }
109+ data-testid = { `data-point` }
94110 />
95- { showBridgeLines && ( showFinalSummary || index !== chartElements ?. length - 1 ) && (
111+ { showBridgeLines &&
112+ ( showFinalSummary || index !== chartElements ?. length - 1 ) && (
96113 < line
97114 key = { `${ chartElement ?. name } -bridge-line` }
98115 className = { classes . bridgeLine }
99- x1 = { ( 2 * index + 2 ) * barWidthVal }
116+ x1 = { ( 2 * index + 2 ) * barWidth }
100117 y1 = { yValueForZeroLine - ( chartElement ?. cumulativeSum / yAxisScale ) * yAxisPixelsPerUnit }
101- x2 = { ( 2 * index + 3 ) * barWidthVal }
118+ x2 = { ( 2 * index + 3 ) * barWidth }
102119 y2 = { yValueForZeroLine - ( chartElement ?. cumulativeSum / yAxisScale ) * yAxisPixelsPerUnit }
103120 id = { `chartBarBridgeLine-${ index } ` }
104121 />
105122 ) }
106- </ >
123+ </ Fragment >
107124 ) ) }
108125 { showFinalSummary && summaryBarHeight > 0 && (
109126 < rect
110127 key = { FINAL_SUMMARY_GRAPH_KEY }
111- width = { barWidthVal }
128+ width = { barWidth }
112129 height = { summaryChartElement ?. barHeight }
113130 y = { summaryChartElement ?. yVal }
114- x = { ( 2 * chartElements ?. length + 1 ) * barWidthVal }
131+ x = { ( 2 * chartElements ?. length + 1 ) * barWidth }
115132 className = { `${ classes . graphBar } ${ classes . summaryGraphBar } ` }
116133 onClick = { ( ) : void => onChartClick && onChartClick ( summaryChartElement ) }
117134 id = 'summaryBar'
135+ onMouseEnter = { ( e : React . MouseEvent < SVGRectElement , MouseEvent > ) :void => onMouseEnter && onMouseEnter ( e , summaryChartElement ) }
136+ onMouseLeave = { ( e : React . MouseEvent < SVGRectElement , MouseEvent > ) :void => onMouseLeave && onMouseLeave ( e , summaryChartElement ) }
118137 />
119138 ) }
120139 </ svg >
121140 < div className = { classes . yPoints } >
122141 { yAxisPoints ?. map ( ( yAxisPoint , index ) => (
123- < div
124- key = { yAxisPoint }
125- className = { classes . yPoint }
126- style = { { bottom : index * yAxisPixelsPerUnit - 7 } }
127- >
142+ < div key = { yAxisPoint } className = { classes . yPoint } style = { { bottom : index * yAxisPixelsPerUnit - 7 } } >
128143 { yAxisPoint }
129144 </ div >
130145 ) ) }
@@ -134,7 +149,7 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
134149 < div
135150 key = { transaction ?. label }
136151 className = { classes . xPoint }
137- style = { { left : ( 2 * index + 1.25 ) * barWidthVal } }
152+ style = { { left : ( 2 * index + 1.25 ) * barWidth } }
138153 // the 1.25 is to reduce chances for the label to overflow to right
139154 >
140155 { transaction ?. label }
@@ -144,7 +159,7 @@ const WaterFallChart: FC<IWaterfallGraphProps> = (props) => {
144159 < div
145160 key = { FINAL_SUMMARY_X_LABEL_KEY }
146161 className = { classes . xPoint }
147- style = { { ...styles ?. summaryBar , left : ( 2 * chartElements ?. length + 1.25 ) * barWidthVal } }
162+ style = { { ...styles ?. summaryBar , left : ( 2 * chartElements ?. length + 1.25 ) * barWidth } }
148163 >
149164 { summaryXLabel }
150165 </ div >
0 commit comments