@@ -232,7 +232,13 @@ function _hover(gd, evt, subplot, noHoverEvent) {
232
232
xval ,
233
233
yval ,
234
234
pointData ,
235
- closedataPreviousLength ;
235
+ closedataPreviousLength ,
236
+
237
+ // crosslinePoints: the set of candidate points we've found to draw crosslines to
238
+ crosslinePoints = {
239
+ hLinePoint : null ,
240
+ vLinePoint : null
241
+ } ;
236
242
237
243
// Figure out what we're hovering on:
238
244
// mouse location or user-supplied data
@@ -402,10 +408,60 @@ function _hover(gd, evt, subplot, noHoverEvent) {
402
408
hoverData . splice ( 0 , closedataPreviousLength ) ;
403
409
distance = hoverData [ 0 ] . distance ;
404
410
}
411
+
412
+ var showSpikes = fullLayout . xaxis && fullLayout . xaxis . showspikes && fullLayout . yaxis && fullLayout . yaxis . showspikes ;
413
+ var showCrosslines = fullLayout . xaxis && fullLayout . xaxis . showcrossline || fullLayout . yaxis && fullLayout . yaxis . showcrossline ;
414
+
415
+ if ( fullLayout . _has ( 'cartesian' ) && showCrosslines && ! ( showSpikes && hovermode === 'closest' ) ) {
416
+ // Now find the points for the crosslines.
417
+ if ( fullLayout . yaxis . showcrossline ) {
418
+ crosslinePoints . hLinePoint = findCrosslinePoint ( pointData , xval , yval , 'y' , crosslinePoints . hLinePoint ) ;
419
+ }
420
+ if ( fullLayout . xaxis . showcrossline ) {
421
+ crosslinePoints . vLinePoint = findCrosslinePoint ( pointData , xval , yval , 'x' , crosslinePoints . vLinePoint ) ;
422
+ }
423
+ }
405
424
}
406
425
407
- // nothing left: remove all labels and quit
408
- if ( hoverData . length === 0 ) return dragElement . unhoverRaw ( gd , evt ) ;
426
+ function findCrosslinePoint ( pointData , xval , yval , mode , endPoint ) {
427
+ var resultPoint = endPoint ;
428
+ pointData . distance = Infinity ;
429
+ pointData . index = false ;
430
+ var closestPoints = trace . _module . hoverPoints ( pointData , xval , yval , mode ) ;
431
+ if ( closestPoints ) {
432
+ var closestPt = closestPoints [ 0 ] ;
433
+ if ( isNumeric ( closestPt . x0 ) && isNumeric ( closestPt . y0 ) ) {
434
+ var tmpPoint = {
435
+ xa : closestPt . xa ,
436
+ ya : closestPt . ya ,
437
+ x0 : closestPt . x0 ,
438
+ x1 : closestPt . x1 ,
439
+ y0 : closestPt . y0 ,
440
+ y1 : closestPt . y1 ,
441
+ distance : closestPt . distance ,
442
+ curveNumber : closestPt . trace . index ,
443
+ pointNumber : closestPt . index
444
+ } ;
445
+ if ( ! resultPoint || ( resultPoint . distance > tmpPoint . distance ) ) {
446
+ resultPoint = tmpPoint ;
447
+ }
448
+ }
449
+ }
450
+ return resultPoint ;
451
+ }
452
+
453
+ // if hoverData is empty check for the crosslines to draw and quit if there are none
454
+ if ( hoverData . length === 0 ) {
455
+ var result = dragElement . unhoverRaw ( gd , evt ) ;
456
+ if ( fullLayout . _has ( 'cartesian' ) && ( ( crosslinePoints . hLinePoint !== null ) || ( crosslinePoints . vLinePoint !== null ) ) ) {
457
+ createCrosslines ( crosslinePoints , fullLayout ) ;
458
+ }
459
+ return result ;
460
+ }
461
+
462
+ if ( fullLayout . _has ( 'cartesian' ) ) {
463
+ createCrosslines ( crosslinePoints , fullLayout ) ;
464
+ }
409
465
410
466
hoverData . sort ( function ( d1 , d2 ) { return d1 . distance - d2 . distance ; } ) ;
411
467
@@ -1089,6 +1145,77 @@ function cleanPoint(d, hovermode) {
1089
1145
return d ;
1090
1146
}
1091
1147
1148
+ function createCrosslines ( hoverData , fullLayout ) {
1149
+ var showXSpikeline = fullLayout . xaxis && fullLayout . xaxis . showspikes ;
1150
+ var showYSpikeline = fullLayout . yaxis && fullLayout . yaxis . showspikes ;
1151
+ var showH = fullLayout . yaxis && fullLayout . yaxis . showcrossline ;
1152
+ var showV = fullLayout . xaxis && fullLayout . xaxis . showcrossline ;
1153
+ var container = fullLayout . _hoverlayer ;
1154
+ var hovermode = fullLayout . hovermode ;
1155
+ if ( ! ( showV || showH ) || ( showXSpikeline && showYSpikeline && hovermode === 'closest' ) ) return ;
1156
+ var hLinePoint ,
1157
+ vLinePoint ,
1158
+ xa ,
1159
+ ya ,
1160
+ hLinePointY ,
1161
+ vLinePointX ;
1162
+
1163
+ // Remove old crossline items
1164
+ container . selectAll ( '.crossline' ) . remove ( ) ;
1165
+
1166
+ var contrastColor = Color . combine ( fullLayout . plot_bgcolor , fullLayout . paper_bgcolor ) ;
1167
+ var dfltCrosslineColor = Color . contrast ( contrastColor ) ;
1168
+
1169
+ // do not draw a crossline if there is a spikeline
1170
+ if ( showV && ! ( showXSpikeline && hovermode === 'closest' ) ) {
1171
+ vLinePoint = hoverData . vLinePoint ;
1172
+ xa = vLinePoint . xa ;
1173
+ vLinePointX = xa . _offset + ( vLinePoint . x0 + vLinePoint . x1 ) / 2 ;
1174
+
1175
+ var xThickness = xa . crosslinethickness ;
1176
+ var xDash = xa . crosslinedash ;
1177
+ var xColor = xa . crosslinecolor || dfltCrosslineColor ;
1178
+
1179
+ // Foreground vertical line (to x-axis)
1180
+ container . insert ( 'line' , ':first-child' )
1181
+ . attr ( {
1182
+ 'x1' : vLinePointX ,
1183
+ 'x2' : vLinePointX ,
1184
+ 'y1' : xa . _counterSpan [ 0 ] ,
1185
+ 'y2' : xa . _counterSpan [ 1 ] ,
1186
+ 'stroke-width' : xThickness ,
1187
+ 'stroke' : xColor ,
1188
+ 'stroke-dasharray' : Drawing . dashStyle ( xDash , xThickness )
1189
+ } )
1190
+ . classed ( 'crossline' , true )
1191
+ . classed ( 'crisp' , true ) ;
1192
+ }
1193
+
1194
+ if ( showH && ! ( showYSpikeline && hovermode === 'closest' ) ) {
1195
+ hLinePoint = hoverData . hLinePoint ;
1196
+ ya = hLinePoint . ya ;
1197
+ hLinePointY = ya . _offset + ( hLinePoint . y0 + hLinePoint . y1 ) / 2 ;
1198
+
1199
+ var yThickness = ya . crosslinethickness ;
1200
+ var yDash = ya . crosslinedash ;
1201
+ var yColor = ya . crosslinecolor || dfltCrosslineColor ;
1202
+
1203
+ // Foreground horizontal line (to y-axis)
1204
+ container . insert ( 'line' , ':first-child' )
1205
+ . attr ( {
1206
+ 'x1' : ya . _counterSpan [ 0 ] ,
1207
+ 'x2' : ya . _counterSpan [ 1 ] ,
1208
+ 'y1' : hLinePointY ,
1209
+ 'y2' : hLinePointY ,
1210
+ 'stroke-width' : yThickness ,
1211
+ 'stroke' : yColor ,
1212
+ 'stroke-dasharray' : Drawing . dashStyle ( yDash , yThickness )
1213
+ } )
1214
+ . classed ( 'crossline' , true )
1215
+ . classed ( 'crisp' , true ) ;
1216
+ }
1217
+ }
1218
+
1092
1219
function createSpikelines ( hoverData , opts ) {
1093
1220
var hovermode = opts . hovermode ;
1094
1221
var container = opts . container ;
0 commit comments