Skip to content

Commit a79f5dc

Browse files
committed
add splom hover/selection/drag tests
1 parent 31e34fa commit a79f5dc

File tree

1 file changed

+367
-0
lines changed

1 file changed

+367
-0
lines changed

test/jasmine/tests/splom_test.js

+367
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ var supplyAllDefaults = require('../assets/supply_defaults');
88
var createGraphDiv = require('../assets/create_graph_div');
99
var destroyGraphDiv = require('../assets/destroy_graph_div');
1010
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;
1116

1217
describe('Test splom trace defaults:', function() {
1318
var gd;
@@ -545,3 +550,365 @@ describe('@gl Test splom interactions:', function() {
545550
.then(done);
546551
});
547552
});
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

Comments
 (0)