@@ -365,176 +365,178 @@ function _hover(gd, evt, subplot, noHoverEvent) {
365365 // find the closest point in each trace
366366 // this is minimum dx and/or dy, depending on mode
367367 // and the pixel position for the label (labelXpx, labelYpx)
368- for ( curvenum = 0 ; curvenum < searchData . length ; curvenum ++ ) {
369- cd = searchData [ curvenum ] ;
368+ function findHoverPoints ( vals ) {
369+ for ( curvenum = 0 ; curvenum < searchData . length ; curvenum ++ ) {
370+ cd = searchData [ curvenum ] ;
370371
371- // filter out invisible or broken data
372- if ( ! cd || ! cd [ 0 ] || ! cd [ 0 ] . trace ) continue ;
372+ // filter out invisible or broken data
373+ if ( ! cd || ! cd [ 0 ] || ! cd [ 0 ] . trace ) continue ;
373374
374- trace = cd [ 0 ] . trace ;
375+ trace = cd [ 0 ] . trace ;
375376
376- if ( trace . visible !== true || trace . _length === 0 ) continue ;
377+ if ( trace . visible !== true || trace . _length === 0 ) continue ;
377378
378- // Explicitly bail out for these two. I don't know how to otherwise prevent
379- // the rest of this function from running and failing
380- if ( [ 'carpet' , 'contourcarpet' ] . indexOf ( trace . _module . name ) !== - 1 ) continue ;
379+ // Explicitly bail out for these two. I don't know how to otherwise prevent
380+ // the rest of this function from running and failing
381+ if ( [ 'carpet' , 'contourcarpet' ] . indexOf ( trace . _module . name ) !== - 1 ) continue ;
381382
382- if ( trace . type === 'splom' ) {
383- // splom traces do not generate overlay subplots,
384- // it is safe to assume here splom traces correspond to the 0th subplot
385- subploti = 0 ;
386- subplotId = subplots [ subploti ] ;
387- } else {
388- subplotId = helpers . getSubplot ( trace ) ;
389- subploti = subplots . indexOf ( subplotId ) ;
390- }
391-
392- // within one trace mode can sometimes be overridden
393- mode = hovermode ;
394- if ( [ 'x unified' , 'y unified' ] . indexOf ( mode ) !== - 1 ) {
395- mode = mode . charAt ( 0 ) ;
396- }
397-
398- // container for new point, also used to pass info into module.hoverPoints
399- pointData = {
400- // trace properties
401- cd : cd ,
402- trace : trace ,
403- xa : xaArray [ subploti ] ,
404- ya : yaArray [ subploti ] ,
405-
406- // max distances for hover and spikes - for points that want to show but do not
407- // want to override other points, set distance/spikeDistance equal to max*Distance
408- // and it will not get filtered out but it will be guaranteed to have a greater
409- // distance than any point that calculated a real distance.
410- maxHoverDistance : hoverdistance ,
411- maxSpikeDistance : spikedistance ,
412-
413- // point properties - override all of these
414- index : false , // point index in trace - only used by plotly.js hoverdata consumers
415- distance : Math . min ( distance , hoverdistance ) , // pixel distance or pseudo-distance
416-
417- // distance/pseudo-distance for spikes. This distance should always be calculated
418- // as if in "closest" mode, and should only be set if this point should
419- // generate a spike.
420- spikeDistance : Infinity ,
421-
422- // in some cases the spikes have different positioning from the hover label
423- // they don't need x0/x1, just one position
424- xSpike : undefined ,
425- ySpike : undefined ,
426-
427- // where and how to display the hover label
428- color : Color . defaultLine , // trace color
429- name : trace . name ,
430- x0 : undefined ,
431- x1 : undefined ,
432- y0 : undefined ,
433- y1 : undefined ,
434- xLabelVal : undefined ,
435- yLabelVal : undefined ,
436- zLabelVal : undefined ,
437- text : undefined
438- } ;
383+ if ( trace . type === 'splom' ) {
384+ // splom traces do not generate overlay subplots,
385+ // it is safe to assume here splom traces correspond to the 0th subplot
386+ subploti = 0 ;
387+ subplotId = subplots [ subploti ] ;
388+ } else {
389+ subplotId = helpers . getSubplot ( trace ) ;
390+ subploti = subplots . indexOf ( subplotId ) ;
391+ }
439392
440- // add ref to subplot object (non-cartesian case)
441- if ( fullLayout [ subplotId ] ) {
442- pointData . subplot = fullLayout [ subplotId ] . _subplot ;
443- }
444- // add ref to splom scene
445- if ( fullLayout . _splomScenes && fullLayout . _splomScenes [ trace . uid ] ) {
446- pointData . scene = fullLayout . _splomScenes [ trace . uid ] ;
447- }
393+ // within one trace mode can sometimes be overridden
394+ mode = hovermode ;
395+ if ( [ 'x unified' , 'y unified' ] . indexOf ( mode ) !== - 1 ) {
396+ mode = mode . charAt ( 0 ) ;
397+ }
448398
449- closedataPreviousLength = hoverData . length ;
399+ // container for new point, also used to pass info into module.hoverPoints
400+ pointData = {
401+ // trace properties
402+ cd : cd ,
403+ trace : trace ,
404+ xa : xaArray [ subploti ] ,
405+ ya : yaArray [ subploti ] ,
406+
407+ // max distances for hover and spikes - for points that want to show but do not
408+ // want to override other points, set distance/spikeDistance equal to max*Distance
409+ // and it will not get filtered out but it will be guaranteed to have a greater
410+ // distance than any point that calculated a real distance.
411+ maxHoverDistance : hoverdistance ,
412+ maxSpikeDistance : spikedistance ,
413+
414+ // point properties - override all of these
415+ index : false , // point index in trace - only used by plotly.js hoverdata consumers
416+ distance : Math . min ( distance , hoverdistance ) , // pixel distance or pseudo-distance
417+
418+ // distance/pseudo-distance for spikes. This distance should always be calculated
419+ // as if in "closest" mode, and should only be set if this point should
420+ // generate a spike.
421+ spikeDistance : Infinity ,
422+
423+ // in some cases the spikes have different positioning from the hover label
424+ // they don't need x0/x1, just one position
425+ xSpike : undefined ,
426+ ySpike : undefined ,
427+
428+ // where and how to display the hover label
429+ color : Color . defaultLine , // trace color
430+ name : trace . name ,
431+ x0 : undefined ,
432+ x1 : undefined ,
433+ y0 : undefined ,
434+ y1 : undefined ,
435+ xLabelVal : undefined ,
436+ yLabelVal : undefined ,
437+ zLabelVal : undefined ,
438+ text : undefined
439+ } ;
440+
441+ // add ref to subplot object (non-cartesian case)
442+ if ( fullLayout [ subplotId ] ) {
443+ pointData . subplot = fullLayout [ subplotId ] . _subplot ;
444+ }
445+ // add ref to splom scene
446+ if ( fullLayout . _splomScenes && fullLayout . _splomScenes [ trace . uid ] ) {
447+ pointData . scene = fullLayout . _splomScenes [ trace . uid ] ;
448+ }
450449
451- // for a highlighting array, figure out what
452- // we're searching for with this element
453- if ( mode === 'array' ) {
454- var selection = evt [ curvenum ] ;
455- if ( 'pointNumber' in selection ) {
456- pointData . index = selection . pointNumber ;
457- mode = 'closest' ;
458- } else {
459- mode = '' ;
460- if ( 'xval' in selection ) {
461- xval = selection . xval ;
462- mode = 'x' ;
463- }
464- if ( 'yval' in selection ) {
465- yval = selection . yval ;
466- mode = mode ? 'closest' : 'y' ;
450+ closedataPreviousLength = hoverData . length ;
451+
452+ // for a highlighting array, figure out what
453+ // we're searching for with this element
454+ if ( mode === 'array' ) {
455+ var selection = evt [ curvenum ] ;
456+ if ( 'pointNumber' in selection ) {
457+ pointData . index = selection . pointNumber ;
458+ mode = 'closest' ;
459+ } else {
460+ mode = '' ;
461+ if ( 'xval' in selection ) {
462+ xval = selection . xval ;
463+ mode = 'x' ;
464+ }
465+ if ( 'yval' in selection ) {
466+ yval = selection . yval ;
467+ mode = mode ? 'closest' : 'y' ;
468+ }
467469 }
470+ } else {
471+ xval = xvalArray [ subploti ] ;
472+ yval = yvalArray [ subploti ] ;
468473 }
469- } else {
470- xval = xvalArray [ subploti ] ;
471- yval = yvalArray [ subploti ] ;
472- }
473474
474- // Now if there is range to look in, find the points to hover.
475- if ( hoverdistance !== 0 ) {
476- if ( trace . _module && trace . _module . hoverPoints ) {
477- var newPoints = trace . _module . hoverPoints ( pointData , xval , yval , mode , fullLayout . _hoverlayer ) ;
478- if ( newPoints ) {
479- var newPoint ;
480- for ( var newPointNum = 0 ; newPointNum < newPoints . length ; newPointNum ++ ) {
481- newPoint = newPoints [ newPointNum ] ;
482- if ( isNumeric ( newPoint . x0 ) && isNumeric ( newPoint . y0 ) ) {
483- hoverData . push ( cleanPoint ( newPoint , hovermode ) ) ;
475+ // Now if there is range to look in, find the points to hover.
476+ if ( hoverdistance !== 0 ) {
477+ if ( trace . _module && trace . _module . hoverPoints ) {
478+ var newPoints = trace . _module . hoverPoints ( pointData , xval , yval , mode , fullLayout . _hoverlayer ) ;
479+ if ( newPoints ) {
480+ var newPoint ;
481+ for ( var newPointNum = 0 ; newPointNum < newPoints . length ; newPointNum ++ ) {
482+ newPoint = newPoints [ newPointNum ] ;
483+ if ( isNumeric ( newPoint . x0 ) && isNumeric ( newPoint . y0 ) ) {
484+ hoverData . push ( cleanPoint ( newPoint , hovermode ) ) ;
485+ }
484486 }
485487 }
488+ } else {
489+ Lib . log ( 'Unrecognized trace type in hover:' , trace ) ;
486490 }
487- } else {
488- Lib . log ( 'Unrecognized trace type in hover:' , trace ) ;
489491 }
490- }
491492
492- // in closest mode, remove any existing (farther) points
493- // and don't look any farther than this latest point (or points, some
494- // traces like box & violin make multiple hover labels at once)
495- if ( hovermode === 'closest' && hoverData . length > closedataPreviousLength ) {
496- hoverData . splice ( 0 , closedataPreviousLength ) ;
497- distance = hoverData [ 0 ] . distance ;
498- }
493+ // in closest mode, remove any existing (farther) points
494+ // and don't look any farther than this latest point (or points, some
495+ // traces like box & violin make multiple hover labels at once)
496+ if ( hovermode === 'closest' && hoverData . length > closedataPreviousLength ) {
497+ hoverData . splice ( 0 , closedataPreviousLength ) ;
498+ distance = hoverData [ 0 ] . distance ;
499+ }
499500
500- // Now if there is range to look in, find the points to draw the spikelines
501- // Do it only if there is no hoverData
502- if ( hasCartesian && ( spikedistance !== 0 ) ) {
503- if ( hoverData . length === 0 ) {
504- pointData . distance = spikedistance ;
505- pointData . index = false ;
506- var closestPoints = trace . _module . hoverPoints ( pointData , xval , yval , 'closest' , fullLayout . _hoverlayer ) ;
507- if ( closestPoints ) {
508- closestPoints = closestPoints . filter ( function ( point ) {
509- // some hover points, like scatter fills, do not allow spikes,
510- // so will generate a hover point but without a valid spikeDistance
511- return point . spikeDistance <= spikedistance ;
512- } ) ;
513- }
514- if ( closestPoints && closestPoints . length ) {
515- var tmpPoint ;
516- var closestVPoints = closestPoints . filter ( function ( point ) {
517- return point . xa . showspikes ;
518- } ) ;
519- if ( closestVPoints . length ) {
520- var closestVPt = closestVPoints [ 0 ] ;
521- if ( isNumeric ( closestVPt . x0 ) && isNumeric ( closestVPt . y0 ) ) {
522- tmpPoint = fillSpikePoint ( closestVPt ) ;
523- if ( ! spikePoints . vLinePoint || ( spikePoints . vLinePoint . spikeDistance > tmpPoint . spikeDistance ) ) {
524- spikePoints . vLinePoint = tmpPoint ;
501+ // Now if there is range to look in, find the points to draw the spikelines
502+ // Do it only if there is no hoverData
503+ if ( hasCartesian && ( spikedistance !== 0 ) ) {
504+ if ( hoverData . length === 0 ) {
505+ pointData . distance = spikedistance ;
506+ pointData . index = false ;
507+ var closestPoints = trace . _module . hoverPoints ( pointData , xval , yval , 'closest' , fullLayout . _hoverlayer ) ;
508+ if ( closestPoints ) {
509+ closestPoints = closestPoints . filter ( function ( point ) {
510+ // some hover points, like scatter fills, do not allow spikes,
511+ // so will generate a hover point but without a valid spikeDistance
512+ return point . spikeDistance <= spikedistance ;
513+ } ) ;
514+ }
515+ if ( closestPoints && closestPoints . length ) {
516+ var tmpPoint ;
517+ var closestVPoints = closestPoints . filter ( function ( point ) {
518+ return point . xa . showspikes ;
519+ } ) ;
520+ if ( closestVPoints . length ) {
521+ var closestVPt = closestVPoints [ 0 ] ;
522+ if ( isNumeric ( closestVPt . x0 ) && isNumeric ( closestVPt . y0 ) ) {
523+ tmpPoint = fillSpikePoint ( closestVPt ) ;
524+ if ( ! spikePoints . vLinePoint || ( spikePoints . vLinePoint . spikeDistance > tmpPoint . spikeDistance ) ) {
525+ spikePoints . vLinePoint = tmpPoint ;
526+ }
525527 }
526528 }
527- }
528529
529- var closestHPoints = closestPoints . filter ( function ( point ) {
530- return point . ya . showspikes ;
531- } ) ;
532- if ( closestHPoints . length ) {
533- var closestHPt = closestHPoints [ 0 ] ;
534- if ( isNumeric ( closestHPt . x0 ) && isNumeric ( closestHPt . y0 ) ) {
535- tmpPoint = fillSpikePoint ( closestHPt ) ;
536- if ( ! spikePoints . hLinePoint || ( spikePoints . hLinePoint . spikeDistance > tmpPoint . spikeDistance ) ) {
537- spikePoints . hLinePoint = tmpPoint ;
530+ var closestHPoints = closestPoints . filter ( function ( point ) {
531+ return point . ya . showspikes ;
532+ } ) ;
533+ if ( closestHPoints . length ) {
534+ var closestHPt = closestHPoints [ 0 ] ;
535+ if ( isNumeric ( closestHPt . x0 ) && isNumeric ( closestHPt . y0 ) ) {
536+ tmpPoint = fillSpikePoint ( closestHPt ) ;
537+ if ( ! spikePoints . hLinePoint || ( spikePoints . hLinePoint . spikeDistance > tmpPoint . spikeDistance ) ) {
538+ spikePoints . hLinePoint = tmpPoint ;
539+ }
538540 }
539541 }
540542 }
@@ -543,6 +545,8 @@ function _hover(gd, evt, subplot, noHoverEvent) {
543545 }
544546 }
545547
548+ findHoverPoints ( ) ;
549+
546550 function selectClosestPoint ( pointsData , spikedistance ) {
547551 var resultPoint = null ;
548552 var minDistance = Infinity ;
0 commit comments