Skip to content

Commit 315e632

Browse files
committed
add Lib.tagSelected made to make selectedpoints work w/ transforms
- tagSelected make heavy use of the transforms _indexToPoints map object to determine how input index (called pointIndex) are mapped to calcdata index (called pointNumber). - use pointIndex (not pointNumber) while filling up selectedpoints array to match input indices. - Use tagSelected in scatter, box, and histogram calcSelection methods taking care of all trace types that support selections.
1 parent 949b311 commit 315e632

File tree

6 files changed

+106
-35
lines changed

6 files changed

+106
-35
lines changed

src/lib/index.js

+51
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,57 @@ lib.extractOption = function(calcPt, trace, calcKey, traceKey) {
465465
if(!Array.isArray(traceVal)) return traceVal;
466466
};
467467

468+
/** Tag selected calcdata items
469+
*
470+
* N.B. note that point 'index' corresponds to input data array index
471+
* whereas 'number' is its post-transform version.
472+
*
473+
* @param {array} calcTrace
474+
* @param {object} trace
475+
* - selectedpoints {array}
476+
* - _indexToPoints {object}
477+
* @param {ptNumber2cdIndex} ptNumber2cdIndex (optional)
478+
* optional map object for trace types that do not have 1-to-1 point number to
479+
* calcdata item index correspondence (e.g. histogram)
480+
*/
481+
lib.tagSelected = function(calcTrace, trace, ptNumber2cdIndex) {
482+
var selectedpoints = trace.selectedpoints;
483+
var indexToPoints = trace._indexToPoints;
484+
var ptIndex2ptNumber;
485+
486+
// make pt index-to-number map object, which takes care of transformed traces
487+
if(indexToPoints) {
488+
ptIndex2ptNumber = {};
489+
for(var k in indexToPoints) {
490+
var pts = indexToPoints[k];
491+
for(var j = 0; j < pts.length; j++) {
492+
ptIndex2ptNumber[pts[j]] = k;
493+
}
494+
}
495+
}
496+
497+
function isPtIndexValid(v) {
498+
return lib.validate(v, {valType: 'integer', min: 0});
499+
}
500+
501+
function isCdIndexValid(v) {
502+
return v !== undefined && v < calcTrace.length;
503+
}
504+
505+
for(var i = 0; i < selectedpoints.length; i++) {
506+
var ptIndex = selectedpoints[i];
507+
508+
if(isPtIndexValid(ptIndex)) {
509+
var ptNumber = ptIndex2ptNumber ? ptIndex2ptNumber[ptIndex] : ptIndex;
510+
var cdIndex = ptNumber2cdIndex ? ptNumber2cdIndex[ptNumber] : ptNumber;
511+
512+
if(isCdIndexValid(cdIndex)) {
513+
calcTrace[cdIndex].selected = 1;
514+
}
515+
}
516+
}
517+
};
518+
468519
/** Returns target as set by 'target' transform attribute
469520
*
470521
* @param {object} trace : full trace object

src/plots/cartesian/select.js

+12-13
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,7 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
240240
traceSelection = searchInfo.selectPoints(searchInfo, testPoly);
241241
traceSelections.push(traceSelection);
242242

243-
var thisSelection = fillSelectionItem(
244-
traceSelection, searchInfo
245-
);
243+
var thisSelection = fillSelectionItem(traceSelection, searchInfo);
246244
if(selection.length) {
247245
for(var j = 0; j < thisSelection.length; j++) {
248246
selection.push(thisSelection[j]);
@@ -294,30 +292,31 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
294292
};
295293

296294
function updateSelectedState(gd, searchTraces, eventData) {
297-
var i, searchInfo;
295+
var i, searchInfo, trace;
298296

299297
if(eventData) {
300298
var pts = eventData.points || [];
301299

302300
for(i = 0; i < searchTraces.length; i++) {
303-
searchInfo = searchTraces[i];
304-
searchInfo.cd[0].trace.selectedpoints = [];
305-
searchInfo.cd[0].trace._input.selectedpoints = [];
301+
trace = searchTraces[i].cd[0].trace;
302+
trace.selectedpoints = [];
303+
trace._input.selectedpoints = [];
306304
}
307305

308306
for(i = 0; i < pts.length; i++) {
309307
var pt = pts[i];
310-
var ptNumber = pt.pointNumber;
308+
var data = pt.data;
309+
var fullData = pt.fullData;
311310

312-
pt.data.selectedpoints.push(ptNumber);
313-
pt.fullData.selectedpoints.push(ptNumber);
311+
data.selectedpoints.push(pt.pointIndex);
312+
fullData.selectedpoints.push(pt.pointIndex);
314313
}
315314
}
316315
else {
317316
for(i = 0; i < searchTraces.length; i++) {
318-
searchInfo = searchTraces[i];
319-
delete searchInfo.cd[0].trace.selectedpoints;
320-
delete searchInfo.cd[0].trace._input.selectedpoints;
317+
trace = searchTraces[i].cd[0].trace;
318+
delete trace.selectedpoints;
319+
delete trace._input.selectedpoints;
321320
}
322321
}
323322

src/plots/plots.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -2241,7 +2241,21 @@ plots.doCalcdata = function(gd, traces) {
22412241

22422242
if(trace.visible === true) {
22432243
_module = trace._module;
2244-
if(_module && _module.calc) cd = _module.calc(gd, trace);
2244+
2245+
// keep ref of index-to-points map object of the *last* enabled transform,
2246+
// this index-to-points map object is required to determine the calcdata indices
2247+
// that correspond to input indices (e.g. from 'selectedpoints')
2248+
var transforms = trace.transforms || [];
2249+
for(j = transforms.length - 1; j >= 0; j--) {
2250+
if(transforms[j].enabled) {
2251+
trace._indexToPoints = transforms[j]._indexToPoints;
2252+
break;
2253+
}
2254+
}
2255+
2256+
if(_module && _module.calc) {
2257+
cd = _module.calc(gd, trace);
2258+
}
22452259
}
22462260

22472261
// Make sure there is a first point.

src/traces/box/calc.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ module.exports = function calc(gd, trace) {
114114
}
115115
}
116116

117+
calcSelection(cd, trace);
117118
Axes.expand(valAxis, val, {padded: true});
118119

119120
if(cd.length > 0) {
@@ -193,13 +194,13 @@ function arraysToCalcdata(pt, trace, i) {
193194
pt[trace2calc[k]] = trace[k][i];
194195
}
195196
}
197+
}
196198

197-
var selectedpoints = trace.selectedpoints;
198-
199-
// TODO this is slow
200-
if(Array.isArray(selectedpoints)) {
201-
if(selectedpoints.indexOf(pt.i) !== -1) {
202-
pt.selected = 1;
199+
function calcSelection(cd, trace) {
200+
if(Array.isArray(trace.selectedpoints)) {
201+
for(var i = 0; i < cd.length; i++) {
202+
var pts = cd[i].pts || [];
203+
Lib.tagSelected(pts, trace);
203204
}
204205
}
205206
}

src/traces/histogram/calc.js

+16-2
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@ var Lib = require('../../lib');
1515
var Axes = require('../../plots/cartesian/axes');
1616

1717
var arraysToCalcdata = require('../bar/arrays_to_calcdata');
18-
var calcSelection = require('../scatter/calc_selection');
1918
var binFunctions = require('./bin_functions');
2019
var normFunctions = require('./norm_functions');
2120
var doAvg = require('./average');
2221
var cleanBins = require('./clean_bins');
2322
var oneMonth = require('../../constants/numerical').ONEAVGMONTH;
2423
var getBinSpanLabelRound = require('./bin_label_vals');
2524

26-
2725
module.exports = function calc(gd, trace) {
2826
// ignore as much processing as possible (and including in autorange) if bar is not visible
2927
if(trace.visible !== true) return;
@@ -512,3 +510,19 @@ function cdf(size, direction, currentBin) {
512510
}
513511
}
514512
}
513+
514+
function calcSelection(cd, trace) {
515+
if(Array.isArray(trace.selectedpoints)) {
516+
var ptNumber2cdIndex = {};
517+
518+
// make histogram-specific pt-number-to-cd-index map object
519+
for(var i = 0; i < cd.length; i++) {
520+
var pts = cd[i].pts || [];
521+
for(var j = 0; j < pts.length; j++) {
522+
ptNumber2cdIndex[pts[j]] = i;
523+
}
524+
}
525+
526+
Lib.tagSelected(cd, trace, ptNumber2cdIndex);
527+
}
528+
}

src/traces/scatter/calc_selection.js

+5-13
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,12 @@
88

99
'use strict';
1010

11-
var isNumeric = require('fast-isnumeric');
11+
var Lib = require('../../lib');
1212

13-
module.exports = function calcSelection(cd, trace) {
14-
var selectedpoints = trace.selectedpoints;
15-
16-
// TODO ids vs points??
13+
// TODO ids vs points??
1714

18-
if(Array.isArray(selectedpoints)) {
19-
for(var i = 0; i < selectedpoints.length; i++) {
20-
var ptNumber = selectedpoints[i];
21-
22-
if(isNumeric(ptNumber)) {
23-
cd[+ptNumber].selected = 1;
24-
}
25-
}
15+
module.exports = function calcSelection(cd, trace) {
16+
if(Array.isArray(trace.selectedpoints)) {
17+
Lib.tagSelected(cd, trace);
2618
}
2719
};

0 commit comments

Comments
 (0)