Skip to content

Commit f8e7ee4

Browse files
authored
Merge pull request #2388 from plotly/typed-arrays-support
Typed arrays support
2 parents 22cfd39 + d4cb0c4 commit f8e7ee4

File tree

102 files changed

+1127
-476
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+1127
-476
lines changed

.eslintrc

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"Int16Array": true,
1818
"Int32Array": true,
1919
"ArrayBuffer": true,
20+
"DataView": true,
2021
"SVGElement": false
2122
},
2223
"rules": {

src/components/colorscale/has_colorscale.js

+5-9
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,20 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
109
'use strict';
1110

1211
var isNumeric = require('fast-isnumeric');
13-
1412
var Lib = require('../../lib');
15-
1613
var isValidScale = require('./is_valid_scale');
1714

18-
1915
module.exports = function hasColorscale(trace, containerStr) {
2016
var container = containerStr ?
21-
Lib.nestedProperty(trace, containerStr).get() || {} :
22-
trace,
23-
color = container.color,
24-
isArrayWithOneNumber = false;
17+
Lib.nestedProperty(trace, containerStr).get() || {} :
18+
trace;
19+
var color = container.color;
2520

26-
if(Array.isArray(color)) {
21+
var isArrayWithOneNumber = false;
22+
if(Lib.isArrayOrTypedArray(color)) {
2723
for(var i = 0; i < color.length; i++) {
2824
if(isNumeric(color[i])) {
2925
isArrayWithOneNumber = true;

src/components/drawing/index.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,10 @@ function singlePointStyle(d, sel, trace, markerScale, lineScale, marker, markerL
316316

317317
if('mlc' in d) lineColor = d.mlcc = lineScale(d.mlc);
318318
// weird case: array wasn't long enough to apply to every point
319-
else if(Array.isArray(markerLine.color)) lineColor = Color.defaultLine;
319+
else if(Lib.isArrayOrTypedArray(markerLine.color)) lineColor = Color.defaultLine;
320320
else lineColor = markerLine.color;
321321

322-
if(Array.isArray(marker.color)) {
322+
if(Lib.isArrayOrTypedArray(marker.color)) {
323323
fillColor = Color.defaultLine;
324324
perPointGradient = true;
325325
}
@@ -542,7 +542,7 @@ drawing.tryColorscale = function(marker, prefix) {
542542
scl = cont.colorscale,
543543
colorArray = cont.color;
544544

545-
if(scl && Array.isArray(colorArray)) {
545+
if(scl && Lib.isArrayOrTypedArray(colorArray)) {
546546
return Colorscale.makeColorScaleFunc(
547547
Colorscale.extractScale(scl, cont.cmin, cont.cmax)
548548
);

src/lib/coerce.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,21 @@ var nestedProperty = require('./nested_property');
1919
var counterRegex = require('./regex').counter;
2020
var DESELECTDIM = require('../constants/interactions').DESELECTDIM;
2121
var wrap180 = require('./angles').wrap180;
22+
var isArrayOrTypedArray = require('./is_array').isArrayOrTypedArray;
2223

2324
exports.valObjectMeta = {
2425
data_array: {
2526
// You can use *dflt=[] to force said array to exist though.
2627
description: [
2728
'An {array} of data.',
28-
'The value MUST be an {array}, or we ignore it.'
29+
'The value MUST be an {array}, or we ignore it.',
30+
'Note that typed arrays (e.g. Float32Array) are supported.'
2931
].join(' '),
3032
requiredOpts: [],
3133
otherOpts: ['dflt'],
3234
coerceFunction: function(v, propOut, dflt) {
33-
if(Array.isArray(v)) propOut.set(v);
35+
// TODO maybe `v: {type: 'float32', vals: [/* ... */]}` also
36+
if(isArrayOrTypedArray(v)) propOut.set(v);
3437
else if(dflt !== undefined) propOut.set(dflt);
3538
}
3639
},
@@ -367,7 +370,7 @@ exports.coerce = function(containerIn, containerOut, attributes, attribute, dflt
367370
* individual form (eg. some array vals can be numbers, even if the
368371
* single values must be color strings)
369372
*/
370-
if(opts.arrayOk && Array.isArray(v)) {
373+
if(opts.arrayOk && isArrayOrTypedArray(v)) {
371374
propOut.set(v);
372375
return v;
373376
}
@@ -464,7 +467,7 @@ exports.coerceSelectionMarkerOpacity = function(traceOut, coerce) {
464467
//
465468
// Only give [un]selected.marker.opacity a default value if you don't
466469
// set any other [un]selected attributes.
467-
if(!Array.isArray(mo) && !traceOut.selected && !traceOut.unselected) {
470+
if(!isArrayOrTypedArray(mo) && !traceOut.selected && !traceOut.unselected) {
468471
smoDflt = mo;
469472
usmoDflt = DESELECTDIM * mo;
470473
}
@@ -476,7 +479,7 @@ exports.coerceSelectionMarkerOpacity = function(traceOut, coerce) {
476479
exports.validate = function(value, opts) {
477480
var valObjectDef = exports.valObjectMeta[opts.valType];
478481

479-
if(opts.arrayOk && Array.isArray(value)) return true;
482+
if(opts.arrayOk && isArrayOrTypedArray(value)) return true;
480483

481484
if(valObjectDef.validateFunction) {
482485
return valObjectDef.validateFunction(value, opts);

src/lib/extend.js

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ function _extend(inputs, isDeep, keepAllKeys, noArrayCopies) {
6565

6666
var input, key, src, copy, copyIsArray, clone, allPrimitives;
6767

68+
// TODO does this do the right thing for typed arrays?
69+
6870
if(length === 2 && isArray(target) && isArray(inputs[1]) && target.length === 0) {
6971

7072
allPrimitives = primitivesLoopSplice(inputs[1], target);

src/lib/index.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,15 @@ lib.nestedProperty = require('./nested_property');
2222
lib.keyedContainer = require('./keyed_container');
2323
lib.relativeAttr = require('./relative_attr');
2424
lib.isPlainObject = require('./is_plain_object');
25-
lib.isArray = require('./is_array');
2625
lib.mod = require('./mod');
2726
lib.toLogRange = require('./to_log_range');
2827
lib.relinkPrivateKeys = require('./relink_private');
2928
lib.ensureArray = require('./ensure_array');
3029

30+
var isArrayModule = require('./is_array');
31+
lib.isTypedArray = isArrayModule.isTypedArray;
32+
lib.isArrayOrTypedArray = isArrayModule.isArrayOrTypedArray;
33+
3134
var coerceModule = require('./coerce');
3235
lib.valObjectMeta = coerceModule.valObjectMeta;
3336
lib.coerce = coerceModule.coerce;
@@ -389,7 +392,7 @@ lib.noneOrAll = function(containerIn, containerOut, attrList) {
389392
* @param {string} cdAttr : calcdata key
390393
*/
391394
lib.mergeArray = function(traceAttr, cd, cdAttr) {
392-
if(Array.isArray(traceAttr)) {
395+
if(lib.isArrayOrTypedArray(traceAttr)) {
393396
var imax = Math.min(traceAttr.length, cd.length);
394397
for(var i = 0; i < imax; i++) cd[i][cdAttr] = traceAttr[i];
395398
}
@@ -408,7 +411,7 @@ lib.mergeArray = function(traceAttr, cd, cdAttr) {
408411
lib.fillArray = function(traceAttr, cd, cdAttr, fn) {
409412
fn = fn || lib.identity;
410413

411-
if(Array.isArray(traceAttr)) {
414+
if(lib.isArrayOrTypedArray(traceAttr)) {
412415
for(var i = 0; i < cd.length; i++) {
413416
cd[i][cdAttr] = fn(traceAttr[i]);
414417
}
@@ -429,8 +432,8 @@ lib.castOption = function(trace, ptNumber, astr, fn) {
429432

430433
var val = lib.nestedProperty(trace, astr).get();
431434

432-
if(Array.isArray(val)) {
433-
if(Array.isArray(ptNumber) && Array.isArray(val[ptNumber[0]])) {
435+
if(lib.isArrayOrTypedArray(val)) {
436+
if(Array.isArray(ptNumber) && lib.isArrayOrTypedArray(val[ptNumber[0]])) {
434437
return fn(val[ptNumber[0]][ptNumber[1]]);
435438
} else {
436439
return fn(val[ptNumber]);

src/lib/is_array.js

+11-6
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,20 @@
88

99
'use strict';
1010

11-
/**
12-
* Return true for arrays, whether they're untyped or not.
13-
*/
11+
// IE9 fallbacks
1412

15-
// IE9 fallback
1613
var ab = (typeof ArrayBuffer === 'undefined' || !ArrayBuffer.isView) ?
1714
{isView: function() { return false; }} :
1815
ArrayBuffer;
1916

20-
module.exports = function isArray(a) {
21-
return Array.isArray(a) || ab.isView(a);
17+
var dv = (typeof DataView === 'undefined') ?
18+
function() {} :
19+
DataView;
20+
21+
exports.isTypedArray = function(a) {
22+
return ab.isView(a) && !(a instanceof dv);
23+
};
24+
25+
exports.isArrayOrTypedArray = function(a) {
26+
return Array.isArray(a) || exports.isTypedArray(a);
2227
};

src/lib/nested_property.js

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

1212
var isNumeric = require('fast-isnumeric');
13-
var isArray = require('./is_array');
13+
var isArrayOrTypedArray = require('./is_array').isArrayOrTypedArray;
1414
var isPlainObject = require('./is_plain_object');
1515
var containerArrayMatch = require('../plot_api/container_array_match');
1616

@@ -96,7 +96,7 @@ function npGet(cont, parts) {
9696
}
9797
return allSame ? out[0] : out;
9898
}
99-
if(typeof curPart === 'number' && !isArray(curCont)) {
99+
if(typeof curPart === 'number' && !isArrayOrTypedArray(curCont)) {
100100
return undefined;
101101
}
102102
curCont = curCont[curPart];
@@ -144,7 +144,7 @@ function isDeletable(val, propStr) {
144144
) {
145145
return false;
146146
}
147-
if(!isArray(val)) return true;
147+
if(!isArrayOrTypedArray(val)) return true;
148148

149149
if(propStr.match(INFO_PATTERNS)) return true;
150150

@@ -167,7 +167,7 @@ function npSet(cont, parts, propStr) {
167167
for(i = 0; i < parts.length - 1; i++) {
168168
curPart = parts[i];
169169

170-
if(typeof curPart === 'number' && !isArray(curCont)) {
170+
if(typeof curPart === 'number' && !isArrayOrTypedArray(curCont)) {
171171
throw 'array index but container is not an array';
172172
}
173173

@@ -211,7 +211,7 @@ function joinPropStr(propStr, newPart) {
211211

212212
// handle special -1 array index
213213
function setArrayAll(containerArray, innerParts, val, propStr) {
214-
var arrayVal = isArray(val),
214+
var arrayVal = isArrayOrTypedArray(val),
215215
allSet = true,
216216
thisVal = val,
217217
thisPropStr = propStr.replace('-1', 0),
@@ -261,7 +261,7 @@ function pruneContainers(containerLevels) {
261261
propPart = containerLevels[i][1];
262262

263263
remainingKeys = false;
264-
if(isArray(curCont)) {
264+
if(isArrayOrTypedArray(curCont)) {
265265
for(j = curCont.length - 1; j >= 0; j--) {
266266
if(isDeletable(curCont[j], joinPropStr(propPart, j))) {
267267
if(remainingKeys) curCont[j] = undefined;
@@ -287,7 +287,7 @@ function pruneContainers(containerLevels) {
287287
function emptyObj(obj) {
288288
if(obj === undefined || obj === null) return true;
289289
if(typeof obj !== 'object') return false; // any plain value
290-
if(isArray(obj)) return !obj.length; // []
290+
if(isArrayOrTypedArray(obj)) return !obj.length; // []
291291
return !Object.keys(obj).length; // {}
292292
}
293293

src/lib/relink_private.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
'use strict';
1111

12-
var isArray = require('./is_array');
12+
var isArrayOrTypedArray = require('./is_array').isArrayOrTypedArray;
1313
var isPlainObject = require('./is_plain_object');
1414

1515
/**
@@ -35,7 +35,7 @@ module.exports = function relinkPrivateKeys(toContainer, fromContainer) {
3535

3636
toContainer[k] = fromVal;
3737
}
38-
else if(isArray(fromVal) && isArray(toVal) && isPlainObject(fromVal[0])) {
38+
else if(isArrayOrTypedArray(fromVal) && isArrayOrTypedArray(toVal) && isPlainObject(fromVal[0])) {
3939

4040
// filter out data_array items that can contain user objects
4141
// most of the time the toVal === fromVal check will catch these early

src/lib/stats.js

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

1212
var isNumeric = require('fast-isnumeric');
13-
13+
var isArrayOrTypedArray = require('./is_array').isArrayOrTypedArray;
1414

1515
/**
1616
* aggNums() returns the result of an aggregate function applied to an array of
@@ -30,7 +30,7 @@ exports.aggNums = function(f, v, a, len) {
3030
b;
3131
if(!len || len > a.length) len = a.length;
3232
if(!isNumeric(v)) v = false;
33-
if(Array.isArray(a[0])) {
33+
if(isArrayOrTypedArray(a[0])) {
3434
b = new Array(len);
3535
for(i = 0; i < len; i++) b[i] = exports.aggNums(f, v, a[i]);
3636
a = b;

0 commit comments

Comments
 (0)