@@ -49,25 +49,35 @@ class CFDRenderer extends UIControlsRenderer {
4949 * }
5050 * ];
5151 */
52- constructor ( data , states ) {
52+ constructor ( data , states , chartName ) {
5353 super ( data ) ;
5454 this . states = states ;
55+ this . chartType = 'CFD' ;
56+ this . chartName = chartName ;
5557 this . #statesColors = d3 . scaleOrdinal ( ) . domain ( this . states ) . range ( this . #colorPalette) ;
5658 }
5759
5860 /**
5961 * Sets up an event bus for the renderer to listen to events.
6062 * @param {Object } eventBus - The event bus for communication.
6163 */
62- setupEventBus ( eventBus ) {
64+ setupEventBus ( eventBus , mouseChartsEvents , timeRangeChartsEvents ) {
6365 this . eventBus = eventBus ;
64- this . eventBus ?. addEventListener ( 'change-time-range-scatterplot' , this . updateBrushSelection . bind ( this ) ) ;
65- this . eventBus ?. addEventListener ( 'scatterplot-mousemove' , ( event ) => this . #handleMouseEvent( event , 'scatterplot-mousemove' ) ) ;
66- this . eventBus ?. addEventListener ( 'scatterplot-mouseleave' , ( ) => this . hideTooltipAndMovingLine ( ) ) ;
67- this . eventBus ?. addEventListener ( 'change-time-interval-scatterplot' , ( timeInterval ) => {
68- this . timeInterval = timeInterval ;
69- this . drawXAxis ( this . gx , this . x ?. copy ( ) . domain ( this . selectedTimeRange ) , this . height , true ) ;
70- } ) ;
66+ if ( this . eventBus && Array . isArray ( timeRangeChartsEvents ) ) {
67+ timeRangeChartsEvents . forEach ( ( chart ) => {
68+ this . eventBus . addEventListener ( `change-time-range-${ chart } ` , ( newTimeRange ) => {
69+ if ( ! this . preventEventLoop ) {
70+ this . updateBrushSelection ( newTimeRange ) ;
71+ }
72+ } ) ;
73+ } ) ;
74+ }
75+ if ( this . eventBus && Array . isArray ( mouseChartsEvents ) ) {
76+ mouseChartsEvents . forEach ( ( chart ) => {
77+ this . eventBus ?. addEventListener ( `${ chart } -mousemove` , ( event ) => this . #handleMouseEvent( event , `${ chart } -mousemove` ) ) ;
78+ this . eventBus ?. addEventListener ( `${ chart } -mouseleave` , ( ) => this . hideTooltipAndMovingLine ( ) ) ;
79+ } ) ;
80+ }
7181 }
7282
7383 //region Graph and brush rendering
@@ -101,7 +111,7 @@ class CFDRenderer extends UIControlsRenderer {
101111 this . selectedTimeRange = selection . map ( this . x . invert , this . x ) ;
102112 this . updateGraph ( this . selectedTimeRange ) ;
103113 if ( this . isManualBrushUpdate && this . eventBus ) {
104- this . eventBus ?. emitEvents ( ' change-time-range-cfd' , this . selectedTimeRange ) ;
114+ this . eventBus ?. emitEvents ( ` change-time-range-${ this . chartName } ` , this . selectedTimeRange ) ;
105115 }
106116 this . isManualBrushUpdate = true ;
107117 } )
@@ -113,7 +123,7 @@ class CFDRenderer extends UIControlsRenderer {
113123
114124 const brushArea = this . #createAreaGenerator( this . x , this . y . copy ( ) . range ( [ this . focusHeight - this . margin . top , 4 ] ) ) ;
115125 this . #drawStackedAreaChart( svgBrush , this . #stackedData, brushArea ) ;
116- this . changeTimeInterval ( false , 'cfd' ) ;
126+ this . changeTimeInterval ( false ) ;
117127 this . drawXAxis ( svgBrush . append ( 'g' ) , this . x , this . focusHeight - this . margin . top ) ;
118128 this . brushGroup = svgBrush . append ( 'g' ) ;
119129 this . brushGroup . call ( this . brush ) . call (
@@ -142,10 +152,10 @@ class CFDRenderer extends UIControlsRenderer {
142152 */
143153 updateGraph ( domain ) {
144154 const maxY = d3 . max ( this . #stackedData[ this . #stackedData. length - 1 ] , ( d ) => ( d . data . date <= domain [ 1 ] ? d [ 1 ] : - 1 ) ) ;
145- this . reportingRangeDays = calculateDaysBetweenDates ( domain [ 0 ] , domain [ 1 ] ) ;
155+ this . reportingRangeDays = calculateDaysBetweenDates ( domain [ 0 ] , domain [ 1 ] ) . roundedDays ;
146156 this . currentXScale = this . x . copy ( ) . domain ( domain ) ;
147157 this . currentYScale = this . y . copy ( ) . domain ( [ 0 , maxY ] ) . nice ( ) ;
148- this . changeTimeInterval ( false , 'cfd' ) ;
158+ this . changeTimeInterval ( false ) ;
149159 this . drawXAxis ( this . gx , this . currentXScale , this . height , true ) ;
150160 this . drawYAxis ( this . gy , this . currentYScale ) ;
151161
@@ -181,8 +191,13 @@ class CFDRenderer extends UIControlsRenderer {
181191 * @private
182192 */
183193 #drawArea( ) {
184- this . chartArea = this . addClipPath ( this . svg , 'cfd-clip' ) ;
185- this . chartArea . append ( 'rect' ) . attr ( 'width' , '100%' ) . attr ( 'height' , '100%' ) . attr ( 'id' , 'cfd-area' ) . attr ( 'fill' , 'transparent' ) ;
194+ this . chartArea = this . addClipPath ( this . svg , `${ this . chartName } -clip` ) ;
195+ this . chartArea
196+ . append ( 'rect' )
197+ . attr ( 'width' , '100%' )
198+ . attr ( 'height' , '100%' )
199+ . attr ( 'id' , `${ this . chartName } -area` )
200+ . attr ( 'fill' , 'transparent' ) ;
186201 const areaGenerator = this . #createAreaGenerator( this . x , this . y ) ;
187202 this . #drawStackedAreaChart( this . chartArea , this . #stackedData, areaGenerator ) ;
188203 this . #drawLegend( ) ;
@@ -289,7 +304,7 @@ class CFDRenderer extends UIControlsRenderer {
289304 */
290305 setupXAxisControl ( ) {
291306 this . gx . on ( 'click' , ( ) => {
292- this . changeTimeInterval ( true , 'cfd' ) ;
307+ this . changeTimeInterval ( true ) ;
293308 this . drawXAxis ( this . gx , this . x . copy ( ) . domain ( this . selectedTimeRange ) , this . height , true ) ;
294309 } ) ;
295310 }
@@ -327,7 +342,7 @@ class CFDRenderer extends UIControlsRenderer {
327342 */
328343 drawXAxis ( g , x , height = this . height , isGraph = false ) {
329344 let axis ;
330- const clipId = 'cfd -x-axis-clip' ;
345+ const clipId = ` ${ this . chartName } -x-axis-clip` ;
331346 this . svg
332347 . append ( 'clipPath' )
333348 . attr ( 'id' , clipId )
@@ -371,7 +386,7 @@ class CFDRenderer extends UIControlsRenderer {
371386 * @param {Object } observations - Observations data for the renderer.
372387 */
373388 setupObservationLogging ( observations ) {
374- if ( observations . length > 0 ) {
389+ if ( observations . data . length > 0 ) {
375390 this . displayObservationMarkers ( observations ) ;
376391 this . enableMetrics ( ) ;
377392 }
@@ -398,7 +413,7 @@ class CFDRenderer extends UIControlsRenderer {
398413 const trianglePath = `M${ - triangleBase / 2 } ,0 L${ triangleBase / 2 } ,0 L0,-${ triangleHeight } Z` ;
399414 this . chartArea
400415 . selectAll ( 'observations' )
401- . data ( observations ?. data ?. filter ( ( d ) => d . chart_type === 'CFD' ) )
416+ . data ( observations ?. data ?. filter ( ( d ) => d . chart_type === this . chartType ) )
402417 . join ( 'path' )
403418 . attr ( 'class' , 'observation-marker' )
404419 . attr ( 'd' , trianglePath )
@@ -448,7 +463,7 @@ class CFDRenderer extends UIControlsRenderer {
448463 this . tooltip = d3 . select ( 'body' ) . append ( 'div' ) . attr ( 'class' , styles . tooltip ) . attr ( 'id' , 'c-tooltip' ) . style ( 'opacity' , 0 ) ;
449464 this . cfdLine = this . chartArea
450465 . append ( 'line' )
451- . attr ( 'id' , 'cfd -line' )
466+ . attr ( 'id' , ` ${ this . chartName } -line` )
452467 . attr ( 'stroke' , 'black' )
453468 . attr ( 'y1' , 0 )
454469 . attr ( 'y2' , y )
@@ -551,8 +566,8 @@ class CFDRenderer extends UIControlsRenderer {
551566 return ; // Exit the function if metrics are already enabled
552567 }
553568 this . #areMetricsEnabled = true ;
554- this . chartArea . on ( 'mousemove' , ( event ) => this . #handleMouseEvent( event , 'cfd -mousemove' ) ) ;
555- this . chartArea . on ( 'click' , ( event ) => this . #handleMouseEvent( event , 'cfd -click' ) ) ;
569+ this . chartArea . on ( 'mousemove' , ( event ) => this . #handleMouseEvent( event , ` ${ this . chartName } -mousemove` ) ) ;
570+ this . chartArea . on ( 'click' , ( event ) => this . #handleMouseEvent( event , ` ${ this . chartName } -click` ) ) ;
556571 this . #setupMouseLeaveHandler( ) ;
557572 }
558573
@@ -566,7 +581,7 @@ class CFDRenderer extends UIControlsRenderer {
566581 #handleMouseEvent( event , eventName ) {
567582 if ( this . #areMetricsEnabled) {
568583 this . #removeMetricsLines( ) ;
569- const coords = d3 . pointer ( event , d3 . select ( '#cfd -area' ) . node ( ) ) ;
584+ const coords = d3 . pointer ( event , d3 . select ( `# ${ this . chartName } -area` ) . node ( ) ) ;
570585 const xPosition = coords [ 0 ] ;
571586 const yPosition = coords [ 1 ] ;
572587
@@ -577,12 +592,13 @@ class CFDRenderer extends UIControlsRenderer {
577592
578593 const date = this . currentXScale . invert ( xPosition ) ;
579594 const cumulativeCountOfWorkItems = this . currentYScale . invert ( yPosition ) ;
580- const excludeCycleTime = eventName === 'scatterplot- mousemove';
595+ const excludeCycleTime = eventName . includes ( ' mousemove') && ! eventName . includes ( this . chartName ) ;
581596
582597 const metrics = this . computeMetrics ( date , Math . floor ( cumulativeCountOfWorkItems ) , excludeCycleTime ) ;
598+
583599 this . #drawMetricLines( metrics . metricLinesData ) ;
584600 delete metrics . metricLinesData ;
585- const observation = this . observations ?. data ?. find ( ( o ) => o . chart_type === 'CFD' && areDatesEqual ( o . date_from , date ) ) ;
601+ const observation = this . observations ?. data ?. find ( ( o ) => o . chart_type === this . chartType && areDatesEqual ( o . date_from , date ) ) ;
586602 const data = {
587603 date : date ,
588604 lineX : xPosition ,
@@ -624,13 +640,14 @@ class CFDRenderer extends UIControlsRenderer {
624640 const leadTimeDateBefore = this . #computeLeadTimeDate( currentDeliveredItems , filteredData ) ;
625641 let { cycleTimeDateBefore, averageCycleTime, biggestCycleTime, currentStateCumulativeCount, cycleTimesByState } =
626642 this . computeCycleTimeAndLeadTimeMetrics ( currentDataEntry , filteredData , currentDate , currentStateIndex ) ;
627- const averageLeadTime = leadTimeDateBefore ? Math . floor ( calculateDaysBetweenDates ( leadTimeDateBefore , currentDate ) ) : null ;
643+ const averageLeadTime = leadTimeDateBefore
644+ ? Math . floor ( calculateDaysBetweenDates ( leadTimeDateBefore , currentDate ) . roundedDays )
645+ : null ;
628646 const noOfItemsBefore = this . #getNoOfItems( currentDataEntry , this . states [ this . states . indexOf ( 'delivered' ) ] ) ;
629647 const noOfItemsAfter = this . #getNoOfItems( currentDataEntry , this . states [ this . states . indexOf ( 'analysis_active' ) ] ) ;
630648
631649 const wip = noOfItemsAfter - noOfItemsBefore ;
632650 const throughput = averageLeadTime ? parseFloat ( ( wip / averageLeadTime ) . toFixed ( 1 ) ) : undefined ;
633-
634651 excludeCycleTime && ( averageCycleTime = null ) ;
635652 return {
636653 currentState : this . states [ currentStateIndex ] ,
@@ -664,7 +681,9 @@ class CFDRenderer extends UIControlsRenderer {
664681 for ( let i = 0 ; i < this . states . length - 1 ; i ++ ) {
665682 let stateCumulativeCount = this . #getNoOfItems( currentDataEntry , this . states [ i ] ) ;
666683 let cycleTimeDate = this . #computeCycleTimeDate( stateCumulativeCount , i , filteredData ) ;
667- cycleTimesByState [ this . states [ i + 1 ] ] = cycleTimeDate ? Math . floor ( calculateDaysBetweenDates ( cycleTimeDate , currentDate ) ) : null ;
684+ cycleTimesByState [ this . states [ i + 1 ] ] = cycleTimeDate
685+ ? Math . floor ( calculateDaysBetweenDates ( cycleTimeDate , currentDate ) . roundedDays )
686+ : null ;
668687 if ( cycleTimesByState [ this . states [ i + 1 ] ] > biggestCycleTime ) {
669688 biggestCycleTime = cycleTimesByState [ this . states [ i + 1 ] ] ;
670689 }
0 commit comments