Skip to content

Commit 07e5cef

Browse files
committed
selection on scatter points
1 parent 12b43c6 commit 07e5cef

File tree

2 files changed

+99
-5
lines changed

2 files changed

+99
-5
lines changed

src/plots/cartesian/select.js

+47-5
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99

1010
'use strict';
1111
var polygon = require('../../lib/polygon');
12+
var axes = require('./axes');
1213
var filteredPolygon = polygon.filter;
14+
var polygonTester = polygon.tester;
1315
var BENDPX = 1.5; // max pixels off straight before a line counts as bent
1416

17+
function getAxId(ax) { return ax._id; }
18+
1519
module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
1620
var plot = dragOptions.plotinfo.plot,
1721
dragBBox = dragOptions.element.getBoundingClientRect(),
@@ -21,7 +25,10 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
2125
y1 = y0,
2226
path0 = 'M' + x0 + ',' + y0,
2327
pw = dragOptions.xaxes[0]._length,
24-
ph = dragOptions.yaxes[0]._length;
28+
ph = dragOptions.yaxes[0]._length,
29+
xAxisIds = dragOptions.xaxes.map(getAxId),
30+
yAxisIds = dragOptions.yaxes.map(getAxId);
31+
2532
if(mode === 'lasso') {
2633
var pts = filteredPolygon([[x0, y0]], BENDPX);
2734
}
@@ -33,28 +40,63 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
3340
.attr('class', function(d) { return 'select-outline select-outline-' + d; })
3441
.attr('d', path0 + 'Z');
3542

43+
// find the traces to search for selection points
44+
var searchTraces = [],
45+
gd = dragOptions.gd,
46+
i,
47+
cd,
48+
trace,
49+
searchInfo,
50+
selection = [];
51+
for(i = 0; i < gd.calcdata.length; i++) {
52+
cd = gd.calcdata[i];
53+
trace = cd[0].trace;
54+
if(!trace._module || !trace._module.selectPoints) continue;
55+
56+
if(xAxisIds.indexOf(trace.xaxis) === -1) continue;
57+
if(yAxisIds.indexOf(trace.yaxis) === -1) continue;
58+
59+
searchTraces.push({
60+
selectPoints: trace._module.selectPoints,
61+
cd: cd,
62+
xaxis: axes.getFromId(gd, trace.xaxis),
63+
yaxis: axes.getFromId(gd, trace.yaxis)
64+
});
65+
}
66+
3667
dragOptions.moveFn = function(dx0, dy0) {
68+
var poly;
3769
x1 = Math.max(0, Math.min(pw, dx0 + x0));
3870
y1 = Math.max(0, Math.min(ph, dy0 + y0));
3971

4072
if(mode === 'select') {
73+
poly = polygonTester([[x0, y0], [x0, y1], [x1, y1], [x1, y0]]);
4174
outlines.attr('d', path0 + 'H' + x1 + 'V' + y1 + 'H' + x0 + 'Z');
4275
}
4376
else if(mode === 'lasso') {
4477
pts.addPt([x1, y1]);
45-
outlines.attr('d', 'M' + pts.filtered.join('L'));
78+
poly = polygonTester(pts.filtered);
79+
outlines.attr('d', 'M' + pts.filtered.join('L') + 'Z');
4680
}
4781

48-
// TODO - actual selection and dimming!
82+
selection = [];
83+
for(i = 0; i < searchTraces.length; i++) {
84+
searchInfo = searchTraces[i];
85+
[].push.apply(selection, searchInfo.selectPoints(searchInfo, poly));
86+
}
87+
dragOptions.gd.emit('plotly_selecting', {points: selection});
4988
};
5089

5190
dragOptions.doneFn = function(dragged, numclicks) {
5291
if(!dragged && numclicks === 2) dragOptions.doubleclick();
5392
else {
54-
// TODO - select event
93+
dragOptions.gd.emit('plotly_selected', {points: selection});
5594
}
5695
outlines.remove();
57-
// TODO - remove dimming
96+
for(i = 0; i < searchTraces.length; i++) {
97+
searchInfo = searchTraces[i];
98+
searchInfo.selectPoints(searchInfo, false);
99+
}
58100
};
59101
};
60102

src/traces/scatter/index.js

+52
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ scatter.plot = function(gd, plotinfo, cdscatter) {
458458
line = trace.line;
459459
if(trace.visible !== true) return;
460460

461+
d[0].node = this; // store node for tweaking by selectPoints
462+
461463
scatter.arraysToCalcdata(d);
462464

463465
if(!scatter.hasLines(trace) && trace.fill==='none') return;
@@ -855,3 +857,53 @@ scatter.hoverPoints = function(pointData, xval, yval, hovermode) {
855857

856858
return [pointData];
857859
};
860+
861+
var DESELECTDIM = 0.2;
862+
863+
scatter.selectPoints = function(searchInfo, polygon) {
864+
var cd = searchInfo.cd,
865+
xa = searchInfo.xaxis,
866+
ya = searchInfo.yaxis,
867+
selection = [],
868+
curveNumber = cd[0].trace.index,
869+
marker = cd[0].trace.marker,
870+
i,
871+
di,
872+
x,
873+
y;
874+
875+
if(!marker) return; // TODO: include text and/or lines?
876+
877+
var opacity = Array.isArray(marker.opacity) ? 1 : marker.opacity;
878+
879+
if(polygon === false) { // clear selection
880+
for(i = 0; i < cd.length; i++) cd[i].dim = 0;
881+
}
882+
else {
883+
for(i = 0; i < cd.length; i++) {
884+
di = cd[i];
885+
x = xa.c2p(di.x);
886+
y = ya.c2p(di.y);
887+
if(polygon.contains([x, y])) {
888+
selection.push({
889+
curveNumber: curveNumber,
890+
pointNumber: i,
891+
x: di.x,
892+
y: di.y
893+
});
894+
di.dim = 0;
895+
}
896+
else di.dim = 1;
897+
}
898+
}
899+
900+
// do the dimming here, as well as returning the selection
901+
// The logic here duplicates Drawing.pointStyle, but I don't want
902+
// d.dim in pointStyle in case something goes wrong with selection.
903+
d3.select(cd[0].node).selectAll('path.point')
904+
.style('opacity', function(d) {
905+
return ((d.mo+1 || opacity+1) - 1) * (d.dim ? DESELECTDIM : 1);
906+
});
907+
908+
return selection;
909+
};

0 commit comments

Comments
 (0)