99'use strict' ;
1010
1111var Axes = require ( '../../plots/cartesian/axes' ) ;
12+ var Lib = require ( '../../lib' ) ;
1213var Fx = require ( '../../components/fx' ) ;
1314var Color = require ( '../../components/color' ) ;
1415var fillHoverText = require ( '../scatter/fill_hover_text' ) ;
@@ -18,32 +19,48 @@ var DIRSYMBOL = {
1819 decreasing : '▼'
1920} ;
2021
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 ) {
2238 var cd = pointData . cd ;
2339 var xa = pointData . xa ;
24- var ya = pointData . ya ;
2540 var trace = cd [ 0 ] . trace ;
2641 var t = cd [ 0 ] . t ;
2742
2843 var type = trace . type ;
2944 var minAttr = type === 'ohlc' ? 'l' : 'min' ;
3045 var maxAttr = type === 'ohlc' ? 'h' : 'max' ;
3146
47+ var hoverPseudoDistance , spikePseudoDistance ;
48+
3249 // potentially shift xval for grouped candlesticks
3350 var centerShift = t . bPos || 0 ;
34- var x0 = xval - centerShift ;
51+ var shiftPos = function ( di ) { return di . pos + centerShift - xval ; } ;
3552
3653 // ohlc and candlestick call displayHalfWidth different things...
3754 var displayHalfWidth = t . bdPos || t . tickLen ;
3855 var hoverHalfWidth = t . wHover ;
3956
40- // if two items are overlaying, let the narrowest one win
57+ // if two figures are overlaying, let the narrowest one win
4158 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 ;
4461
4562 function dx ( di ) {
46- var pos = di . pos - x0 ;
63+ var pos = shiftPos ( di ) ;
4764 return Fx . inbox ( pos - hoverHalfWidth , pos + hoverHalfWidth , hoverPseudoDistance ) ;
4865 }
4966
@@ -52,18 +69,13 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
5269 }
5370
5471 function dxy ( di ) { return ( dx ( di ) + dy ( di ) ) / 2 ; }
72+
5573 var distfn = Fx . getDistanceFunction ( hovermode , dx , dy , dxy ) ;
5674 Fx . getClosest ( cd , distfn , pointData ) ;
5775
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 ;
6677
78+ var di = cd [ pointData . index ] ;
6779 var dir = di . dir ;
6880 var container = trace [ dir ] ;
6981 var lc = container . line . color ;
@@ -79,6 +91,81 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
7991 pointData . spikeDistance = dxy ( di ) * spikePseudoDistance / hoverPseudoDistance ;
8092 pointData . xSpike = xa . c2p ( di . pos , true ) ;
8193
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+
82169 function getLabelLine ( attr ) {
83170 return t . labels [ attr ] + Axes . hoverLabelText ( ya , trace [ attr ] [ i ] ) ;
84171 }
@@ -99,11 +186,17 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
99186
100187 // don't make .yLabelVal or .text, since we're managing hoverinfo
101188 // put it all in .extraText
102- pointData . extraText = textParts . join ( '<br>' ) ;
189+ closestPoint . extraText = textParts . join ( '<br>' ) ;
103190
104191 // this puts the label *and the spike* at the midpoint of the box, ie
105192 // 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+ }
107197
108- return [ pointData ] ;
198+ module . exports = {
199+ hoverPoints : hoverPoints ,
200+ hoverOnOhlc : hoverOnOhlc ,
201+ hoverOnPoints : hoverOnPoints
109202} ;
0 commit comments