Skip to content

Commit a72f7a9

Browse files
committed
Add lassoClearEvent property
Address #19
1 parent 524716e commit a72f7a9

7 files changed

Lines changed: 89 additions & 17 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## v0.10.0
2+
3+
- Add `lassoClearEvent` property to allow customizing when the lasso is cleared.
4+
- Add `preventEvent` option to `scatterplot.select()` and `scatterplot.deselect()` to prevent publishing the `select` and `deselect` events
5+
- Add Promise-based return value to `scatterplot.draw()` to enable the parent application to determine when the points were drawn
6+
- Add support for `get('lassoMinDelay')` and `get('lassoMinDist')`
7+
18
## v0.9.1
29

310
- Only listen on mouse down events within the instance's canvas element (#16)

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ scatterplot.draw([]);
178178
| lassoColor | quadruple | rgba(0, 0.667, 1, 1) | hex, rgb, rgba | `true` | `false` |
179179
| lassoMinDelay | integer | 15 | >= 0 | `true` | `false` |
180180
| lassoMinDist | integer | 4 | >= 0 | `true` | `false` |
181+
| lassoClearEvent | string | `'lassoEnd'` | `'lassoEnd'` or `'deselect'` | `true` | `false` |
181182
| showRecticle | boolean | `false` | `true` or `false` | `true` | `false` |
182183
| recticleColor | quadruple | rgba(1, 1, 1, .5) | hex, rgb, rgba | `true` | `false` |
183184

@@ -275,6 +276,8 @@ scatterplot.set({
275276
lassoColor: [1, 1, 1, 1],
276277
lassoMinDelay: 0,
277278
lassoMinDist: 1,
279+
// This will keep the drawn lasso until the selected points are deselected
280+
lassoClearEvent: 'deselect',
278281
});
279282

280283
// Activate recticle and set recticle color to red

example/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const scatterplot = createScatterplot({
6565
pointSize,
6666
showRecticle,
6767
recticleColor,
68+
lassoClearEvent: 'deselect',
6869
});
6970

7071
console.log(scatterplot.get('pointColorActive'));

src/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ export const FLOAT_BYTES = Float32Array.BYTES_PER_ELEMENT;
77
export const GL_EXTENSIONS = ['OES_standard_derivatives', 'OES_texture_float'];
88

99
// Default lasso
10+
export const LASSO_CLEAR_ON_DESELECT = 'deselect';
11+
export const LASSO_CLEAR_ON_END = 'lassoEnd';
12+
export const LASSO_CLEAR_EVENTS = [LASSO_CLEAR_ON_DESELECT, LASSO_CLEAR_ON_END];
1013
export const DEFAULT_LASSO_MIN_DELAY = 10;
1114
export const DEFAULT_LASSO_MIN_DIST = 3;
15+
export const DEFAULT_LASSO_CLEAR_EVENT = LASSO_CLEAR_ON_END;
1216

1317
// Default attribute
1418
export const DEFAULT_DATA_ASPECT_RATIO = 1;

src/index.js

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
DEFAULT_LASSO_COLOR,
3030
DEFAULT_LASSO_MIN_DELAY,
3131
DEFAULT_LASSO_MIN_DIST,
32+
DEFAULT_LASSO_CLEAR_EVENT,
3233
DEFAULT_SHOW_RECTICLE,
3334
DEFAULT_RECTICLE_COLOR,
3435
DEFAULT_POINT_OUTLINE_WIDTH,
@@ -39,6 +40,9 @@ import {
3940
DEFAULT_VIEW,
4041
DEFAULT_WIDTH,
4142
FLOAT_BYTES,
43+
LASSO_CLEAR_EVENTS,
44+
LASSO_CLEAR_ON_DESELECT,
45+
LASSO_CLEAR_ON_END,
4246
} from './constants';
4347

4448
import {
@@ -50,6 +54,7 @@ import {
5054
isMultipleColors,
5155
isPointInPolygon,
5256
isString,
57+
limit,
5358
toRgba,
5459
max,
5560
min,
@@ -96,6 +101,7 @@ const createScatterplot = (initialProperties = {}) => {
96101
lassoColor: initialLassoColor = DEFAULT_LASSO_COLOR,
97102
lassoMinDelay: initialLassoMinDelay = DEFAULT_LASSO_MIN_DELAY,
98103
lassoMinDist: initialLassoMinDist = DEFAULT_LASSO_MIN_DIST,
104+
lassoClearEvent: initialLassoClearEvent = DEFAULT_LASSO_CLEAR_EVENT,
99105
showRecticle: initialShowRecticle = DEFAULT_SHOW_RECTICLE,
100106
recticleColor: initialRecticleColor = DEFAULT_RECTICLE_COLOR,
101107
pointColor: initialPointColor = DEFAULT_COLOR_NORMAL,
@@ -136,9 +142,9 @@ const createScatterplot = (initialProperties = {}) => {
136142
let lassoColor = toRgba(initialLassoColor, true);
137143
let lassoMinDelay = +initialLassoMinDelay;
138144
let lassoMinDist = +initialLassoMinDist;
145+
let lassoClearEvent = initialLassoClearEvent;
139146
let lassoPos = [];
140147
let lassoPoints = [];
141-
let lassoScatterPos = [];
142148
let lassoPrevMousePos;
143149
let searchIndex;
144150
let viewAspectRatio;
@@ -259,19 +265,17 @@ const createScatterplot = (initialProperties = {}) => {
259265
const currMousePos = getMousePos();
260266

261267
if (!lassoPrevMousePos) {
262-
const point = getMouseGlPos(currMousePos);
263-
lassoPos = [point[0], point[1]];
268+
const point = getScatterGlPos(currMousePos);
269+
lassoPos = [...point];
264270
lassoPoints = [point];
265-
lassoScatterPos = [...getScatterGlPos(currMousePos)];
266271
lassoPrevMousePos = currMousePos;
267272
} else {
268273
const d = dist(...currMousePos, ...lassoPrevMousePos);
269274

270275
if (d > lassoMinDist) {
271-
const point = getMouseGlPos(currMousePos);
272-
lassoPos.push(point[0], point[1]);
276+
const point = getScatterGlPos(currMousePos);
277+
lassoPos.push(...point);
273278
lassoPoints.push(point);
274-
lassoScatterPos.push(...getScatterGlPos(currMousePos));
275279
lassoPrevMousePos = currMousePos;
276280
if (lassoPos.length > 2) {
277281
lasso.setPoints(lassoPos);
@@ -296,7 +300,14 @@ const createScatterplot = (initialProperties = {}) => {
296300
return pointsInPolygon;
297301
};
298302

303+
const lassoClear = () => {
304+
lassoPos = [];
305+
lassoPoints = [];
306+
lasso.clear();
307+
};
308+
299309
const deselect = ({ preventEvent = false } = {}) => {
310+
if (lassoClearEvent === LASSO_CLEAR_ON_DESELECT) lassoClear();
300311
if (selection.length) {
301312
if (!preventEvent) pubSub.publish('deselect');
302313
selection = [];
@@ -332,20 +343,17 @@ const createScatterplot = (initialProperties = {}) => {
332343
camera.config({ isFixed: true });
333344
// Make sure we start a new lasso selection
334345
lassoPrevMousePos = undefined;
335-
lasso.clear();
346+
lassoClear();
336347
};
337348

338349
const lassoEnd = () => {
339350
camera.config({ isFixed: false });
340351
// const t0 = performance.now();
341-
const pointsInLasso = findPointsInLasso(lassoScatterPos);
352+
const pointsInLasso = findPointsInLasso(lassoPos);
342353
// console.log(`found ${pointsInLasso.length} in ${performance.now() - t0} msec`);
343354
select(pointsInLasso);
344-
lassoPos = [];
345-
lassoPoints = [];
346-
lassoScatterPos = [];
347355
lassoPrevMousePos = undefined;
348-
lasso.clear();
356+
if (lassoClearEvent === LASSO_CLEAR_ON_END) lassoClear();
349357
};
350358

351359
const mouseDownHandler = (event) => {
@@ -698,9 +706,12 @@ const createScatterplot = (initialProperties = {}) => {
698706
const drawPolygon2d = regl({
699707
vert: `
700708
precision mediump float;
709+
uniform mat4 projection;
710+
uniform mat4 model;
711+
uniform mat4 view;
701712
attribute vec2 position;
702713
void main () {
703-
gl_Position = vec4(position, 0, 1);
714+
gl_Position = projection * view * model * vec4(position, 0, 1);
704715
}`,
705716

706717
frag: `
@@ -727,6 +738,9 @@ const createScatterplot = (initialProperties = {}) => {
727738
},
728739

729740
uniforms: {
741+
projection: getProjection,
742+
model: getModel,
743+
view: getView,
730744
color: () => lassoColor,
731745
},
732746

@@ -855,7 +869,11 @@ const createScatterplot = (initialProperties = {}) => {
855869

856870
if (lassoPoints.length > 2) drawPolygon2d();
857871

858-
lasso.draw();
872+
lasso.draw({
873+
projection: getProjection(),
874+
model: getModel(),
875+
view: getView(),
876+
});
859877

860878
// Publish camera change
861879
if (isViewChanged) pubSub.publish('view', camera.view);
@@ -932,6 +950,13 @@ const createScatterplot = (initialProperties = {}) => {
932950
lassoMinDist = +newLassoMinDist;
933951
};
934952

953+
const setLassoClearEvent = (newLassoClearEvent) => {
954+
lassoClearEvent = limit(
955+
LASSO_CLEAR_EVENTS,
956+
lassoClearEvent
957+
)(newLassoClearEvent);
958+
};
959+
935960
const setShowRecticle = (newShowRecticle) => {
936961
if (newShowRecticle === null) return;
937962

@@ -975,6 +1000,7 @@ const createScatterplot = (initialProperties = {}) => {
9751000
if (property === 'lassoColor') return lassoColor;
9761001
if (property === 'lassoMinDelay') return lassoMinDelay;
9771002
if (property === 'lassoMinDist') return lassoMinDist;
1003+
if (property === 'lassoClearEvent') return lassoClearEvent;
9781004
if (property === 'opacity') return opacity;
9791005
if (property === 'pointColor')
9801006
return pointColors.length === 1 ? pointColors[0] : pointColors;
@@ -1060,6 +1086,10 @@ const createScatterplot = (initialProperties = {}) => {
10601086
setLassoMinDist(properties.lassoMinDist);
10611087
}
10621088

1089+
if (properties.lassoClearEvent !== undefined) {
1090+
setLassoClearEvent(properties.lassoClearEvent);
1091+
}
1092+
10631093
if (properties.showRecticle !== undefined) {
10641094
setShowRecticle(properties.showRecticle);
10651095
}

src/utils.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ export const hexToRgb = (hex, isNormalize = false) =>
102102
.match(/.{2}/g)
103103
.map((x) => parseInt(x, 16) / 255 ** isNormalize);
104104

105+
/**
106+
* Create a function to limit choices to a predefined list
107+
* @param {array} choices Array of acceptable choices
108+
* @param {*} defaultOption Default choice
109+
* @return {function} Function limiting the choices
110+
*/
111+
export const limit = (choices, defaultChoice) => (choice) =>
112+
choices.indexOf(choice) >= 0 ? choice : defaultChoice;
113+
105114
/**
106115
* Promised-based image loading
107116
* @param {string} src Remote image source, i.e., a URL

tests/index.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
DEFAULT_WIDTH,
2323
DEFAULT_LASSO_MIN_DELAY,
2424
DEFAULT_LASSO_MIN_DIST,
25+
DEFAULT_LASSO_CLEAR_EVENT,
2526
} from '../src/constants';
2627

2728
import {
@@ -502,7 +503,7 @@ test('set({ opacity })', async (t) => {
502503
);
503504
});
504505

505-
test('set({ lassoColor, lassoMinDist, lassoMinDelay })', async (t) => {
506+
test('set({ lassoColor, lassoMinDist, lassoMinDelay, lassoClearEvent })', async (t) => {
506507
const scatterplot = createScatterplot({ canvas: createCanvas() });
507508

508509
// Check default lasso color, min distance, and min delay
@@ -521,12 +522,18 @@ test('set({ lassoColor, lassoMinDist, lassoMinDelay })', async (t) => {
521522
DEFAULT_LASSO_MIN_DELAY,
522523
`lassoMinDelay should be set to ${DEFAULT_LASSO_MIN_DELAY}`
523524
);
525+
t.equal(
526+
scatterplot.get('lassoClearEvent'),
527+
DEFAULT_LASSO_CLEAR_EVENT,
528+
`lassoClearEvent should be set to ${DEFAULT_LASSO_CLEAR_EVENT}`
529+
);
524530

525531
const lassoColor = [1, 0, 0, 1];
526532
const lassoMinDist = 10;
527533
const lassoMinDelay = 150;
534+
const lassoClearEvent = 'deselect';
528535

529-
scatterplot.set({ lassoColor, lassoMinDist, lassoMinDelay });
536+
scatterplot.set({ lassoColor, lassoMinDist, lassoMinDelay, lassoClearEvent });
530537

531538
t.equal(
532539
scatterplot.get('lassoColor'),
@@ -543,11 +550,17 @@ test('set({ lassoColor, lassoMinDist, lassoMinDelay })', async (t) => {
543550
lassoMinDelay,
544551
`lassoMinDelay should be set to ${lassoMinDelay}`
545552
);
553+
t.equal(
554+
scatterplot.get('lassoClearEvent'),
555+
lassoClearEvent,
556+
`lassoClearEvent should be set to ${lassoClearEvent}`
557+
);
546558

547559
scatterplot.set({
548560
lassoColor: null,
549561
lassoMinDist: null,
550562
lassoMinDelay: null,
563+
lassoClearEvent: null,
551564
});
552565

553566
t.equal(
@@ -565,6 +578,11 @@ test('set({ lassoColor, lassoMinDist, lassoMinDelay })', async (t) => {
565578
lassoMinDelay,
566579
'lassoMinDelay should not be nullifyable'
567580
);
581+
t.equal(
582+
scatterplot.get('lassoClearEvent'),
583+
lassoClearEvent,
584+
'lassoClearEvent should not be nullifyable'
585+
);
568586
});
569587

570588
test('set({ pointOutlineWidth })', async (t) => {

0 commit comments

Comments
 (0)