Skip to content

Commit f8a9a8d

Browse files
committed
Merge pull request #154 from plotly/lasso
Lasso & rectangular selections
2 parents 6e128e8 + 1d7745f commit f8a9a8d

21 files changed

+1039
-113
lines changed

.agignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist

src/components/modebar/buttons.js

+26-1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,24 @@ modeBarButtons.pan2d = {
121121
click: handleCartesian
122122
};
123123

124+
modeBarButtons.select2d = {
125+
name: 'select2d',
126+
title: 'Box Select',
127+
attr: 'dragmode',
128+
val: 'select',
129+
icon: Icons.selectbox,
130+
click: handleCartesian
131+
};
132+
133+
modeBarButtons.lasso2d = {
134+
name: 'lasso2d',
135+
title: 'Lasso Select',
136+
attr: 'dragmode',
137+
val: 'lasso',
138+
icon: Icons.lasso,
139+
click: handleCartesian
140+
};
141+
124142
modeBarButtons.zoomIn2d = {
125143
name: 'zoomIn2d',
126144
title: 'Zoom in',
@@ -179,6 +197,13 @@ modeBarButtons.hoverCompareCartesian = {
179197
click: handleCartesian
180198
};
181199

200+
var DRAGCURSORS = {
201+
pan: 'move',
202+
zoom: 'crosshair',
203+
select: 'crosshair',
204+
lasso: 'crosshair'
205+
};
206+
182207
function handleCartesian(gd, ev) {
183208
var button = ev.currentTarget,
184209
astr = button.getAttribute('data-attr'),
@@ -230,7 +255,7 @@ function handleCartesian(gd, ev) {
230255
if(fullLayout._hasCartesian) {
231256
Plotly.Fx.setCursor(
232257
fullLayout._paper.select('.nsewdrag'),
233-
{pan:'move', zoom:'crosshair'}[val]
258+
DRAGCURSORS[val]
234259
);
235260
}
236261
Plotly.Fx.supplyLayoutDefaults(gd.layout, fullLayout, gd._fullData);

src/components/modebar/manage.js

+41-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
'use strict';
1111

1212
var Plotly = require('../../plotly');
13+
var scatterSubTypes = require('../../traces/scatter/subtypes');
1314

1415
var createModeBar = require('./');
1516
var modeBarButtons = require('./buttons');
@@ -57,7 +58,7 @@ module.exports = function manageModeBar(gd) {
5758
}
5859
else {
5960
buttonGroups = getButtonGroups(
60-
fullLayout,
61+
gd,
6162
context.modeBarButtonsToRemove,
6263
context.modeBarButtonsToAdd
6364
);
@@ -68,8 +69,12 @@ module.exports = function manageModeBar(gd) {
6869
};
6970

7071
// logic behind which buttons are displayed by default
71-
function getButtonGroups(fullLayout, buttonsToRemove, buttonsToAdd) {
72-
var groups = [];
72+
function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) {
73+
var fullLayout = gd._fullLayout,
74+
fullData = gd._fullData,
75+
groups = [],
76+
i,
77+
trace;
7378

7479
function addGroup(newGroup) {
7580
var out = [];
@@ -99,10 +104,40 @@ function getButtonGroups(fullLayout, buttonsToRemove, buttonsToAdd) {
99104

100105
var hasCartesian = fullLayout._hasCartesian,
101106
hasGL2D = fullLayout._hasGL2D,
102-
allAxesFixed = areAllAxesFixed(fullLayout);
107+
allAxesFixed = areAllAxesFixed(fullLayout),
108+
dragModeGroup = [];
109+
110+
if((hasCartesian || hasGL2D) && !allAxesFixed) {
111+
dragModeGroup = ['zoom2d', 'pan2d'];
112+
}
113+
if(hasCartesian) {
114+
// look for traces that support selection
115+
// to be updated as we add more selectPoints handlers
116+
var selectable = false;
117+
for(i = 0; i < fullData.length; i++) {
118+
if(selectable) break;
119+
trace = fullData[i];
120+
if(!trace._module || !trace._module.selectPoints) continue;
121+
122+
if(trace.type === 'scatter') {
123+
if(scatterSubTypes.hasMarkers(trace) || scatterSubTypes.hasText(trace)) {
124+
selectable = true;
125+
}
126+
}
127+
// assume that in general if the trace module has selectPoints,
128+
// then it's selectable. Scatter is an exception to this because it must
129+
// have markers or text, not just be a scatter type.
130+
else selectable = true;
131+
}
132+
133+
if(selectable) {
134+
dragModeGroup.push('select2d');
135+
dragModeGroup.push('lasso2d');
136+
}
137+
}
138+
if(dragModeGroup.length) addGroup(dragModeGroup);
103139

104140
if((hasCartesian || hasGL2D) && !allAxesFixed) {
105-
addGroup(['zoom2d', 'pan2d']);
106141
addGroup(['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d']);
107142
}
108143

@@ -119,7 +154,7 @@ function getButtonGroups(fullLayout, buttonsToRemove, buttonsToAdd) {
119154
// append buttonsToAdd to the groups
120155
if(buttonsToAdd.length) {
121156
if(Array.isArray(buttonsToAdd[0])) {
122-
for(var i = 0; i < buttonsToAdd.length; i++) {
157+
for(i = 0; i < buttonsToAdd.length; i++) {
123158
groups.push(buttonsToAdd[i]);
124159
}
125160
}

src/css/_drag.scss

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.select-outline {
2+
fill: none;
3+
stroke-width: 1;
4+
shape-rendering: crispEdges;
5+
}
6+
.select-outline-1 {
7+
stroke: white;
8+
}
9+
.select-outline-2 {
10+
stroke: black;
11+
stroke-dasharray: 2px 2px;
12+
}

src/css/style.scss

+1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
@import "cursor.scss";
77
@import "modebar.scss";
88
@import "tooltip.scss";
9+
@import "drag.scss";
910
}
1011
@import "notifier.scss";

src/fonts/ploticon/_ploticon.scss

+2
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,5 @@
4141
.ploticon-movie:before { content: '\e80e'; } /* '' */
4242
.ploticon-question:before { content: '\e80f'; } /* '' */
4343
.ploticon-disk:before { content: '\e810'; } /* '' */
44+
.ploticon-lasso:before { content: '\e811'; } /* '' */
45+
.ploticon-selectbox:before { content: '\e812'; } /* '' */

src/fonts/ploticon/config.json

+20
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,26 @@
14621462
"movie"
14631463
]
14641464
},
1465+
{
1466+
"uid": "11aaeff1fa846b5a34638dbb78619c59",
1467+
"css": "lasso",
1468+
"code": 59409,
1469+
"src": "custom_icons",
1470+
"selected": true,
1471+
"svg": {
1472+
"path": "M1018.2 311.9C981.8 105 727.8-23.6 450.2 25.7 172.6 74-22.5 281.9 13.9 488.7 23.6 545.6 50.4 597 90 639.9 77.2 706.3 100.8 777.1 157.6 823.2 191.9 851 232.6 863.9 272.2 865L216.5 934.6 216.5 934.6C215.4 935.7 214.4 936.8 213.3 937.8 202.6 951.8 204.7 972.1 217.6 982.9 231.5 993.6 251.9 991.4 262.6 978.6 263.7 977.5 264.7 976.4 264.7 974.3L264.7 974.3 378.3 833.9C394.4 823.2 409.4 810.3 423.4 794.2 426.6 791 428.7 786.7 430.9 783.5 479.1 785.6 530.5 783.5 582 773.8 859.6 725.6 1054.7 518.8 1018.2 311.9ZM394.4 691.3C314 677.4 245.4 643.1 197.2 594.9 239 553.1 305.5 547.7 352.6 586.3 385.9 612 399.8 651.7 394.4 691.3ZM206.9 765.3C187.6 749.2 173.6 727.8 168.3 705.3 217.6 737.4 276.5 759.9 341.9 772.8 300.1 798.5 246.5 797.4 206.9 765.3ZM567 690.2C532.7 696.7 498.4 698.8 465.2 697.7 472.7 635.6 449.1 570.2 396.6 528.4 323.7 469.5 221.9 473.7 153.3 532.7 143.6 513.4 137.2 493 132.9 471.6 105 313 254 155.4 466.2 117.9S872.5 177.9 900.3 335.5C928.2 494.1 779.2 652.7 567 690.2Z",
1473+
"width": 1031
1474+
},
1475+
"search": [
1476+
"lasso"
1477+
]
1478+
},
1479+
{
1480+
"uid": "8ce732688587909ad0a9d8323eaca8ad",
1481+
"css": "selectbox",
1482+
"code": 59410,
1483+
"src": "fontelico"
1484+
},
14651485
{
14661486
"uid": "9d3d9d6ce1ec63eaa26281e6162853c9",
14671487
"css": "camera-retro",

src/fonts/ploticon/ploticon.eot

456 Bytes
Binary file not shown.

src/fonts/ploticon/ploticon.svg

+3-1
Loading

src/fonts/ploticon/ploticon.ttf

456 Bytes
Binary file not shown.

src/fonts/ploticon/ploticon.woff

320 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)