@@ -14,6 +14,7 @@ var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
1414// from the mousemove events and then simulate
1515// a click event on mouseup
1616var click = require ( '../assets/timed_click' ) ;
17+ var doubleClick = require ( '../assets/double_click' ) ;
1718var hover = require ( '../assets/hover' ) ;
1819var delay = require ( '../assets/delay' ) ;
1920var mouseEvent = require ( '../assets/mouse_event' ) ;
@@ -963,4 +964,174 @@ describe('@noCI @gl Test gl2d lasso/select:', function() {
963964 . catch ( failTest )
964965 . then ( done ) ;
965966 } ) ;
967+
968+ it ( 'should behave correctly during select+doubleclick+pan scenarios' , function ( done ) {
969+ gd = createGraphDiv ( ) ;
970+
971+ // See https://github.com/plotly/plotly.js/issues/2767
972+
973+ function grabScene ( ) {
974+ return gd . calcdata [ 0 ] [ 0 ] . t . _scene ;
975+ }
976+
977+ function _assert ( msg , exp ) {
978+ var scene = grabScene ( ) ;
979+ var scatter2d = scene . scatter2d ;
980+
981+ expect ( ( scene . markerOptions || [ ] ) [ 0 ] . opacity )
982+ . toBe ( 1 , 'marker.opacity - ' + msg ) ;
983+ expect ( ( scene . markerSelectedOptions || [ ] ) [ 0 ] . opacity )
984+ . toBe ( 1 , 'selected.marker.opacity - ' + msg ) ;
985+ expect ( ( scene . markerUnselectedOptions || [ ] ) [ 0 ] . opacity )
986+ . toBe ( 0.2 , 'unselected.marker.opacity - ' + msg ) ;
987+
988+ expect ( scene . selectBatch ) . toEqual ( exp . selectBatch ) ;
989+ expect ( scene . unselectBatch ) . toEqual ( exp . unselectBatch ) ;
990+
991+ var updateCalls = scatter2d . update . calls . all ( ) ;
992+ var drawCalls = scatter2d . draw . calls . all ( ) ;
993+
994+ expect ( updateCalls . length ) . toBe (
995+ exp . updateArgs . length ,
996+ 'scatter2d.update has been called the correct number of times - ' + msg
997+ ) ;
998+ updateCalls . forEach ( function ( d , i ) {
999+ d . args . forEach ( function ( arg , j ) {
1000+ if ( 'range' in arg [ 0 ] ) {
1001+ // no need to assert range value in detail
1002+ expect ( exp . updateArgs [ i ] [ j ] ) . toBe (
1003+ 'range' ,
1004+ 'scatter.update range update - ' + msg
1005+ ) ;
1006+ } else {
1007+ expect ( arg ) . toBe (
1008+ exp . updateArgs [ i ] [ j ] ,
1009+ 'scatter.update call' + i + ' arg' + j + ' - ' + msg
1010+ ) ;
1011+ }
1012+ } ) ;
1013+ } ) ;
1014+
1015+ expect ( drawCalls . length ) . toBe (
1016+ exp . drawArgs . length ,
1017+ 'scatter2d.draw has been called the correct number of times - ' + msg
1018+ ) ;
1019+ drawCalls . forEach ( function ( d , i ) {
1020+ d . args . forEach ( function ( arg , j ) {
1021+ expect ( arg ) . toBe (
1022+ exp . drawArgs [ i ] [ j ] ,
1023+ 'scatter.draw call' + i + ' arg' + j + ' - ' + msg
1024+ ) ;
1025+ } ) ;
1026+ } ) ;
1027+
1028+ scene . scatter2d . update . calls . reset ( ) ;
1029+ scene . scatter2d . draw . calls . reset ( ) ;
1030+ }
1031+
1032+ var unselectBatchOld ;
1033+
1034+ Plotly . newPlot ( 'graph' , [ {
1035+ type : 'scattergl' ,
1036+ mode : 'markers' ,
1037+ y : [ 1 , 2 , 1 ] ,
1038+ marker : { size : 30 }
1039+ } ] , {
1040+ dragmode : 'select' ,
1041+ margin : { t : 0 , b : 0 , l : 0 , r : 0 } ,
1042+ width : 500 ,
1043+ height : 500
1044+ } )
1045+ . then ( delay ( 100 ) )
1046+ . then ( function ( ) {
1047+ var scene = grabScene ( ) ;
1048+ spyOn ( scene . scatter2d , 'update' ) . and . callThrough ( ) ;
1049+ spyOn ( scene . scatter2d , 'draw' ) . and . callThrough ( ) ;
1050+ } )
1051+ . then ( function ( ) {
1052+ _assert ( 'base' , {
1053+ selectBatch : [ ] ,
1054+ unselectBatch : [ ] ,
1055+ updateArgs : [ ] ,
1056+ drawArgs : [ ]
1057+ } ) ;
1058+ } )
1059+ . then ( function ( ) { return select ( [ [ 20 , 20 ] , [ 480 , 250 ] ] ) ; } )
1060+ . then ( function ( ) {
1061+ var scene = grabScene ( ) ;
1062+ _assert ( 'after select' , {
1063+ selectBatch : [ [ 1 ] ] ,
1064+ unselectBatch : [ [ 0 , 2 ] ] ,
1065+ updateArgs : [
1066+ // N.B. scatter2d now draws unselected options
1067+ [ scene . markerUnselectedOptions ] ,
1068+ ] ,
1069+ drawArgs : [
1070+ [ scene . unselectBatch ]
1071+ ]
1072+ } ) ;
1073+ } )
1074+ . then ( function ( ) { return doubleClick ( 250 , 250 ) ; } )
1075+ . then ( function ( ) {
1076+ var scene = grabScene ( ) ;
1077+ _assert ( 'after doubleclick' , {
1078+ selectBatch : [ null ] ,
1079+ unselectBatch : [ [ 0 , 1 , 2 ] ] ,
1080+ updateArgs : [ ] ,
1081+ drawArgs : [
1082+ // call in no-selection loop (can we get rid of this?)
1083+ [ 0 ] ,
1084+ // call with unselectBatch
1085+ [ scene . unselectBatch ]
1086+ ]
1087+ } ) ;
1088+ } )
1089+ . then ( function ( ) { return Plotly . relayout ( gd , 'dragmode' , 'pan' ) ; } )
1090+ . then ( function ( ) {
1091+ _assert ( 'after relayout to *pan*' , {
1092+ selectBatch : [ null ] ,
1093+ unselectBatch : [ [ 0 , 1 , 2 ] ] ,
1094+ // nothing to do when relayouting to 'pan'
1095+ updateArgs : [ ] ,
1096+ drawArgs : [ ]
1097+ } ) ;
1098+
1099+ // keep ref for next _assert()
1100+ var scene = grabScene ( ) ;
1101+ unselectBatchOld = scene . unselectBatch ;
1102+ } )
1103+ . then ( function ( ) { return drag ( [ [ 200 , 200 ] , [ 250 , 250 ] ] ) ; } )
1104+ . then ( function ( ) {
1105+ var scene = grabScene ( ) ;
1106+ _assert ( 'after pan' , {
1107+ selectBatch : null ,
1108+ unselectBatch : null ,
1109+ // drag triggers:
1110+ // - 2 scene.update() calls, which each invoke
1111+ // + 1 scatter2d.update (updating viewport)
1112+ // + 2 scatter2d.draw (same as after double-click)
1113+ //
1114+ // replot on mouseup triggers:
1115+ // - 1 scatter2d.update updating viewport
1116+ // - 1 scatter2d.update resetting markerOptions
1117+ // - 1 (full) scene.draw()
1118+ updateArgs : [
1119+ [ 'range' ] ,
1120+ [ 'range' ] ,
1121+ // N.B. bring scatter2d back to 'base' marker options
1122+ [ scene . markerOptions ] ,
1123+ [ 'range' ]
1124+ ] ,
1125+ drawArgs : [
1126+ [ 0 ] ,
1127+ [ unselectBatchOld ] ,
1128+ [ 0 ] ,
1129+ [ unselectBatchOld ] ,
1130+ [ 0 ]
1131+ ]
1132+ } ) ;
1133+ } )
1134+ . catch ( failTest )
1135+ . then ( done ) ;
1136+ } ) ;
9661137} ) ;
0 commit comments