Skip to content

Commit 581f3fa

Browse files
committed
add lasso/select dragmode support to box traces
- use pts array of object to determine which box points are inside selection polygon - use index field (from Box.calc) to match each selected box point to underlying x/y input value. - dim point node opacity upon selection
1 parent 53c446b commit 581f3fa

File tree

4 files changed

+118
-4
lines changed

4 files changed

+118
-4
lines changed

src/traces/box/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Box.setPositions = require('./set_positions');
1919
Box.plot = require('./plot');
2020
Box.style = require('./style');
2121
Box.hoverPoints = require('./hover');
22+
Box.selectPoints = require('./select');
2223

2324
Box.moduleType = 'trace';
2425
Box.name = 'box';

src/traces/box/plot.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ module.exports = function plot(gd, plotinfo, cdbox) {
4848
var cd0 = d[0];
4949
var t = cd0.t;
5050
var trace = cd0.trace;
51+
var sel = cd0.node3 = d3.select(this);
5152

5253
var group = (fullLayout.boxmode === 'group' && gd.numboxes > 1);
5354
// box half width
@@ -80,7 +81,7 @@ module.exports = function plot(gd, plotinfo, cdbox) {
8081
seed();
8182

8283
// boxes and whiskers
83-
d3.select(this).selectAll('path.box')
84+
sel.selectAll('path.box')
8485
.data(Lib.identity)
8586
.enter().append('path')
8687
.style('vector-effect', 'non-scaling-stroke')
@@ -99,6 +100,7 @@ module.exports = function plot(gd, plotinfo, cdbox) {
99100
Math.min(q1, q3) + 1, Math.max(q1, q3) - 1),
100101
lf = valAxis.c2p(trace.boxpoints === false ? d.min : d.lf, true),
101102
uf = valAxis.c2p(trace.boxpoints === false ? d.max : d.uf, true);
103+
102104
if(trace.orientation === 'h') {
103105
d3.select(this).attr('d',
104106
'M' + m + ',' + pos0 + 'V' + pos1 + // median line
@@ -118,7 +120,7 @@ module.exports = function plot(gd, plotinfo, cdbox) {
118120

119121
// draw points, if desired
120122
if(trace.boxpoints) {
121-
d3.select(this).selectAll('g.points')
123+
sel.selectAll('g.points')
122124
// since box plot points get an extra level of nesting, each
123125
// box needs the trace styling info
124126
.data(function(d) {
@@ -212,9 +214,10 @@ module.exports = function plot(gd, plotinfo, cdbox) {
212214
.classed('point', true)
213215
.call(Drawing.translatePoints, xa, ya);
214216
}
217+
215218
// draw mean (and stdev diamond) if desired
216219
if(trace.boxmean) {
217-
d3.select(this).selectAll('path.mean')
220+
sel.selectAll('path.mean')
218221
.data(Lib.identity)
219222
.enter().append('path')
220223
.attr('class', 'mean')

src/traces/box/select.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Copyright 2012-2017, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var DESELECTDIM = require('../../constants/interactions').DESELECTDIM;
12+
13+
module.exports = function selectPoints(searchInfo, polygon) {
14+
var cd = searchInfo.cd;
15+
var xa = searchInfo.xaxis;
16+
var ya = searchInfo.yaxis;
17+
var trace = cd[0].trace;
18+
var node3 = cd[0].node3;
19+
var selection = [];
20+
var i, j;
21+
22+
if(trace.visible !== true) return [];
23+
24+
if(polygon === false) {
25+
for(i = 0; i < cd.length; i++) {
26+
for(j = 0; j < (cd[i].pts || []).length; j++) {
27+
// clear selection
28+
cd[i].pts[j].dim = 0;
29+
}
30+
}
31+
} else {
32+
for(i = 0; i < cd.length; i++) {
33+
for(j = 0; j < (cd[i].pts || []).length; j++) {
34+
var pt = cd[i].pts[j];
35+
var x = xa.c2p(pt.x);
36+
var y = ya.c2p(pt.y);
37+
38+
if(polygon.contains([x, y])) {
39+
selection.push({
40+
pointNumber: pt.i,
41+
x: pt.x,
42+
y: pt.y
43+
});
44+
pt.dim = 0;
45+
} else {
46+
pt.dim = 1;
47+
}
48+
}
49+
}
50+
}
51+
52+
node3.selectAll('.point').style('opacity', function(d) {
53+
return d.dim ? DESELECTDIM : 1;
54+
});
55+
56+
return selection;
57+
};

test/jasmine/tests/select_test.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,60 @@ describe('Test select box and lasso per trace:', function() {
848848
]);
849849
assertRanges([[1.66, 3.59], [0.69, 2.17]]);
850850
},
851-
null, BOXEVENTS, 'bar select'
851+
null, BOXEVENTS, 'histogram select'
852+
);
853+
})
854+
.catch(fail)
855+
.then(done);
856+
});
857+
858+
it('should work for box traces', function(done) {
859+
var assertPoints = makeAssertPoints(['curveNumber', 'y']);
860+
var assertRanges = makeAssertRanges();
861+
var assertLassoPoints = makeAssertLassoPoints();
862+
863+
var fig = Lib.extendDeep({}, require('@mocks/box_grouped'));
864+
fig.data.forEach(function(trace) {
865+
trace.boxpoints = 'all';
866+
});
867+
fig.layout.dragmode = 'lasso';
868+
fig.layout.width = 600;
869+
fig.layout.height = 500;
870+
addInvisible(fig);
871+
872+
Plotly.plot(gd, fig)
873+
.then(function() {
874+
return _run(
875+
[[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],
876+
function() {
877+
assertPoints([
878+
[0, 0.2], [0, 0.3], [0, 0.5], [0, 0.7],
879+
[1, 0.2], [1, 0.5], [1, 0.7], [1, 0.7],
880+
[2, 0.3], [2, 0.6], [2, 0.6]
881+
]);
882+
assertLassoPoints([
883+
['day 1', 'day 2', 'day 2', 'day 1', 'day 1'],
884+
[0.71, 0.71, 0.1875, 0.1875, 0.71]
885+
]);
886+
},
887+
null, LASSOEVENTS, 'box lasso'
888+
);
889+
})
890+
.then(function() {
891+
return Plotly.relayout(gd, 'dragmode', 'select');
892+
})
893+
.then(function() {
894+
return _run(
895+
[[200, 200], [400, 350]],
896+
function() {
897+
assertPoints([
898+
[0, 0.2], [0, 0.3], [0, 0.5], [0, 0.7],
899+
[1, 0.2], [1, 0.5], [1, 0.7], [1, 0.7],
900+
[2, 0.3], [2, 0.6], [2, 0.6]
901+
]);
902+
assertRanges([['day 1', 'day 2'], [0.1875, 0.71]]);
903+
},
904+
null, BOXEVENTS, 'box select'
852905
);
853906
})
854907
.catch(fail)

0 commit comments

Comments
 (0)