9
9
'use strict' ;
10
10
11
11
var Axes = require ( '../../plots/cartesian/axes' ) ;
12
+ var Lib = require ( '../../lib' ) ;
12
13
var Fx = require ( '../../components/fx' ) ;
13
14
var Color = require ( '../../components/color' ) ;
14
15
var fillHoverText = require ( '../scatter/fill_hover_text' ) ;
@@ -18,32 +19,48 @@ var DIRSYMBOL = {
18
19
decreasing : '▼'
19
20
} ;
20
21
21
- module . exports = function hoverPoints ( pointData , xval , yval , hovermode ) {
22
+ function hoverPoints ( pointData , xval , yval , hovermode ) {
23
+ var cd = pointData . cd ;
24
+ var trace = cd [ 0 ] . trace ;
25
+ var hoveron = trace . hoveron ;
26
+
27
+ if ( hoveron . indexOf ( 'ohlc' ) !== - 1 ) {
28
+ return hoverOnOhlc ( pointData , xval , yval , hovermode ) ;
29
+ }
30
+ else if ( hoveron . indexOf ( 'points' ) !== - 1 ) {
31
+ return hoverOnPoints ( pointData , xval , yval , hovermode ) ;
32
+ }
33
+
34
+ return [ ] ;
35
+ }
36
+
37
+ function getClosestPoint ( pointData , xval , yval , hovermode ) {
22
38
var cd = pointData . cd ;
23
39
var xa = pointData . xa ;
24
- var ya = pointData . ya ;
25
40
var trace = cd [ 0 ] . trace ;
26
41
var t = cd [ 0 ] . t ;
27
42
28
43
var type = trace . type ;
29
44
var minAttr = type === 'ohlc' ? 'l' : 'min' ;
30
45
var maxAttr = type === 'ohlc' ? 'h' : 'max' ;
31
46
47
+ var hoverPseudoDistance , spikePseudoDistance ;
48
+
32
49
// potentially shift xval for grouped candlesticks
33
50
var centerShift = t . bPos || 0 ;
34
- var x0 = xval - centerShift ;
51
+ var shiftPos = function ( di ) { return di . pos + centerShift - xval ; } ;
35
52
36
53
// ohlc and candlestick call displayHalfWidth different things...
37
54
var displayHalfWidth = t . bdPos || t . tickLen ;
38
55
var hoverHalfWidth = t . wHover ;
39
56
40
- // if two items are overlaying, let the narrowest one win
57
+ // if two figures are overlaying, let the narrowest one win
41
58
var pseudoDistance = Math . min ( 1 , displayHalfWidth / Math . abs ( xa . r2c ( xa . range [ 1 ] ) - xa . r2c ( xa . range [ 0 ] ) ) ) ;
42
- var hoverPseudoDistance = pointData . maxHoverDistance - pseudoDistance ;
43
- var spikePseudoDistance = pointData . maxSpikeDistance - pseudoDistance ;
59
+ hoverPseudoDistance = pointData . maxHoverDistance - pseudoDistance ;
60
+ spikePseudoDistance = pointData . maxSpikeDistance - pseudoDistance ;
44
61
45
62
function dx ( di ) {
46
- var pos = di . pos - x0 ;
63
+ var pos = shiftPos ( di ) ;
47
64
return Fx . inbox ( pos - hoverHalfWidth , pos + hoverHalfWidth , hoverPseudoDistance ) ;
48
65
}
49
66
@@ -52,18 +69,13 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
52
69
}
53
70
54
71
function dxy ( di ) { return ( dx ( di ) + dy ( di ) ) / 2 ; }
72
+
55
73
var distfn = Fx . getDistanceFunction ( hovermode , dx , dy , dxy ) ;
56
74
Fx . getClosest ( cd , distfn , pointData ) ;
57
75
58
- // skip the rest (for this trace) if we didn't find a close point
59
- if ( pointData . index === false ) return [ ] ;
60
-
61
- // we don't make a calcdata point if we're missing any piece (x/o/h/l/c)
62
- // so we need to fix the index here to point to the data arrays
63
- var cdIndex = pointData . index ;
64
- var di = cd [ cdIndex ] ;
65
- var i = pointData . index = di . i ;
76
+ if ( pointData . index === false ) return null ;
66
77
78
+ var di = cd [ pointData . index ] ;
67
79
var dir = di . dir ;
68
80
var container = trace [ dir ] ;
69
81
var lc = container . line . color ;
@@ -79,6 +91,81 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
79
91
pointData . spikeDistance = dxy ( di ) * spikePseudoDistance / hoverPseudoDistance ;
80
92
pointData . xSpike = xa . c2p ( di . pos , true ) ;
81
93
94
+ return pointData ;
95
+ }
96
+
97
+ function hoverOnOhlc ( pointData , xval , yval , hovermode ) {
98
+ var cd = pointData . cd ;
99
+ var ya = pointData . ya ;
100
+ var trace = cd [ 0 ] . trace ;
101
+ var t = cd [ 0 ] . t ;
102
+ var closeBoxData = [ ] ;
103
+
104
+ var closestPoint = getClosestPoint ( pointData , xval , yval , hovermode ) ;
105
+ // skip the rest (for this trace) if we didn't find a close point
106
+ if ( ! closestPoint ) return [ ] ;
107
+
108
+ var hoverinfo = trace . hoverinfo ;
109
+ var hoverParts = hoverinfo . split ( '+' ) ;
110
+ var isAll = hoverinfo === 'all' ;
111
+ var hasY = isAll || hoverParts . indexOf ( 'y' ) !== - 1 ;
112
+
113
+ // similar to hoverOnPoints, we return nothing
114
+ // if all or y is not present.
115
+ if ( ! hasY ) return [ ] ;
116
+
117
+ var attrs = [ 'high' , 'open' , 'close' , 'low' ] ;
118
+
119
+ // several attributes can have the same y-coordinate. We will
120
+ // bunch them together in a single text block. For this, we keep
121
+ // a dictionary mapping y-coord -> point data.
122
+ var usedVals = { } ;
123
+
124
+ for ( var i = 0 ; i < attrs . length ; i ++ ) {
125
+ var attr = attrs [ i ] ;
126
+
127
+ var val = trace [ attr ] [ closestPoint . index ] ;
128
+ var valPx = ya . c2p ( val , true ) ;
129
+ var pointData2 ;
130
+ if ( val in usedVals ) {
131
+ pointData2 = usedVals [ val ] ;
132
+ pointData2 . yLabel += '<br>' + t . labels [ attr ] + Axes . hoverLabelText ( ya , val ) ;
133
+ }
134
+ else {
135
+ // copy out to a new object for each new y-value to label
136
+ pointData2 = Lib . extendFlat ( { } , closestPoint ) ;
137
+
138
+ pointData2 . y0 = pointData2 . y1 = valPx ;
139
+ pointData2 . yLabelVal = val ;
140
+ pointData2 . yLabel = t . labels [ attr ] + Axes . hoverLabelText ( ya , val ) ;
141
+
142
+ pointData2 . name = '' ;
143
+
144
+ closeBoxData . push ( pointData2 ) ;
145
+ usedVals [ val ] = pointData2 ;
146
+ }
147
+ }
148
+
149
+ return closeBoxData ;
150
+ }
151
+
152
+ function hoverOnPoints ( pointData , xval , yval , hovermode ) {
153
+ var cd = pointData . cd ;
154
+ var ya = pointData . ya ;
155
+ var trace = cd [ 0 ] . trace ;
156
+ var t = cd [ 0 ] . t ;
157
+
158
+ var closestPoint = getClosestPoint ( pointData , xval , yval , hovermode ) ;
159
+ // skip the rest (for this trace) if we didn't find a close point
160
+ if ( ! closestPoint ) return [ ] ;
161
+
162
+ // we don't make a calcdata point if we're missing any piece (x/o/h/l/c)
163
+ // so we need to fix the index here to point to the data arrays
164
+ var cdIndex = closestPoint . index ;
165
+ var di = cd [ cdIndex ] ;
166
+ var i = closestPoint . index = di . i ;
167
+ var dir = di . dir ;
168
+
82
169
function getLabelLine ( attr ) {
83
170
return t . labels [ attr ] + Axes . hoverLabelText ( ya , trace [ attr ] [ i ] ) ;
84
171
}
@@ -99,11 +186,17 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
99
186
100
187
// don't make .yLabelVal or .text, since we're managing hoverinfo
101
188
// put it all in .extraText
102
- pointData . extraText = textParts . join ( '<br>' ) ;
189
+ closestPoint . extraText = textParts . join ( '<br>' ) ;
103
190
104
191
// this puts the label *and the spike* at the midpoint of the box, ie
105
192
// halfway between open and close, not between high and low.
106
- pointData . y0 = pointData . y1 = ya . c2p ( di . yc , true ) ;
193
+ closestPoint . y0 = closestPoint . y1 = ya . c2p ( di . yc , true ) ;
194
+
195
+ return [ closestPoint ] ;
196
+ }
107
197
108
- return [ pointData ] ;
198
+ module . exports = {
199
+ hoverPoints : hoverPoints ,
200
+ hoverOnOhlc : hoverOnOhlc ,
201
+ hoverOnPoints : hoverOnPoints
109
202
} ;
0 commit comments