@@ -8,6 +8,11 @@ var supplyAllDefaults = require('../assets/supply_defaults');
8
8
var createGraphDiv = require ( '../assets/create_graph_div' ) ;
9
9
var destroyGraphDiv = require ( '../assets/destroy_graph_div' ) ;
10
10
var failTest = require ( '../assets/fail_test' ) ;
11
+ var mouseEvent = require ( '../assets/mouse_event' ) ;
12
+ var drag = require ( '../assets/drag' ) ;
13
+
14
+ var customAssertions = require ( '../assets/custom_assertions' ) ;
15
+ var assertHoverLabelContent = customAssertions . assertHoverLabelContent ;
11
16
12
17
describe ( 'Test splom trace defaults:' , function ( ) {
13
18
var gd ;
@@ -545,3 +550,365 @@ describe('@gl Test splom interactions:', function() {
545
550
. then ( done ) ;
546
551
} ) ;
547
552
} ) ;
553
+
554
+ describe ( '@gl Test splom hover:' , function ( ) {
555
+ var gd ;
556
+
557
+ afterEach ( function ( ) {
558
+ Plotly . purge ( gd ) ;
559
+ destroyGraphDiv ( ) ;
560
+ } ) ;
561
+
562
+ function run ( s , done ) {
563
+ gd = createGraphDiv ( ) ;
564
+
565
+ var fig = Lib . extendDeep ( { } ,
566
+ s . mock || require ( '@mocks/splom_iris.json' )
567
+ ) ;
568
+
569
+ if ( s . patch ) {
570
+ fig = s . patch ( fig ) ;
571
+ }
572
+
573
+ var pos = s . pos || [ 200 , 100 ] ;
574
+
575
+ return Plotly . plot ( gd , fig ) . then ( function ( ) {
576
+ var to = setTimeout ( function ( ) {
577
+ failTest ( 'no event data received' ) ;
578
+ done ( ) ;
579
+ } , 100 ) ;
580
+
581
+ gd . on ( 'plotly_hover' , function ( d ) {
582
+ clearTimeout ( to ) ;
583
+ assertHoverLabelContent ( s ) ;
584
+
585
+ var msg = ' - event data ' + s . desc ;
586
+ var actual = d . points || [ ] ;
587
+ var exp = s . evtPts ;
588
+ expect ( actual . length ) . toBe ( exp . length , 'pt length' + msg ) ;
589
+ for ( var i = 0 ; i < exp . length ; i ++ ) {
590
+ for ( var k in exp [ i ] ) {
591
+ var m = 'key ' + k + ' in pt ' + i + msg ;
592
+ expect ( actual [ i ] [ k ] ) . toBe ( exp [ i ] [ k ] , m ) ;
593
+ }
594
+ }
595
+
596
+ // w/o this purge gets called before
597
+ // hover throttle is complete
598
+ setTimeout ( done , 0 ) ;
599
+ } ) ;
600
+
601
+ mouseEvent ( 'mousemove' , pos [ 0 ] , pos [ 1 ] ) ;
602
+ } )
603
+ . catch ( failTest ) ;
604
+ }
605
+
606
+ var specs = [ {
607
+ desc : 'basic' ,
608
+ nums : '7.7' ,
609
+ name : 'Virginica' ,
610
+ axis : '2.6' ,
611
+ evtPts : [ { x : 2.6 , y : 7.7 , pointNumber : 18 , curveNumber : 2 } ]
612
+ } , {
613
+ desc : 'hovermode closest' ,
614
+ patch : function ( fig ) {
615
+ fig . layout . hovermode = 'closest' ;
616
+ return fig ;
617
+ } ,
618
+ nums : '(2.6, 7.7)' ,
619
+ name : 'Virginica' ,
620
+ evtPts : [ { x : 2.6 , y : 7.7 , pointNumber : 18 , curveNumber : 2 } ]
621
+ } , {
622
+ desc : 'skipping over visible false dims' ,
623
+ patch : function ( fig ) {
624
+ fig . data [ 0 ] . dimensions [ 0 ] . visible = false ;
625
+ return fig ;
626
+ } ,
627
+ nums : '7.7' ,
628
+ name : 'Virginica' ,
629
+ axis : '2.6' ,
630
+ evtPts : [ { x : 2.6 , y : 7.7 , pointNumber : 18 , curveNumber : 2 } ]
631
+ } , {
632
+ desc : 'on log axes' ,
633
+ mock : require ( '@mocks/splom_log.json' ) ,
634
+ patch : function ( fig ) {
635
+ fig . layout . margin = { t : 0 , l : 0 , b : 0 , r : 0 } ;
636
+ fig . layout . width = 400 ;
637
+ fig . layout . height = 400 ;
638
+ return fig ;
639
+ } ,
640
+ pos : [ 20 , 380 ] ,
641
+ nums : '100' ,
642
+ axis : '10' ,
643
+ evtPts : [ { x : 10 , y : 100 , pointNumber : 0 } ]
644
+ } , {
645
+ desc : 'on date axes' ,
646
+ mock : require ( '@mocks/splom_dates.json' ) ,
647
+ patch : function ( fig ) {
648
+ fig . layout = {
649
+ margin : { t : 0 , l : 0 , b : 0 , r : 0 } ,
650
+ width : 400 ,
651
+ height : 400
652
+ } ;
653
+ return fig ;
654
+ } ,
655
+ pos : [ 20 , 380 ] ,
656
+ nums : 'Apr 2003' ,
657
+ axis : 'Jan 2000' ,
658
+ evtPts : [ { x : '2000-01-01' , y : '2003-04-21' , pointNumber : 0 } ]
659
+ } ] ;
660
+
661
+ specs . forEach ( function ( s ) {
662
+ it ( 'should generate correct hover labels ' + s . desc , function ( done ) {
663
+ run ( s , done ) ;
664
+ } ) ;
665
+ } ) ;
666
+ } ) ;
667
+
668
+ describe ( '@gl Test splom drag:' , function ( ) {
669
+ var gd ;
670
+
671
+ beforeEach ( function ( ) {
672
+ gd = createGraphDiv ( ) ;
673
+ } ) ;
674
+
675
+ afterEach ( function ( ) {
676
+ Plotly . purge ( gd ) ;
677
+ destroyGraphDiv ( ) ;
678
+ } ) ;
679
+
680
+ function _drag ( p0 , p1 ) {
681
+ var node = d3 . select ( '.nsewdrag[data-subplot="xy"]' ) . node ( ) ;
682
+ var dx = p1 [ 0 ] - p0 [ 0 ] ;
683
+ var dy = p1 [ 1 ] - p0 [ 1 ] ;
684
+ return drag ( node , dx , dy , null , p0 [ 0 ] , p0 [ 1 ] ) ;
685
+ }
686
+
687
+ it ( 'should update scattermatrix ranges on pan' , function ( done ) {
688
+ var fig = require ( '@mocks/splom_iris.json' ) ;
689
+ fig . layout . dragmode = 'pan' ;
690
+
691
+ var xaxes = [ 'xaxis' , 'xaxis2' , 'xaxis3' ] ;
692
+ var yaxes = [ 'yaxis' , 'yaxis2' , 'yaxis3' ] ;
693
+
694
+ function _assertRanges ( msg , xRanges , yRanges ) {
695
+ xaxes . forEach ( function ( n , i ) {
696
+ expect ( gd . _fullLayout [ n ] . range )
697
+ . toBeCloseToArray ( xRanges [ i ] , 1 , n + ' range - ' + msg ) ;
698
+ } ) ;
699
+ yaxes . forEach ( function ( n , i ) {
700
+ expect ( gd . _fullLayout [ n ] . range )
701
+ . toBeCloseToArray ( yRanges [ i ] , 1 , n + ' range - ' + msg ) ;
702
+ } ) ;
703
+ }
704
+
705
+ Plotly . plot ( gd , fig )
706
+ . then ( function ( ) {
707
+ var scene = gd . calcdata [ 0 ] [ 0 ] . t . _scene ;
708
+ spyOn ( scene . matrix , 'update' ) ;
709
+ spyOn ( scene . matrix , 'draw' ) ;
710
+
711
+ _assertRanges ( 'before drag' , [
712
+ [ 3.9 , 8.3 ] ,
713
+ [ 1.7 , 4.7 ] ,
714
+ [ 0.3 , 7.6 ]
715
+ ] , [
716
+ [ 3.8 , 8.4 ] ,
717
+ [ 1.7 , 4.7 ] ,
718
+ [ 0.3 , 7.6 ]
719
+ ] ) ;
720
+ } )
721
+ . then ( function ( ) { return _drag ( [ 130 , 130 ] , [ 150 , 150 ] ) ; } )
722
+ . then ( function ( ) {
723
+ var scene = gd . calcdata [ 0 ] [ 0 ] . t . _scene ;
724
+ // N.B. _drag triggers two updateSubplots call
725
+ // - 1 update and 1 draw call per updateSubplot
726
+ // - 2 update calls (1 for data, 1 for view opts)
727
+ // during splom plot on mouseup
728
+ // - 1 draw call during splom plot on mouseup
729
+ expect ( scene . matrix . update ) . toHaveBeenCalledTimes ( 4 ) ;
730
+ expect ( scene . matrix . draw ) . toHaveBeenCalledTimes ( 3 ) ;
731
+
732
+ _assertRanges ( 'after drag' , [
733
+ [ 2.9 , 7.3 ] ,
734
+ [ 1.7 , 4.7 ] ,
735
+ [ 0.3 , 7.6 ]
736
+ ] , [
737
+ [ 5.1 , 9.6 ] ,
738
+ [ 1.7 , 4.7 ] ,
739
+ [ 0.3 , 7.6 ]
740
+ ] ) ;
741
+ } )
742
+ . catch ( failTest )
743
+ . then ( done ) ;
744
+ } ) ;
745
+ } ) ;
746
+
747
+ describe ( '@gl Test splom select:' , function ( ) {
748
+ var gd ;
749
+ var ptData ;
750
+ var subplot ;
751
+
752
+ beforeEach ( function ( ) {
753
+ gd = createGraphDiv ( ) ;
754
+ } ) ;
755
+
756
+ afterEach ( function ( ) {
757
+ Plotly . purge ( gd ) ;
758
+ destroyGraphDiv ( ) ;
759
+ } ) ;
760
+
761
+ function _select ( path , opts ) {
762
+ return new Promise ( function ( resolve , reject ) {
763
+ opts = opts || { } ;
764
+ ptData = null ;
765
+ subplot = null ;
766
+
767
+ var to = setTimeout ( function ( ) {
768
+ reject ( 'fail: plotly_selected not emitter' ) ;
769
+ } , 200 ) ;
770
+
771
+ gd . once ( 'plotly_selected' , function ( d ) {
772
+ clearTimeout ( to ) ;
773
+ ptData = ( d || { } ) . points ;
774
+ subplot = Object . keys ( d . range || { } ) . join ( '' ) ;
775
+ resolve ( ) ;
776
+ } ) ;
777
+
778
+ Lib . clearThrottle ( ) ;
779
+ mouseEvent ( 'mousemove' , path [ 0 ] [ 0 ] , path [ 0 ] [ 1 ] , opts ) ;
780
+ mouseEvent ( 'mousedown' , path [ 0 ] [ 0 ] , path [ 0 ] [ 1 ] , opts ) ;
781
+
782
+ var len = path . length ;
783
+ path . slice ( 1 , len ) . forEach ( function ( pt ) {
784
+ Lib . clearThrottle ( ) ;
785
+ mouseEvent ( 'mousemove' , pt [ 0 ] , pt [ 1 ] , opts ) ;
786
+ } ) ;
787
+
788
+ mouseEvent ( 'mouseup' , path [ len - 1 ] [ 0 ] , path [ len - 1 ] [ 1 ] , opts ) ;
789
+ } ) ;
790
+ }
791
+
792
+ it ( 'should emit correct event data and draw selection outlines' , function ( done ) {
793
+ var fig = require ( '@mocks/splom_0.json' ) ;
794
+ fig . layout = {
795
+ dragmode : 'select' ,
796
+ width : 400 ,
797
+ height : 400 ,
798
+ margin : { l : 0 , t : 0 , r : 0 , b : 0 } ,
799
+ grid : { xgap : 0 , ygap : 0 }
800
+ } ;
801
+
802
+ function _assert ( _msg , ptExp , otherExp ) {
803
+ var msg = ' - ' + _msg ;
804
+
805
+ expect ( ptData . length ) . toBe ( ptExp . length , 'pt length' + msg ) ;
806
+ for ( var i = 0 ; i < ptExp . length ; i ++ ) {
807
+ for ( var k in ptExp [ i ] ) {
808
+ var m = 'key ' + k + ' in pt ' + i + msg ;
809
+ expect ( ptData [ i ] [ k ] ) . toBe ( ptExp [ i ] [ k ] , m ) ;
810
+ }
811
+ }
812
+
813
+ expect ( subplot ) . toBe ( otherExp . subplot , 'subplot of selection' + msg ) ;
814
+
815
+ expect ( d3 . selectAll ( '.zoomlayer > .select-outline' ) . size ( ) )
816
+ . toBe ( otherExp . selectionOutlineCnt , 'selection outline cnt' + msg ) ;
817
+ }
818
+
819
+ Plotly . newPlot ( gd , fig )
820
+ . then ( function ( ) { return _select ( [ [ 5 , 5 ] , [ 195 , 195 ] ] ) ; } )
821
+ . then ( function ( ) {
822
+ _assert ( 'first' , [
823
+ { pointNumber : 0 , x : 1 , y : 1 } ,
824
+ { pointNumber : 1 , x : 2 , y : 2 } ,
825
+ { pointNumber : 2 , x : 3 , y : 3 }
826
+ ] , {
827
+ subplot : 'xy' ,
828
+ selectionOutlineCnt : 2
829
+ } ) ;
830
+ } )
831
+ . then ( function ( ) { return _select ( [ [ 50 , 50 ] , [ 100 , 100 ] ] ) ; } )
832
+ . then ( function ( ) {
833
+ _assert ( 'second' , [
834
+ { pointNumber : 1 , x : 2 , y : 2 }
835
+ ] , {
836
+ subplot : 'xy' ,
837
+ selectionOutlineCnt : 2
838
+ } ) ;
839
+ } )
840
+ . then ( function ( ) { return _select ( [ [ 5 , 195 ] , [ 100 , 100 ] ] , { shiftKey : true } ) ; } )
841
+ . then ( function ( ) {
842
+ _assert ( 'multi-select' , [
843
+ { pointNumber : 0 , x : 1 , y : 1 } ,
844
+ { pointNumber : 1 , x : 2 , y : 2 }
845
+ ] , {
846
+ subplot : 'xy' ,
847
+ // still '2' as the selection get merged
848
+ selectionOutlineCnt : 2
849
+ } ) ;
850
+ } )
851
+ . then ( function ( ) { return _select ( [ [ 205 , 205 ] , [ 395 , 395 ] ] ) ; } )
852
+ . then ( function ( ) {
853
+ _assert ( 'across other subplot' , [
854
+ { pointNumber : 0 , x : 2 , y : 2 } ,
855
+ { pointNumber : 1 , x : 5 , y : 5 } ,
856
+ { pointNumber : 2 , x : 6 , y : 6 }
857
+ ] , {
858
+ subplot : 'x2y2' ,
859
+ // outlines from previous subplot are cleared!
860
+ selectionOutlineCnt : 2
861
+ } ) ;
862
+ } )
863
+ . then ( function ( ) { return _select ( [ [ 50 , 50 ] , [ 100 , 100 ] ] ) ; } )
864
+ . then ( function ( ) {
865
+ _assert ( 'multi-select across other subplot (prohibited for now)' , [
866
+ { pointNumber : 1 , x : 2 , y : 2 }
867
+ ] , {
868
+ subplot : 'xy' ,
869
+ // outlines from previous subplot are cleared!
870
+ selectionOutlineCnt : 2
871
+ } ) ;
872
+ } )
873
+ . catch ( failTest )
874
+ . then ( done ) ;
875
+ } ) ;
876
+
877
+ it ( 'should redraw splom traces before scattergl trace (if any)' , function ( done ) {
878
+ var fig = require ( '@mocks/splom_with-cartesian.json' ) ;
879
+ fig . layout . dragmode = 'select' ;
880
+ fig . layout . width = 400 ;
881
+ fig . layout . height = 400 ;
882
+ fig . layout . margin = { l : 0 , t : 0 , r : 0 , b : 0 } ;
883
+ fig . layout . grid . xgap = 0 ;
884
+ fig . layout . grid . ygap = 0 ;
885
+
886
+ var cnt = 0 ;
887
+ var scatterGlCnt = 0 ;
888
+ var splomCnt = 0 ;
889
+
890
+ Plotly . newPlot ( gd , fig ) . then ( function ( ) {
891
+ // 'scattergl' trace module
892
+ spyOn ( gd . _fullLayout . _modules [ 0 ] , 'style' ) . and . callFake ( function ( ) {
893
+ cnt ++ ;
894
+ scatterGlCnt = cnt ;
895
+ } ) ;
896
+ // 'splom' trace module
897
+ spyOn ( gd . _fullLayout . _modules [ 1 ] , 'style' ) . and . callFake ( function ( ) {
898
+ cnt ++ ;
899
+ splomCnt = cnt ;
900
+ } ) ;
901
+ } )
902
+ . then ( function ( ) { return _select ( [ [ 20 , 395 ] , [ 195 , 205 ] ] ) ; } )
903
+ . then ( function ( ) {
904
+ expect ( gd . _fullLayout . _modules [ 0 ] . style ) . toHaveBeenCalledTimes ( 1 ) ;
905
+ expect ( gd . _fullLayout . _modules [ 1 ] . style ) . toHaveBeenCalledTimes ( 1 ) ;
906
+
907
+ expect ( cnt ) . toBe ( 2 ) ;
908
+ expect ( splomCnt ) . toBe ( 1 , 'splom redraw before scattergl' ) ;
909
+ expect ( scatterGlCnt ) . toBe ( 2 , 'scattergl redraw after splom' ) ;
910
+ } )
911
+ . catch ( failTest )
912
+ . then ( done ) ;
913
+ } ) ;
914
+ } ) ;
0 commit comments