@@ -2,7 +2,7 @@ import * as d3 from 'd3';
2
2
import _ from 'lodash' ;
3
3
import { Duration } from 'luxon' ;
4
4
5
- import { BAR_HEIGHT , DIMENSION } from './constants' ;
5
+ import { BAR_HEIGHT , DIMENSION , HOVERED_RECT_OPACITY } from './constants' ;
6
6
import { EPOCH_DURATION_MS , TRANSITION_TIME_MS , STAGES_ORDERED } from '../constants' ;
7
7
8
8
import '../style.css' ;
@@ -11,6 +11,8 @@ export const createTimelineChartCallbacks = (g, xTime, xTimeAxis, color, tooltip
11
11
Object ( {
12
12
fromInitial : ( ) => {
13
13
const annotationRects = g . selectAll ( '.rect-stacked' ) . interrupt ( ) ;
14
+ g . selectAll ( 'text.proportion' ) . remove ( ) ;
15
+ d3 . selectAll ( 'div.tooltip' ) . style ( 'opacity' , 0 ) ;
14
16
15
17
setAttrOnAnnotationRects ( annotationRects , xTime , 0 , color , tooltip ) ;
16
18
@@ -21,8 +23,9 @@ export const createTimelineChartCallbacks = (g, xTime, xTimeAxis, color, tooltip
21
23
} ,
22
24
fromInstance : ( ) => {
23
25
const annotationRects = g . selectAll ( '.rect-stacked' ) . interrupt ( ) ;
24
-
26
+ g . selectAll ( 'text.proportion' ) . remove ( ) ;
25
27
g . selectAll ( '.y.visualization__axis' ) . remove ( ) ;
28
+ d3 . selectAll ( 'div.tooltip' ) . style ( 'opacity' , 0 ) ;
26
29
27
30
setAttrOnAnnotationRects ( annotationRects , xTime , 0 , color , tooltip ) ;
28
31
@@ -34,67 +37,65 @@ export const createInstanceChartCallbacks = (g, data, xTime, xTimeAxis, yAxis, c
34
37
Object ( {
35
38
fromTimeline : ( ) => {
36
39
const annotationRects = g . selectAll ( '.rect-stacked' ) . interrupt ( ) ;
40
+ g . selectAll ( 'text.proportion' ) . remove ( ) ;
41
+ d3 . selectAll ( 'div.tooltip' ) . style ( 'opacity' , 0 ) ;
37
42
38
43
createVerticalAxis ( g , yAxis , color ) ;
39
44
transitionHorizontalAxis ( g , STAGES_ORDERED . length * BAR_HEIGHT ) ;
40
- setAttrOnAnnotationRects ( annotationRects , xTime , getVerticalPositionCallback , color , tooltip ) ;
45
+ setAttrOnAnnotationRects ( annotationRects , xTime , getVerticalPositionCallback ( ) , color , tooltip ) ;
41
46
} ,
42
47
fromBarChart : ( ) => {
43
48
const annotationRects = g . selectAll ( '.rect-stacked' ) . interrupt ( ) ;
44
49
const xProportionCallback = getOffsetSleepStageProportionCallback ( data ) ;
45
50
annotationRects . attr ( 'x' , xProportionCallback ) . attr ( 'width' , ( { end, start } ) => xTime ( end ) - xTime ( start ) ) ;
46
51
47
52
g . selectAll ( 'text.proportion' ) . remove ( ) ;
53
+ d3 . selectAll ( 'div.tooltip' ) . style ( 'opacity' , 0 ) ;
48
54
49
55
g . select ( '.x.visualization__axis' ) . interrupt ( ) . transition ( ) . call ( xTimeAxis ) ;
50
56
transitionHorizontalAxis ( g , STAGES_ORDERED . length * BAR_HEIGHT ) ;
51
57
52
- setAttrOnAnnotationRects ( annotationRects , xTime , getVerticalPositionCallback , color , tooltip ) ;
58
+ setAttrOnAnnotationRects ( annotationRects , xTime , getVerticalPositionCallback ( ) , color , tooltip ) ;
53
59
} ,
54
60
} ) ;
55
61
56
62
export const createBarChartCallbacks = ( g , data , xAxisLinear , yAxis , color , tip ) =>
57
63
Object ( {
58
64
fromInstance : ( ) => {
59
- const { firstStageIndexes, stageTimeProportions } = data ;
60
65
const annotationRects = g . selectAll ( '.rect-stacked' ) . interrupt ( ) ;
61
66
const xProportionCallback = getOffsetSleepStageProportionCallback ( data ) ;
62
67
68
+ d3 . selectAll ( 'div.tooltip' ) . style ( 'opacity' , 0 ) ;
63
69
g . select ( '.x.visualization__axis' ) . transition ( ) . call ( xAxisLinear ) ;
64
70
transitionHorizontalAxis ( g , STAGES_ORDERED . length * BAR_HEIGHT ) ;
65
71
66
- setTooltip ( annotationRects , tip )
72
+ setTooltip ( annotationRects , tip , getVerticalPositionCallback ( 20 ) )
67
73
. transition ( )
68
74
. duration ( TRANSITION_TIME_MS )
69
- . attr ( 'y' , getVerticalPositionCallback )
75
+ . attr ( 'y' , getVerticalPositionCallback ( ) )
70
76
. attr ( 'x' , xProportionCallback )
71
- . on ( 'end' , ( ) => {
72
- // Only keep the first rectangle of each stage to be visible
73
- g . selectAll ( '.rect-stacked' )
74
- . attr ( 'x' , 0 )
75
- . attr ( 'width' , getFirstRectangleProportionWidthCallback ( firstStageIndexes , stageTimeProportions ) ) ;
76
- createProportionLabels ( g , data ) ;
77
- } ) ;
77
+ . on ( 'end' , ( ) => setFirstRectangleToBeAsWideAsStageProportion ( data , g ) ) ;
78
78
} ,
79
79
fromStackedBarChart : ( ) => {
80
80
const annotationRects = g . selectAll ( '.rect-stacked' ) . interrupt ( ) ;
81
81
g . selectAll ( 'text.proportion' ) . remove ( ) ;
82
+ d3 . selectAll ( 'div.tooltip' ) . style ( 'opacity' , 0 ) ;
82
83
83
84
createVerticalAxis ( g , yAxis , color ) ;
84
85
transitionHorizontalAxis ( g , STAGES_ORDERED . length * BAR_HEIGHT ) ;
85
86
86
- annotationRects
87
+ setTooltip ( annotationRects , tip , getVerticalPositionCallback ( 20 ) )
87
88
. transition ( )
88
89
. duration ( TRANSITION_TIME_MS / 2 )
89
90
. attr ( 'y' , ( d ) => BAR_HEIGHT * STAGES_ORDERED . indexOf ( d . stage ) )
90
91
. transition ( )
91
92
. duration ( TRANSITION_TIME_MS / 2 )
92
93
. attr ( 'x' , 0 )
93
- . on ( 'end' , ( ) => createProportionLabels ( g , data ) ) ;
94
+ . on ( 'end' , ( ) => setFirstRectangleToBeAsWideAsStageProportion ( data , g ) ) ;
94
95
} ,
95
96
} ) ;
96
97
97
- export const createStackedBarChartCallbacks = ( g , data ) =>
98
+ export const createStackedBarChartCallbacks = ( g , data , tip ) =>
98
99
Object ( {
99
100
fromBarChart : ( ) => {
100
101
const { annotations, firstStageIndexes, stageTimeProportions, epochs } = data ;
@@ -103,6 +104,8 @@ export const createStackedBarChartCallbacks = (g, data) =>
103
104
( getCumulativeProportionOfNightAtStart ( stage , stageTimeProportions ) + stageTimeProportions [ stage ] / 2 ) *
104
105
DIMENSION . WIDTH ;
105
106
const annotationRects = g . selectAll ( '.rect-stacked' ) . interrupt ( ) ;
107
+ setTooltip ( annotationRects , tip , 0 ) ;
108
+ d3 . selectAll ( 'div.tooltip' ) . style ( 'opacity' , 0 ) ;
106
109
107
110
g . selectAll ( '.y.visualization__axis' ) . remove ( ) ;
108
111
g . selectAll ( 'text.proportion' ) . remove ( ) ;
@@ -137,28 +140,42 @@ export const createStackedBarChartCallbacks = (g, data) =>
137
140
} ,
138
141
} ) ;
139
142
140
- const setAttrOnAnnotationRects = ( annotationRects , x , yPosition , color , tooltip ) =>
141
- setTooltip ( annotationRects , tooltip )
143
+ const setAttrOnAnnotationRects = ( annotationRects , x , yBarPosition , color , tooltip ) =>
144
+ setTooltip ( annotationRects , tooltip , yBarPosition )
142
145
. attr ( 'height' , BAR_HEIGHT )
143
146
. transition ( )
144
147
. duration ( TRANSITION_TIME_MS )
145
148
. attr ( 'x' , ( { start } ) => x ( start ) )
146
- . attr ( 'y' , yPosition )
149
+ . attr ( 'y' , yBarPosition )
147
150
. attr ( 'width' , ( { end, start } ) => x ( end ) - x ( start ) )
148
151
. attr ( 'fill' , ( { stage } ) => color ( stage ) ) ;
149
152
150
- const setTooltip = ( element , tooltip ) =>
153
+ const setFirstRectangleToBeAsWideAsStageProportion = ( data , g ) => {
154
+ const { firstStageIndexes, stageTimeProportions } = data ;
155
+
156
+ // Only keep the first rectangle of each stage to be visible
157
+ g . selectAll ( '.rect-stacked' )
158
+ . attr ( 'x' , 0 )
159
+ . attr ( 'width' , getFirstRectangleProportionWidthCallback ( firstStageIndexes , stageTimeProportions ) ) ;
160
+ createProportionLabels ( g , data ) ;
161
+ } ;
162
+
163
+ const setTooltip = ( element , tooltip , y ) =>
151
164
element
152
- . on ( 'mouseover' , function ( d ) {
153
- tooltip . show ( d , this ) ;
154
- d3 . select ( this ) . style ( 'opacity' , 0.8 ) ;
165
+ . on ( 'mouseover' , function ( ) {
166
+ tooltip . mouseover ( ) ;
167
+ d3 . select ( this ) . style ( 'stroke' , 'black' ) . style ( 'opacity' , HOVERED_RECT_OPACITY ) ;
168
+ } )
169
+ . on ( 'mousemove' , function ( d ) {
170
+ tooltip . mousemove ( d , d3 . mouse ( this ) , `${ y === 0 ? 0 : y ( d ) } px` ) ;
155
171
} )
156
172
. on ( 'mouseout' , function ( ) {
157
- tooltip . hide ( ) ;
158
- d3 . select ( this ) . style ( 'opacity' , 1 ) ;
173
+ tooltip . mouseleave ( ) ;
174
+ d3 . select ( this ) . style ( 'stroke' , 'none' ) . style ( ' opacity', 1 ) ;
159
175
} ) ;
160
176
161
- const getVerticalPositionCallback = ( d ) => BAR_HEIGHT * STAGES_ORDERED . indexOf ( d . stage ) ;
177
+ const getVerticalPositionCallback = ( cardOffset = 0 ) => ( d ) =>
178
+ BAR_HEIGHT * STAGES_ORDERED . indexOf ( d . stage ) + cardOffset ;
162
179
163
180
const getFirstRectangleProportionWidthCallback = ( firstStageIndexes , stageTimeProportions ) => ( { stage } , i ) =>
164
181
i === firstStageIndexes [ stage ] ? stageTimeProportions [ stage ] * DIMENSION . WIDTH : 0 ;
0 commit comments