Skip to content

Configurable select direction #2506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
12 changes: 12 additions & 0 deletions src/components/fx/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,17 @@ module.exports = {
].join(' ')
},
editType: 'none'
},
selectdirection: {
valType: 'enumerated',
role: 'info',
values: ['h', 'v', 'd', 'any'],
dflt: 'any',
description: [
'When "dragmode" is set to "select", this limits the selection of the drag to',
'horizontal, vertical or diagonal. "h" only allows horizontal selection,',
'"v" only vertical, "d" only diagonal and "any" sets no limit.'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I like 'd', I guess what it allows that 'any' doesn't is selecting regions that are very narrow in height or width, which would otherwise devolve to pure horizontal or vertical selections. Cool.

].join(' '),
editType: 'none'
}
};
3 changes: 2 additions & 1 deletion src/components/fx/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}

coerce('dragmode');
var dragMode = coerce('dragmode');
if(dragMode === 'select') coerce('selectdirection');

var hovermodeDflt;
if(layoutOut._has('cartesian')) {
Expand Down
17 changes: 14 additions & 3 deletions src/plots/cartesian/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,18 @@ function prepSelect(e, startX, startY, dragOptions, mode) {
dy = Math.abs(y1 - y0);

if(mode === 'select') {
if(dy < Math.min(dx * 0.6, MINSELECT)) {
var direction = fullLayout.selectdirection;

if(fullLayout.selectdirection === 'any') {
if(dy < Math.min(dx * 0.6, MINSELECT)) direction = 'h';
else if(dx < Math.min(dy * 0.6, MINSELECT)) direction = 'v';
else direction = 'd';
}
else {
direction = fullLayout.selectdirection;
}

if(direction === 'h') {
// horizontal motion: make a vertical box
currentPolygon = [[x0, 0], [x0, ph], [x1, ph], [x1, 0]];
currentPolygon.xmin = Math.min(x0, x1);
Expand All @@ -214,7 +225,7 @@ function prepSelect(e, startX, startY, dragOptions, mode) {
'h4v' + (2 * MINSELECT) + 'h-4Z');

}
else if(dx < Math.min(dy * 0.6, MINSELECT)) {
else if(direction === 'v') {
// vertical motion: make a horizontal box
currentPolygon = [[0, y0], [0, y1], [pw, y1], [pw, y0]];
currentPolygon.xmin = Math.min(0, pw);
Expand All @@ -226,7 +237,7 @@ function prepSelect(e, startX, startY, dragOptions, mode) {
'M' + (x0 - MINSELECT) + ',' + (currentPolygon.ymax - 1) +
'v4h' + (2 * MINSELECT) + 'v-4Z');
}
else {
else if(direction === 'd') {
// diagonal motion
currentPolygon = [[x0, y0], [x0, y1], [x1, y1], [x1, y0]];
currentPolygon.xmin = Math.min(x0, x1);
Expand Down
63 changes: 63 additions & 0 deletions test/jasmine/tests/select_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,69 @@ describe('@flaky Test select box and lasso in general:', function() {
.catch(failTest)
.then(done);
});

it('should select the right data with the corresponding select direction', function(done) {

var gd = createGraphDiv();

// drag around just the center point, but if we have a selectdirection we may
// get either the ones to the left and right or above and below
var selectPath = [[175, 175], [225, 225]];

function selectDrag() {
resetEvents(gd);
drag(selectPath);
return selectedPromise;
}

function assertSelectedPointNumbers(pointNumbers) {
var pts = selectedData.points;
expect(pts.length).toBe(pointNumbers.length);
pointNumbers.forEach(function(pointNumber, i) {
expect(pts[i].pointNumber).toBe(pointNumber);
});
}

Plotly.newPlot(gd, [{
x: [1, 1, 1, 2, 2, 2, 3, 3, 3],
y: [1, 2, 3, 1, 2, 3, 1, 2, 3],
mode: 'markers'
}], {
width: 400,
height: 400,
dragmode: 'select',
margin: {l: 100, r: 100, t: 100, b: 100},
xaxis: {range: [0, 4]},
yaxis: {range: [0, 4]}
})
.then(selectDrag)
.then(function() {
expect(gd._fullLayout.selectdirection).toBe('any');
assertSelectedPointNumbers([4]);

return Plotly.relayout(gd, {selectdirection: 'h'});
})
.then(selectDrag)
.then(function() {
assertSelectedPointNumbers([3, 4, 5]);

return Plotly.relayout(gd, {selectdirection: 'v'});
})
.then(selectDrag)
.then(function() {
assertSelectedPointNumbers([1, 4, 7]);

return Plotly.relayout(gd, {selectdirection: 'd'});
})
.then(selectDrag)
.then(function() {
assertSelectedPointNumbers([4]);
})
.catch(failTest)
.then(done);

});

});

describe('@flaky Test select box and lasso per trace:', function() {
Expand Down
2 changes: 1 addition & 1 deletion test/jasmine/tests/shapes_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1026,7 +1026,7 @@ describe('A fixed size shape', function() {

var shapeAndResizeTypes = combinations(shapeTypes, resizeTypes);
shapeAndResizeTypes.forEach(function(testCase) {
describe('of type ' + testCase.type + ' can be ' + testCase.resizeDisplayName, function() {
describe('@flaky of type ' + testCase.type + ' can be ' + testCase.resizeDisplayName, function() {
resizeDirections.forEach(function(direction) {
it('over direction ' + direction, function(done) {
layout.shapes[0].type = testCase.type;
Expand Down