@@ -24,6 +24,7 @@ var Registry = require('../../registry');
24
24
25
25
var helpers = require ( './helpers' ) ;
26
26
var constants = require ( './constants' ) ;
27
+ var getTraceColor = require ( '../../traces/scatter/get_trace_color' ) ;
27
28
28
29
// hover labels for multiple horizontal bars get tilted by some angle,
29
30
// then need to be offset differently if they overlap
@@ -234,8 +235,8 @@ function _hover(gd, evt, subplot, noHoverEvent) {
234
235
pointData ,
235
236
closedataPreviousLength ,
236
237
237
- // closestPoints : the set of candidate points we've found to draw spikes to
238
- closestPoints = {
238
+ // spikePoints : the set of candidate points we've found to draw spikes to
239
+ spikePoints = {
239
240
hLinePoint : null ,
240
241
vLinePoint : null
241
242
} ;
@@ -331,8 +332,8 @@ function _hover(gd, evt, subplot, noHoverEvent) {
331
332
// within one trace mode can sometimes be overridden
332
333
mode = hovermode ;
333
334
334
- var hoverdistance = fullLayout . hoverdistance ? fullLayout . hoverdistance === - 1 ? Infinity : fullLayout . hoverdistance : constants . MAXDIST ;
335
- var spikedistance = fullLayout . spikedistance ? fullLayout . spikedistance === - 1 ? Infinity : fullLayout . spikedistance : hoverdistance ;
335
+ var hoverdistance = fullLayout . hoverdistance ? fullLayout . hoverdistance === 0 ? Infinity : fullLayout . hoverdistance : constants . MAXDIST ;
336
+ var spikedistance = fullLayout . spikedistance ? fullLayout . spikedistance === 0 ? Infinity : fullLayout . spikedistance : hoverdistance ;
336
337
337
338
// container for new point, also used to pass info into module.hoverPoints
338
339
pointData = {
@@ -391,11 +392,11 @@ function _hover(gd, evt, subplot, noHoverEvent) {
391
392
// Find the points for the spikes first to avoid overwriting the hoverLabels data.
392
393
if ( fullLayout . _has ( 'cartesian' ) ) {
393
394
if ( fullLayout . hovermode === 'closest' ) {
394
- closestPoints . hLinePoint = findClosestPoint ( pointData , xval , yval , 'closest' , closestPoints . hLinePoint , spikedistance ) ;
395
- closestPoints . vLinePoint = findClosestPoint ( pointData , xval , yval , 'closest' , closestPoints . vLinePoint , spikedistance ) ;
395
+ spikePoints . hLinePoint = setClosestPoint ( pointData , xval , yval , 'closest' , spikePoints . hLinePoint , spikedistance , 'h' ) ;
396
+ spikePoints . vLinePoint = setClosestPoint ( pointData , xval , yval , 'closest' , spikePoints . vLinePoint , spikedistance , 'v' ) ;
396
397
} else {
397
- closestPoints . hLinePoint = findClosestPoint ( pointData , xval , yval , 'y' , closestPoints . hLinePoint , spikedistance ) ;
398
- closestPoints . vLinePoint = findClosestPoint ( pointData , xval , yval , 'x' , closestPoints . vLinePoint , spikedistance ) ;
398
+ spikePoints . hLinePoint = setClosestPoint ( pointData , xval , yval , 'y' , spikePoints . hLinePoint , spikedistance , 'h' ) ;
399
+ spikePoints . vLinePoint = setClosestPoint ( pointData , xval , yval , 'x' , spikePoints . vLinePoint , spikedistance , 'v' ) ;
399
400
}
400
401
}
401
402
@@ -424,21 +425,72 @@ function _hover(gd, evt, subplot, noHoverEvent) {
424
425
}
425
426
}
426
427
427
- function findClosestPoint ( pointData , xval , yval , mode , endPoint , spikedistance ) {
428
+ function findClosestPoints ( pointData , xval , yval , hovermode ) {
429
+ var cd = pointData . cd ,
430
+ trace = cd [ 0 ] . trace ,
431
+ xa = pointData . xa ,
432
+ ya = pointData . ya ,
433
+ xpx = xa . c2p ( xval ) ,
434
+ ypx = ya . c2p ( yval ) ,
435
+ hoveron = trace . hoveron || '' ;
436
+
437
+ if ( hoveron . indexOf ( 'points' ) !== - 1 ) {
438
+ var dx = function ( di ) {
439
+ // scatter points: d.mrc is the calculated marker radius
440
+ // adjust the distance so if you're inside the marker it
441
+ // always will show up regardless of point size, but
442
+ // prioritize smaller points
443
+ var rad = Math . max ( 3 , di . mrc || 0 ) ;
444
+ return Math . max ( Math . abs ( xa . c2p ( di . x ) - xpx ) - rad , 1 - 3 / rad ) ;
445
+ } ,
446
+ dy = function ( di ) {
447
+ var rad = Math . max ( 3 , di . mrc || 0 ) ;
448
+ return Math . max ( Math . abs ( ya . c2p ( di . y ) - ypx ) - rad , 1 - 3 / rad ) ;
449
+ } ,
450
+ dxy = function ( di ) {
451
+ var rad = Math . max ( 3 , di . mrc || 0 ) ,
452
+ dx = xa . c2p ( di . x ) - xpx ,
453
+ dy = ya . c2p ( di . y ) - ypx ;
454
+ return Math . max ( Math . sqrt ( dx * dx + dy * dy ) - rad , 1 - 3 / rad ) ;
455
+ } ,
456
+ distfn = helpers . getDistanceFunction ( hovermode , dx , dy , dxy ) ;
457
+
458
+ helpers . getClosest ( cd , distfn , pointData ) ;
459
+
460
+ // skip the rest (for this trace) if we didn't find a close point
461
+ if ( pointData . index !== false ) {
462
+
463
+ // the closest data point
464
+ var di = cd [ pointData . index ] ,
465
+ xc = xa . c2p ( di . x , true ) ,
466
+ yc = ya . c2p ( di . y , true ) ,
467
+ rad = di . mrc || 1 ;
468
+
469
+ Lib . extendFlat ( pointData , {
470
+ color : getTraceColor ( trace , di ) ,
471
+ x0 : xc - rad ,
472
+ x1 : xc + rad ,
473
+ y0 : yc - rad ,
474
+ y1 : yc + rad ,
475
+ } ) ;
476
+ return [ pointData ] ;
477
+ }
478
+ }
479
+ }
480
+
481
+ function setClosestPoint ( pointData , xval , yval , mode , endPoint , spikedistance , type ) {
428
482
var tmpDistance = pointData . distance ;
429
483
var tmpIndex = pointData . index ;
430
484
var resultPoint = endPoint ;
431
485
pointData . distance = spikedistance ;
432
486
pointData . index = false ;
433
- var closestPoints = trace . _module . hoverPoints ( pointData , xval , yval , mode ) ;
487
+ var closestPoints = findClosestPoints ( pointData , xval , yval , mode ) ;
434
488
if ( closestPoints ) {
435
489
closestPoints = closestPoints . filter ( function ( point ) {
436
- if ( mode === 'x ' ) {
490
+ if ( type === 'v ' ) {
437
491
return point . xa . showspikes ;
438
- } else if ( mode === 'y ' ) {
492
+ } else if ( type === 'h ' ) {
439
493
return point . ya . showspikes ;
440
- } else if ( mode === 'closest' ) {
441
- return point . ya . showspikes && point . ya . showspikes ;
442
494
}
443
495
} ) ;
444
496
if ( closestPoints . length ) {
@@ -477,24 +529,24 @@ function _hover(gd, evt, subplot, noHoverEvent) {
477
529
} ;
478
530
var oldspikepoints = gd . _spikepoints ,
479
531
newspikepoints = {
480
- vLinePoint : closestPoints . vLinePoint ,
481
- hLinePoint : closestPoints . hLinePoint
532
+ vLinePoint : spikePoints . vLinePoint ,
533
+ hLinePoint : spikePoints . hLinePoint
482
534
} ;
483
535
gd . _spikepoints = newspikepoints ;
484
536
485
537
if ( hoverData . length === 0 ) {
486
538
var result = dragElement . unhoverRaw ( gd , evt ) ;
487
- if ( fullLayout . _has ( 'cartesian' ) && ( ( closestPoints . hLinePoint !== null ) || ( closestPoints . vLinePoint !== null ) ) ) {
539
+ if ( fullLayout . _has ( 'cartesian' ) && ( ( spikePoints . hLinePoint !== null ) || ( spikePoints . vLinePoint !== null ) ) ) {
488
540
if ( spikesChanged ( oldspikepoints ) ) {
489
- createSpikelines2 ( closestPoints , spikelineOpts ) ;
541
+ createSpikelines ( spikePoints , spikelineOpts ) ;
490
542
}
491
543
}
492
544
return result ;
493
545
}
494
546
495
547
if ( fullLayout . _has ( 'cartesian' ) ) {
496
548
if ( spikesChanged ( oldspikepoints ) ) {
497
- createSpikelines2 ( closestPoints , spikelineOpts ) ;
549
+ createSpikelines ( spikePoints , spikelineOpts ) ;
498
550
}
499
551
}
500
552
@@ -1170,17 +1222,13 @@ function cleanPoint(d, hovermode) {
1170
1222
return d ;
1171
1223
}
1172
1224
1173
- function createSpikelines2 ( closestPoints , opts ) {
1225
+ function createSpikelines ( closestPoints , opts ) {
1174
1226
var hovermode = opts . hovermode ;
1175
1227
var container = opts . container ;
1176
1228
var fullLayout = opts . fullLayout ;
1177
1229
var evt = opts . event ;
1178
- var hLinePoint ,
1179
- vLinePoint ,
1180
- xa ,
1181
- ya ,
1182
- hLinePointY ,
1183
- vLinePointX ;
1230
+ var xa ,
1231
+ ya ;
1184
1232
1185
1233
var showY = closestPoints . hLinePoint ? true : false ;
1186
1234
var showX = closestPoints . vLinePoint ? true : false ;
@@ -1190,31 +1238,22 @@ function createSpikelines2(closestPoints, opts) {
1190
1238
1191
1239
if ( ! ( showX || showY ) ) return ;
1192
1240
1241
+ var contrastColor = Color . combine ( fullLayout . plot_bgcolor , fullLayout . paper_bgcolor ) ;
1242
+
1243
+ // Horizontal line (to y-axis)
1193
1244
if ( showY ) {
1194
- hLinePoint = closestPoints . hLinePoint ;
1245
+ var hLinePoint = closestPoints . hLinePoint ;
1246
+ xa = hLinePoint && hLinePoint . xa ;
1195
1247
ya = hLinePoint && hLinePoint . ya ;
1196
- var ySnap = ya . spikesnap ;
1248
+ var ySnap = ya . spikesnap ,
1249
+ hLinePointX ,
1250
+ hLinePointY ;
1197
1251
if ( ySnap === 'cursor' ) {
1198
1252
hLinePointY = evt . offsetY ;
1199
1253
} else {
1200
1254
hLinePointY = ya . _offset + ( hLinePoint . y0 + hLinePoint . y1 ) / 2 ;
1201
1255
}
1202
- }
1203
- if ( showX ) {
1204
- vLinePoint = closestPoints . vLinePoint ;
1205
- xa = vLinePoint && vLinePoint . xa ;
1206
- var xSnap = xa . spikesnap ;
1207
- if ( xSnap === 'cursor' ) {
1208
- vLinePointX = evt . offsetX ;
1209
- } else {
1210
- vLinePointX = xa . _offset + ( vLinePoint . x0 + vLinePoint . x1 ) / 2 ;
1211
- }
1212
- }
1213
-
1214
- var contrastColor = Color . combine ( fullLayout . plot_bgcolor , fullLayout . paper_bgcolor ) ;
1215
-
1216
- // Horizontal line (to y-axis)
1217
- if ( showY ) {
1256
+ hLinePointX = xa . _offset + ( hLinePoint . x0 + hLinePoint . x1 ) / 2 ;
1218
1257
var dfltHLineColor = tinycolor . readability ( hLinePoint . color , contrastColor ) < 1.5 ?
1219
1258
Color . contrast ( contrastColor ) : hLinePoint . color ;
1220
1259
var yMode = ya . spikemode ;
@@ -1224,14 +1263,14 @@ function createSpikelines2(closestPoints, opts) {
1224
1263
var yThickness = ya . spikethickness ;
1225
1264
var yColor = ya . spikecolor || dfltHLineColor ;
1226
1265
var yBB = ya . _boundingBox ;
1227
- var xEdge = ( ( yBB . left + yBB . right ) / 2 ) < vLinePointX ? yBB . right : yBB . left ;
1266
+ var xEdge = ( ( yBB . left + yBB . right ) / 2 ) < hLinePointX ? yBB . right : yBB . left ;
1228
1267
var xBase ;
1229
1268
var xEndSpike ;
1230
1269
1231
1270
if ( yMode . indexOf ( 'toaxis' ) !== - 1 || yMode . indexOf ( 'across' ) !== - 1 ) {
1232
1271
if ( yMode . indexOf ( 'toaxis' ) !== - 1 ) {
1233
1272
xBase = xEdge ;
1234
- xEndSpike = vLinePointX ;
1273
+ xEndSpike = hLinePointX ;
1235
1274
}
1236
1275
if ( yMode . indexOf ( 'across' ) !== - 1 ) {
1237
1276
xBase = ya . _counterSpan [ 0 ] ;
@@ -1279,24 +1318,36 @@ function createSpikelines2(closestPoints, opts) {
1279
1318
}
1280
1319
1281
1320
if ( showX ) {
1321
+ var vLinePoint = closestPoints . vLinePoint ;
1322
+ xa = vLinePoint && vLinePoint . xa ;
1323
+ ya = vLinePoint && vLinePoint . ya ;
1324
+ var xSnap = xa . spikesnap ,
1325
+ vLinePointX ,
1326
+ vLinePointY ;
1327
+ if ( xSnap === 'cursor' ) {
1328
+ vLinePointX = evt . offsetX ;
1329
+ } else {
1330
+ vLinePointX = xa . _offset + ( vLinePoint . x0 + vLinePoint . x1 ) / 2 ;
1331
+ }
1332
+ vLinePointY = ya . _offset + ( vLinePoint . y0 + vLinePoint . y1 ) / 2 ;
1282
1333
var dfltVLineColor = tinycolor . readability ( vLinePoint . color , contrastColor ) < 1.5 ?
1283
- Color . contrast ( contrastColor ) : vLinePoint . color ;
1334
+ Color . contrast ( contrastColor ) : vLinePoint . color ;
1284
1335
var xMode = xa . spikemode ;
1285
1336
if ( hovermode !== 'closest' && xMode . indexOf ( 'toaxis' ) !== - 1 ) {
1286
1337
xMode = xMode . replace ( 'toaxis' , 'across' ) ;
1287
1338
}
1288
1339
var xThickness = xa . spikethickness ;
1289
1340
var xColor = xa . spikecolor || dfltVLineColor ;
1290
1341
var xBB = xa . _boundingBox ;
1291
- var yEdge = ( ( xBB . top + xBB . bottom ) / 2 ) < hLinePointY ? xBB . bottom : xBB . top ;
1342
+ var yEdge = ( ( xBB . top + xBB . bottom ) / 2 ) < vLinePointY ? xBB . bottom : xBB . top ;
1292
1343
1293
1344
var yBase ;
1294
1345
var yEndSpike ;
1295
1346
1296
1347
if ( xMode . indexOf ( 'toaxis' ) !== - 1 || xMode . indexOf ( 'across' ) !== - 1 ) {
1297
1348
if ( xMode . indexOf ( 'toaxis' ) !== - 1 ) {
1298
1349
yBase = yEdge ;
1299
- yEndSpike = hLinePointY ;
1350
+ yEndSpike = vLinePointY ;
1300
1351
}
1301
1352
if ( xMode . indexOf ( 'across' ) !== - 1 ) {
1302
1353
yBase = xa . _counterSpan [ 0 ] ;
0 commit comments