@@ -14,94 +14,167 @@ var Fx = require('../../components/fx');
14
14
var Color = require ( '../../components/color' ) ;
15
15
16
16
module . exports = function hoverPoints ( pointData , xval , yval , hovermode ) {
17
- // closest mode: handicap box plots a little relative to others
18
- var cd = pointData . cd ,
19
- trace = cd [ 0 ] . trace ,
20
- t = cd [ 0 ] . t ,
21
- xa = pointData . xa ,
22
- ya = pointData . ya ,
23
- closeData = [ ] ,
24
- dx , dy , distfn , boxDelta ,
25
- posLetter , posAxis ,
26
- val , valLetter , valAxis ;
27
-
28
- // adjust inbox w.r.t. to calculate box size
29
- boxDelta = ( hovermode === 'closest' ) ? 2.5 * t . bdPos : t . bdPos ;
30
-
31
- if ( trace . orientation === 'h' ) {
32
- dx = function ( di ) {
33
- return Fx . inbox ( di . min - xval , di . max - xval ) ;
34
- } ;
35
- dy = function ( di ) {
36
- var pos = di . pos + t . bPos - yval ;
37
- return Fx . inbox ( pos - boxDelta , pos + boxDelta ) ;
38
- } ;
39
- posLetter = 'y' ;
40
- posAxis = ya ;
41
- valLetter = 'x' ;
42
- valAxis = xa ;
43
- } else {
44
- dx = function ( di ) {
45
- var pos = di . pos + t . bPos - xval ;
46
- return Fx . inbox ( pos - boxDelta , pos + boxDelta ) ;
47
- } ;
48
- dy = function ( di ) {
49
- return Fx . inbox ( di . min - yval , di . max - yval ) ;
50
- } ;
51
- posLetter = 'x' ;
52
- posAxis = xa ;
53
- valLetter = 'y' ;
54
- valAxis = ya ;
55
- }
17
+ var cd = pointData . cd ;
18
+ var xa = pointData . xa ;
19
+ var ya = pointData . ya ;
20
+
21
+ var trace = cd [ 0 ] . trace ;
22
+ var hoveron = trace . hoveron ;
23
+ var marker = trace . marker || { } ;
24
+
25
+ // output hover points array
26
+ var closeData = [ ] ;
27
+ // x/y/effective distance functions
28
+ var dx , dy , distfn ;
29
+ // orientation-specific fields
30
+ var posLetter , valLetter , posAxis , valAxis ;
31
+ // calcdata item
32
+ var di ;
33
+ // hover point item extended from pointData
34
+ var pointData2 ;
35
+ // loop indices
36
+ var i , j ;
37
+
38
+ if ( hoveron . indexOf ( 'boxes' ) !== - 1 ) {
39
+ var t = cd [ 0 ] . t ;
40
+
41
+ // closest mode: handicap box plots a little relative to others
42
+ // adjust inbox w.r.t. to calculate box size
43
+ var boxDelta = ( hovermode === 'closest' ) ? 2.5 * t . bdPos : t . bdPos ;
44
+
45
+ if ( trace . orientation === 'h' ) {
46
+ dx = function ( di ) {
47
+ return Fx . inbox ( di . min - xval , di . max - xval ) ;
48
+ } ;
49
+ dy = function ( di ) {
50
+ var pos = di . pos + t . bPos - yval ;
51
+ return Fx . inbox ( pos - boxDelta , pos + boxDelta ) ;
52
+ } ;
53
+ posLetter = 'y' ;
54
+ posAxis = ya ;
55
+ valLetter = 'x' ;
56
+ valAxis = xa ;
57
+ } else {
58
+ dx = function ( di ) {
59
+ var pos = di . pos + t . bPos - xval ;
60
+ return Fx . inbox ( pos - boxDelta , pos + boxDelta ) ;
61
+ } ;
62
+ dy = function ( di ) {
63
+ return Fx . inbox ( di . min - yval , di . max - yval ) ;
64
+ } ;
65
+ posLetter = 'x' ;
66
+ posAxis = xa ;
67
+ valLetter = 'y' ;
68
+ valAxis = ya ;
69
+ }
70
+
71
+ distfn = Fx . getDistanceFunction ( hovermode , dx , dy ) ;
72
+ Fx . getClosest ( cd , distfn , pointData ) ;
56
73
57
- distfn = Fx . getDistanceFunction ( hovermode , dx , dy ) ;
58
- Fx . getClosest ( cd , distfn , pointData ) ;
74
+ // skip the rest (for this trace) if we didn't find a close point
75
+ // and create the item(s) in closedata for this point
76
+ if ( pointData . index !== false ) {
77
+ di = cd [ pointData . index ] ;
59
78
60
- // skip the rest (for this trace) if we didn't find a close point
61
- if ( pointData . index === false ) return ;
79
+ var lc = trace . line . color ;
80
+ var mc = marker . color ;
62
81
63
- // create the item(s) in closedata for this point
82
+ if ( Color . opacity ( lc ) && trace . line . width ) pointData . color = lc ;
83
+ else if ( Color . opacity ( mc ) && trace . boxpoints ) pointData . color = mc ;
84
+ else pointData . color = trace . fillcolor ;
64
85
65
- // the closest data point
66
- var di = cd [ pointData . index ] ,
67
- lc = trace . line . color ,
68
- mc = ( trace . marker || { } ) . color ;
69
- if ( Color . opacity ( lc ) && trace . line . width ) pointData . color = lc ;
70
- else if ( Color . opacity ( mc ) && trace . boxpoints ) pointData . color = mc ;
71
- else pointData . color = trace . fillcolor ;
86
+ pointData [ posLetter + '0' ] = posAxis . c2p ( di . pos + t . bPos - t . bdPos , true ) ;
87
+ pointData [ posLetter + '1' ] = posAxis . c2p ( di . pos + t . bPos + t . bdPos , true ) ;
72
88
73
- pointData [ posLetter + '0' ] = posAxis . c2p ( di . pos + t . bPos - t . bdPos , true ) ;
74
- pointData [ posLetter + '1 ' ] = posAxis . c2p ( di . pos + t . bPos + t . bdPos , true ) ;
89
+ Axes . tickText ( posAxis , posAxis . c2l ( di . pos ) , 'hover' ) . text ;
90
+ pointData [ posLetter + 'LabelVal ' ] = di . pos ;
75
91
76
- Axes . tickText ( posAxis , posAxis . c2l ( di . pos ) , 'hover' ) . text ;
77
- pointData [ posLetter + 'LabelVal' ] = di . pos ;
92
+ // box plots: each "point" gets many labels
93
+ var usedVals = { } ;
94
+ var attrs = [ 'med' , 'min' , 'q1' , 'q3' , 'max' ] ;
78
95
79
- // box plots: each "point" gets many labels
80
- var usedVals = { } ,
81
- attrs = [ 'med' , 'min' , 'q1' , 'q3' , 'max' ] ,
82
- attr ,
83
- pointData2 ;
84
- if ( trace . boxmean ) attrs . push ( 'mean' ) ;
85
- if ( trace . boxpoints ) [ ] . push . apply ( attrs , [ 'lf' , 'uf' ] ) ;
96
+ if ( trace . boxmean ) attrs . push ( 'mean' ) ;
97
+ if ( trace . boxpoints ) [ ] . push . apply ( attrs , [ 'lf' , 'uf' ] ) ;
86
98
87
- for ( var i = 0 ; i < attrs . length ; i ++ ) {
88
- attr = attrs [ i ] ;
99
+ for ( i = 0 ; i < attrs . length ; i ++ ) {
100
+ var attr = attrs [ i ] ;
89
101
90
- if ( ! ( attr in di ) || ( di [ attr ] in usedVals ) ) continue ;
91
- usedVals [ di [ attr ] ] = true ;
102
+ if ( ! ( attr in di ) || ( di [ attr ] in usedVals ) ) continue ;
103
+ usedVals [ di [ attr ] ] = true ;
92
104
93
- // copy out to a new object for each value to label
94
- val = valAxis . c2p ( di [ attr ] , true ) ;
95
- pointData2 = Lib . extendFlat ( { } , pointData ) ;
96
- pointData2 [ valLetter + '0' ] = pointData2 [ valLetter + '1' ] = val ;
97
- pointData2 [ valLetter + 'LabelVal' ] = di [ attr ] ;
98
- pointData2 . attr = attr ;
105
+ // copy out to a new object for each value to label
106
+ var val = valAxis . c2p ( di [ attr ] , true ) ;
107
+ pointData2 = Lib . extendFlat ( { } , pointData ) ;
108
+ pointData2 [ valLetter + '0' ] = pointData2 [ valLetter + '1' ] = val ;
109
+ pointData2 [ valLetter + 'LabelVal' ] = di [ attr ] ;
110
+ pointData2 . attr = attr ;
99
111
100
- if ( attr === 'mean' && ( 'sd' in di ) && trace . boxmean === 'sd' ) {
101
- pointData2 [ valLetter + 'err' ] = di . sd ;
112
+ if ( attr === 'mean' && ( 'sd' in di ) && trace . boxmean === 'sd' ) {
113
+ pointData2 [ valLetter + 'err' ] = di . sd ;
114
+ }
115
+ // only keep name on the first item (median)
116
+ pointData . name = '' ;
117
+
118
+ closeData . push ( pointData2 ) ;
119
+ }
102
120
}
103
- pointData . name = '' ; // only keep name on the first item (median)
104
- closeData . push ( pointData2 ) ;
105
121
}
122
+
123
+ if ( hoveron . indexOf ( 'points' ) !== - 1 ) {
124
+ var xPx = xa . c2p ( xval ) ;
125
+ var yPx = ya . c2p ( yval ) ;
126
+
127
+ // do not take jitter into consideration in compare hover modes
128
+ var kx , ky ;
129
+ if ( hovermode === 'closest' ) {
130
+ kx = 'x' ;
131
+ ky = 'y' ;
132
+ } else {
133
+ kx = 'xh' ;
134
+ ky = 'yh' ;
135
+ }
136
+
137
+ dx = function ( di ) {
138
+ var rad = Math . max ( 3 , di . mrc || 0 ) ;
139
+ return Math . max ( Math . abs ( xa . c2p ( di [ kx ] ) - xPx ) - rad , 1 - 3 / rad ) ;
140
+ } ;
141
+ dy = function ( di ) {
142
+ var rad = Math . max ( 3 , di . mrc || 0 ) ;
143
+ return Math . max ( Math . abs ( ya . c2p ( di [ ky ] ) - yPx ) - rad , 1 - 3 / rad ) ;
144
+ } ;
145
+ distfn = Fx . getDistanceFunction ( hovermode , dx , dy ) ;
146
+
147
+ for ( i = 0 ; i < cd . length ; i ++ ) {
148
+ di = cd [ i ] ;
149
+
150
+ for ( j = 0 ; j < ( di . pts || [ ] ) . length ; j ++ ) {
151
+ var pt = di . pts [ j ] ;
152
+
153
+ var newDistance = distfn ( pt ) ;
154
+ if ( newDistance <= pointData . distance ) {
155
+ pointData . distance = newDistance ;
156
+
157
+ var xc = xa . c2p ( pt . x , true ) ;
158
+ var yc = ya . c2p ( pt . y , true ) ;
159
+ var rad = pt . mrc || 1 ;
160
+
161
+ pointData2 = Lib . extendFlat ( { } , pointData , {
162
+ // corresponds to index in x/y input data array
163
+ index : pt . i ,
164
+ color : marker . color ,
165
+ x0 : xc - rad ,
166
+ x1 : xc + rad ,
167
+ xLabelVal : pt . x ,
168
+ y0 : yc - rad ,
169
+ y1 : yc + rad ,
170
+ yLabelVal : pt . y
171
+ } ) ;
172
+
173
+ closeData . push ( pointData2 ) ;
174
+ }
175
+ }
176
+ }
177
+ }
178
+
106
179
return closeData ;
107
180
} ;
0 commit comments