Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 29f94b6

Browse filesBrowse files
authored
Merge pull request plotly#3810 from plotly/scattergl-selection-fixes
scattergl selection fixes
2 parents 862f1f8 + f5b2902 commit 29f94b6
Copy full SHA for 29f94b6

File tree

8 files changed

+367
-249
lines changed
Filter options

8 files changed

+367
-249
lines changed

‎package.json

Copy file name to clipboardExpand all lines: package.json
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
"dependencies": {
5959
"@plotly/d3-sankey": "0.7.2",
6060
"alpha-shape": "^1.0.0",
61-
"array-range": "^1.0.1",
6261
"canvas-fit": "^1.5.0",
6362
"color-normalize": "^1.3.0",
6463
"convex-hull": "^1.0.3",

‎src/traces/scattergl/index.js

Copy file name to clipboardExpand all lines: src/traces/scattergl/index.js
+64-72Lines changed: 64 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ var createScatter = require('regl-scatter2d');
1212
var createLine = require('regl-line2d');
1313
var createError = require('regl-error2d');
1414
var cluster = require('point-cluster');
15-
var arrayRange = require('array-range');
1615
var Text = require('gl-text');
1716

1817
var Registry = require('../../registry');
@@ -116,7 +115,6 @@ function calc(gd, trace) {
116115
opts.marker.snap = stash.tree || TOO_MANY_POINTS;
117116
}
118117

119-
// save scene opts batch
120118
scene.lineOptions.push(opts.line);
121119
scene.errorXOptions.push(opts.errorX);
122120
scene.errorYOptions.push(opts.errorY);
@@ -127,8 +125,9 @@ function calc(gd, trace) {
127125
scene.textOptions.push(opts.text);
128126
scene.textSelectedOptions.push(opts.textSel);
129127
scene.textUnselectedOptions.push(opts.textUnsel);
128+
scene.selectBatch.push([]);
129+
scene.unselectBatch.push([]);
130130

131-
// stash scene ref
132131
stash._scene = scene;
133132
stash.index = scene.count;
134133
stash.x = x;
@@ -146,7 +145,6 @@ function expandForErrorBars(trace, ax, opts) {
146145
extremes.max = extremes.max.concat(errExt.max);
147146
}
148147

149-
// create scene options
150148
function sceneOptions(gd, subplot, trace, positions, x, y) {
151149
var opts = convert.style(gd, trace);
152150

@@ -193,13 +191,12 @@ function sceneOptions(gd, subplot, trace, positions, x, y) {
193191
return opts;
194192
}
195193

196-
197194
// make sure scene exists on subplot, return it
198195
function sceneUpdate(gd, subplot) {
199196
var scene = subplot._scene;
200197

201198
var resetOpts = {
202-
// number of traces in subplot, since scene:subplot 1:1
199+
// number of traces in subplot, since scene:subplot -> 1:1
203200
count: 0,
204201
// whether scene requires init hook in plot call (dirty plot call)
205202
dirty: true,
@@ -213,19 +210,20 @@ function sceneUpdate(gd, subplot) {
213210
errorYOptions: [],
214211
textOptions: [],
215212
textSelectedOptions: [],
216-
textUnselectedOptions: []
213+
textUnselectedOptions: [],
214+
// selection batches
215+
selectBatch: [],
216+
unselectBatch: []
217217
};
218218

219+
// regl- component stubs, initialized in dirty plot call
219220
var initOpts = {
220-
selectBatch: null,
221-
unselectBatch: null,
222-
// regl- component stubs, initialized in dirty plot call
223221
fill2d: false,
224222
scatter2d: false,
225223
error2d: false,
226224
line2d: false,
227225
glText: false,
228-
select2d: null
226+
select2d: false
229227
};
230228

231229
if(!subplot._scene) {
@@ -276,17 +274,22 @@ function sceneUpdate(gd, subplot) {
276274
if(scene.errorXOptions[i]) error2d.draw(i);
277275
if(scene.errorYOptions[i]) error2d.draw(i + count);
278276
}
279-
if(scatter2d && scene.markerOptions[i] && (!selectBatch || !selectBatch[i])) {
280-
scatter2d.draw(i);
277+
if(scatter2d && scene.markerOptions[i]) {
278+
if(unselectBatch[i].length) {
279+
var arg = Lib.repeat([], scene.count);
280+
arg[i] = unselectBatch[i];
281+
scatter2d.draw(arg);
282+
} else if(!selectBatch[i].length) {
283+
scatter2d.draw(i);
284+
}
281285
}
282286
if(glText[i] && scene.textOptions[i]) {
283287
glText[i].render();
284288
}
285289
}
286290

287-
if(scatter2d && select2d && selectBatch) {
291+
if(select2d) {
288292
select2d.draw(selectBatch);
289-
scatter2d.draw(unselectBatch);
290293
}
291294

292295
scene.dirty = false;
@@ -325,7 +328,7 @@ function sceneUpdate(gd, subplot) {
325328
};
326329
}
327330

328-
// In case if we have scene from the last calc - reset data
331+
// in case if we have scene from the last calc - reset data
329332
if(!scene.dirty) {
330333
Lib.extendFlat(scene, resetOpts);
331334
}
@@ -363,6 +366,7 @@ function plot(gd, subplot, cdata) {
363366
return;
364367
}
365368

369+
var count = scene.count;
366370
var regl = fullLayout._glcanvas.data()[0].regl;
367371

368372
// that is needed for fills
@@ -383,28 +387,28 @@ function plot(gd, subplot, cdata) {
383387
scene.fill2d = createLine(regl);
384388
}
385389
if(scene.glText === true) {
386-
scene.glText = new Array(scene.count);
387-
for(i = 0; i < scene.count; i++) {
390+
scene.glText = new Array(count);
391+
for(i = 0; i < count; i++) {
388392
scene.glText[i] = new Text(regl);
389393
}
390394
}
391395

392396
// update main marker options
393397
if(scene.glText) {
394-
if(scene.count > scene.glText.length) {
398+
if(count > scene.glText.length) {
395399
// add gl text marker
396-
var textsToAdd = scene.count - scene.glText.length;
400+
var textsToAdd = count - scene.glText.length;
397401
for(i = 0; i < textsToAdd; i++) {
398402
scene.glText.push(new Text(regl));
399403
}
400-
} else if(scene.count < scene.glText.length) {
404+
} else if(count < scene.glText.length) {
401405
// remove gl text marker
402-
var textsToRemove = scene.glText.length - scene.count;
403-
var removedTexts = scene.glText.splice(scene.count, textsToRemove);
406+
var textsToRemove = scene.glText.length - count;
407+
var removedTexts = scene.glText.splice(count, textsToRemove);
404408
removedTexts.forEach(function(text) { text.destroy(); });
405409
}
406410

407-
for(i = 0; i < scene.count; i++) {
411+
for(i = 0; i < count; i++) {
408412
scene.glText[i].update(scene.textOptions[i]);
409413
}
410414
}
@@ -437,7 +441,7 @@ function plot(gd, subplot, cdata) {
437441
}
438442

439443
// fill requires linked traces, so we generate it's positions here
440-
scene.fillOrder = Lib.repeat(null, scene.count);
444+
scene.fillOrder = Lib.repeat(null, count);
441445
if(scene.fill2d) {
442446
scene.fillOptions = scene.fillOptions.map(function(fillOptions, i) {
443447
var cdscatter = cdata[i];
@@ -556,13 +560,11 @@ function plot(gd, subplot, cdata) {
556560
}
557561

558562
// form batch arrays, and check for selected points
559-
scene.selectBatch = null;
560-
scene.unselectBatch = null;
561563
var dragmode = fullLayout.dragmode;
562564
var selectMode = dragmode === 'lasso' || dragmode === 'select';
563565
var clickSelectEnabled = fullLayout.clickmode.indexOf('select') > -1;
564566

565-
for(i = 0; i < cdata.length; i++) {
567+
for(i = 0; i < count; i++) {
566568
var cd0 = cdata[i][0];
567569
var trace = cd0.trace;
568570
var stash = cd0.t;
@@ -574,11 +576,6 @@ function plot(gd, subplot, cdata) {
574576
if(trace.selectedpoints || selectMode || clickSelectEnabled) {
575577
if(!selectMode) selectMode = true;
576578

577-
if(!scene.selectBatch) {
578-
scene.selectBatch = [];
579-
scene.unselectBatch = [];
580-
}
581-
582579
// regenerate scene batch, if traces number changed during selection
583580
if(trace.selectedpoints) {
584581
var selPts = scene.selectBatch[index] = Lib.selIndices2selPoints(trace);
@@ -610,21 +607,24 @@ function plot(gd, subplot, cdata) {
610607
}
611608
}
612609

613-
614610
if(selectMode) {
615-
// create select2d
611+
// create scatter instance by cloning scatter2d
616612
if(!scene.select2d) {
617-
// create scatter instance by cloning scatter2d
618613
scene.select2d = createScatter(fullLayout._glcanvas.data()[1].regl);
619614
}
620615

621-
if(scene.scatter2d && scene.selectBatch && scene.selectBatch.length) {
622-
// update only traces with selection
623-
scene.scatter2d.update(scene.markerUnselectedOptions.map(function(opts, i) {
624-
return scene.selectBatch[i] ? opts : null;
625-
}));
616+
// use unselected styles on 'context' canvas
617+
if(scene.scatter2d) {
618+
var unselOpts = new Array(count);
619+
for(i = 0; i < count; i++) {
620+
unselOpts[i] = scene.selectBatch[i].length || scene.unselectBatch[i].length ?
621+
scene.markerUnselectedOptions[i] :
622+
{};
623+
}
624+
scene.scatter2d.update(unselOpts);
626625
}
627626

627+
// use selected style on 'focus' canvas
628628
if(scene.select2d) {
629629
scene.select2d.update(scene.markerOptions);
630630
scene.select2d.update(scene.markerSelectedOptions);
@@ -639,9 +639,9 @@ function plot(gd, subplot, cdata) {
639639
});
640640
}
641641
} else {
642+
// reset 'context' scatter2d opts to base opts,
643+
// thus unsetting markerUnselectedOptions from selection
642644
if(scene.scatter2d) {
643-
// reset scatter2d opts to base opts,
644-
// thus unsetting markerUnselectedOptions from selection
645645
scene.scatter2d.update(scene.markerOptions);
646646
}
647647
}
@@ -680,7 +680,6 @@ function plot(gd, subplot, cdata) {
680680
}
681681
}
682682

683-
684683
function hoverPoints(pointData, xval, yval, hovermode) {
685684
var cd = pointData.cd;
686685
var stash = cd[0].t;
@@ -758,7 +757,6 @@ function hoverPoints(pointData, xval, yval, hovermode) {
758757
return [pointData];
759758
}
760759

761-
762760
function calcHover(pointData, x, y, trace) {
763761
var xa = pointData.xa;
764762
var ya = pointData.ya;
@@ -861,7 +859,6 @@ function calcHover(pointData, x, y, trace) {
861859
return pointData;
862860
}
863861

864-
865862
function selectPoints(searchInfo, selectionTester) {
866863
var cd = searchInfo.cd;
867864
var selection = [];
@@ -871,23 +868,23 @@ function selectPoints(searchInfo, selectionTester) {
871868
var x = stash.x;
872869
var y = stash.y;
873870
var scene = stash._scene;
871+
var index = stash.index;
874872

875873
if(!scene) return selection;
876874

877875
var hasText = subTypes.hasText(trace);
878876
var hasMarkers = subTypes.hasMarkers(trace);
879877
var hasOnlyLines = !hasMarkers && !hasText;
878+
880879
if(trace.visible !== true || hasOnlyLines) return selection;
881880

881+
var els = [];
882+
var unels = [];
883+
882884
// degenerate polygon does not enable selection
883885
// filter out points by visible scatter ones
884-
var els = null;
885-
var unels = null;
886-
// FIXME: clearing selection does not work here
887-
var i;
888886
if(selectionTester !== false && !selectionTester.degenerate) {
889-
els = [], unels = [];
890-
for(i = 0; i < len; i++) {
887+
for(var i = 0; i < len; i++) {
891888
if(selectionTester.contains([stash.xpx[i], stash.ypx[i]], false, i, searchInfo)) {
892889
els.push(i);
893890
selection.push({
@@ -899,32 +896,27 @@ function selectPoints(searchInfo, selectionTester) {
899896
unels.push(i);
900897
}
901898
}
902-
} else {
903-
unels = arrayRange(len);
904899
}
905900

906-
// make sure selectBatch is created
907-
if(!scene.selectBatch) {
908-
scene.selectBatch = [];
909-
scene.unselectBatch = [];
910-
}
901+
if(hasMarkers) {
902+
var scatter2d = scene.scatter2d;
911903

912-
if(!scene.selectBatch[stash.index]) {
913-
// enter every trace select mode
914-
for(i = 0; i < scene.count; i++) {
915-
scene.selectBatch[i] = [];
916-
scene.unselectBatch[i] = [];
917-
}
918-
// we should turn scatter2d into unselected once we have any points selected
919-
if(hasMarkers) {
920-
scene.scatter2d.update(scene.markerUnselectedOptions);
904+
if(!els.length && !unels.length) {
905+
// reset to base styles when clearing
906+
var baseOpts = new Array(scene.count);
907+
baseOpts[index] = scene.markerOptions[index];
908+
scatter2d.update.apply(scatter2d, baseOpts);
909+
} else if(!scene.selectBatch[index].length && !scene.unselectBatch[index].length) {
910+
// set unselected styles on 'context' canvas (if not done already)
911+
var unselOpts = new Array(scene.count);
912+
unselOpts[index] = scene.markerUnselectedOptions[index];
913+
scatter2d.update.apply(scatter2d, unselOpts);
921914
}
922915
}
923916

924-
scene.selectBatch[stash.index] = els;
925-
scene.unselectBatch[stash.index] = unels;
917+
scene.selectBatch[index] = els;
918+
scene.unselectBatch[index] = unels;
926919

927-
// update text options
928920
if(hasText) {
929921
styleTextSelection(cd);
930922
}
@@ -946,7 +938,7 @@ function styleTextSelection(cd) {
946938
var opts = Lib.extendFlat({}, baseOpts);
947939
var i, j;
948940

949-
if(els && unels) {
941+
if(els.length || unels.length) {
950942
var stc = selOpts.color;
951943
var utc = unselOpts.color;
952944
var base = baseOpts.color;

‎src/traces/scatterpolargl/index.js

Copy file name to clipboardExpand all lines: src/traces/scatterpolargl/index.js
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ function plot(gd, subplot, cdata) {
155155
scene.textOptions.push(opts.text);
156156
scene.textSelectedOptions.push(opts.textSel);
157157
scene.textUnselectedOptions.push(opts.textUnsel);
158+
scene.selectBatch.push([]);
159+
scene.unselectBatch.push([]);
158160

159161
stash.x = x;
160162
stash.y = y;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.