Skip to content

Commit

Permalink
Merge pull request #2388 from plotly/typed-arrays-support
Browse files Browse the repository at this point in the history
Typed arrays support
  • Loading branch information
etpinard authored Feb 28, 2018
2 parents 22cfd39 + d4cb0c4 commit f8e7ee4
Show file tree
Hide file tree
Showing 102 changed files with 1,127 additions and 476 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"Int16Array": true,
"Int32Array": true,
"ArrayBuffer": true,
"DataView": true,
"SVGElement": false
},
"rules": {
Expand Down
14 changes: 5 additions & 9 deletions src/components/colorscale/has_colorscale.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,20 @@
* LICENSE file in the root directory of this source tree.
*/


'use strict';

var isNumeric = require('fast-isnumeric');

var Lib = require('../../lib');

var isValidScale = require('./is_valid_scale');


module.exports = function hasColorscale(trace, containerStr) {
var container = containerStr ?
Lib.nestedProperty(trace, containerStr).get() || {} :
trace,
color = container.color,
isArrayWithOneNumber = false;
Lib.nestedProperty(trace, containerStr).get() || {} :
trace;
var color = container.color;

if(Array.isArray(color)) {
var isArrayWithOneNumber = false;
if(Lib.isArrayOrTypedArray(color)) {
for(var i = 0; i < color.length; i++) {
if(isNumeric(color[i])) {
isArrayWithOneNumber = true;
Expand Down
6 changes: 3 additions & 3 deletions src/components/drawing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,10 @@ function singlePointStyle(d, sel, trace, markerScale, lineScale, marker, markerL

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

if(Array.isArray(marker.color)) {
if(Lib.isArrayOrTypedArray(marker.color)) {
fillColor = Color.defaultLine;
perPointGradient = true;
}
Expand Down Expand Up @@ -542,7 +542,7 @@ drawing.tryColorscale = function(marker, prefix) {
scl = cont.colorscale,
colorArray = cont.color;

if(scl && Array.isArray(colorArray)) {
if(scl && Lib.isArrayOrTypedArray(colorArray)) {
return Colorscale.makeColorScaleFunc(
Colorscale.extractScale(scl, cont.cmin, cont.cmax)
);
Expand Down
13 changes: 8 additions & 5 deletions src/lib/coerce.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@ var nestedProperty = require('./nested_property');
var counterRegex = require('./regex').counter;
var DESELECTDIM = require('../constants/interactions').DESELECTDIM;
var wrap180 = require('./angles').wrap180;
var isArrayOrTypedArray = require('./is_array').isArrayOrTypedArray;

exports.valObjectMeta = {
data_array: {
// You can use *dflt=[] to force said array to exist though.
description: [
'An {array} of data.',
'The value MUST be an {array}, or we ignore it.'
'The value MUST be an {array}, or we ignore it.',
'Note that typed arrays (e.g. Float32Array) are supported.'
].join(' '),
requiredOpts: [],
otherOpts: ['dflt'],
coerceFunction: function(v, propOut, dflt) {
if(Array.isArray(v)) propOut.set(v);
// TODO maybe `v: {type: 'float32', vals: [/* ... */]}` also
if(isArrayOrTypedArray(v)) propOut.set(v);
else if(dflt !== undefined) propOut.set(dflt);
}
},
Expand Down Expand Up @@ -367,7 +370,7 @@ exports.coerce = function(containerIn, containerOut, attributes, attribute, dflt
* individual form (eg. some array vals can be numbers, even if the
* single values must be color strings)
*/
if(opts.arrayOk && Array.isArray(v)) {
if(opts.arrayOk && isArrayOrTypedArray(v)) {
propOut.set(v);
return v;
}
Expand Down Expand Up @@ -464,7 +467,7 @@ exports.coerceSelectionMarkerOpacity = function(traceOut, coerce) {
//
// Only give [un]selected.marker.opacity a default value if you don't
// set any other [un]selected attributes.
if(!Array.isArray(mo) && !traceOut.selected && !traceOut.unselected) {
if(!isArrayOrTypedArray(mo) && !traceOut.selected && !traceOut.unselected) {
smoDflt = mo;
usmoDflt = DESELECTDIM * mo;
}
Expand All @@ -476,7 +479,7 @@ exports.coerceSelectionMarkerOpacity = function(traceOut, coerce) {
exports.validate = function(value, opts) {
var valObjectDef = exports.valObjectMeta[opts.valType];

if(opts.arrayOk && Array.isArray(value)) return true;
if(opts.arrayOk && isArrayOrTypedArray(value)) return true;

if(valObjectDef.validateFunction) {
return valObjectDef.validateFunction(value, opts);
Expand Down
2 changes: 2 additions & 0 deletions src/lib/extend.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ function _extend(inputs, isDeep, keepAllKeys, noArrayCopies) {

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

// TODO does this do the right thing for typed arrays?

if(length === 2 && isArray(target) && isArray(inputs[1]) && target.length === 0) {

allPrimitives = primitivesLoopSplice(inputs[1], target);
Expand Down
13 changes: 8 additions & 5 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ lib.nestedProperty = require('./nested_property');
lib.keyedContainer = require('./keyed_container');
lib.relativeAttr = require('./relative_attr');
lib.isPlainObject = require('./is_plain_object');
lib.isArray = require('./is_array');
lib.mod = require('./mod');
lib.toLogRange = require('./to_log_range');
lib.relinkPrivateKeys = require('./relink_private');
lib.ensureArray = require('./ensure_array');

var isArrayModule = require('./is_array');
lib.isTypedArray = isArrayModule.isTypedArray;
lib.isArrayOrTypedArray = isArrayModule.isArrayOrTypedArray;

var coerceModule = require('./coerce');
lib.valObjectMeta = coerceModule.valObjectMeta;
lib.coerce = coerceModule.coerce;
Expand Down Expand Up @@ -389,7 +392,7 @@ lib.noneOrAll = function(containerIn, containerOut, attrList) {
* @param {string} cdAttr : calcdata key
*/
lib.mergeArray = function(traceAttr, cd, cdAttr) {
if(Array.isArray(traceAttr)) {
if(lib.isArrayOrTypedArray(traceAttr)) {
var imax = Math.min(traceAttr.length, cd.length);
for(var i = 0; i < imax; i++) cd[i][cdAttr] = traceAttr[i];
}
Expand All @@ -408,7 +411,7 @@ lib.mergeArray = function(traceAttr, cd, cdAttr) {
lib.fillArray = function(traceAttr, cd, cdAttr, fn) {
fn = fn || lib.identity;

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

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

if(Array.isArray(val)) {
if(Array.isArray(ptNumber) && Array.isArray(val[ptNumber[0]])) {
if(lib.isArrayOrTypedArray(val)) {
if(Array.isArray(ptNumber) && lib.isArrayOrTypedArray(val[ptNumber[0]])) {
return fn(val[ptNumber[0]][ptNumber[1]]);
} else {
return fn(val[ptNumber]);
Expand Down
17 changes: 11 additions & 6 deletions src/lib/is_array.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@

'use strict';

/**
* Return true for arrays, whether they're untyped or not.
*/
// IE9 fallbacks

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

module.exports = function isArray(a) {
return Array.isArray(a) || ab.isView(a);
var dv = (typeof DataView === 'undefined') ?
function() {} :
DataView;

exports.isTypedArray = function(a) {
return ab.isView(a) && !(a instanceof dv);
};

exports.isArrayOrTypedArray = function(a) {
return Array.isArray(a) || exports.isTypedArray(a);
};
14 changes: 7 additions & 7 deletions src/lib/nested_property.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'use strict';

var isNumeric = require('fast-isnumeric');
var isArray = require('./is_array');
var isArrayOrTypedArray = require('./is_array').isArrayOrTypedArray;
var isPlainObject = require('./is_plain_object');
var containerArrayMatch = require('../plot_api/container_array_match');

Expand Down Expand Up @@ -96,7 +96,7 @@ function npGet(cont, parts) {
}
return allSame ? out[0] : out;
}
if(typeof curPart === 'number' && !isArray(curCont)) {
if(typeof curPart === 'number' && !isArrayOrTypedArray(curCont)) {
return undefined;
}
curCont = curCont[curPart];
Expand Down Expand Up @@ -144,7 +144,7 @@ function isDeletable(val, propStr) {
) {
return false;
}
if(!isArray(val)) return true;
if(!isArrayOrTypedArray(val)) return true;

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

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

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

Expand Down Expand Up @@ -211,7 +211,7 @@ function joinPropStr(propStr, newPart) {

// handle special -1 array index
function setArrayAll(containerArray, innerParts, val, propStr) {
var arrayVal = isArray(val),
var arrayVal = isArrayOrTypedArray(val),
allSet = true,
thisVal = val,
thisPropStr = propStr.replace('-1', 0),
Expand Down Expand Up @@ -261,7 +261,7 @@ function pruneContainers(containerLevels) {
propPart = containerLevels[i][1];

remainingKeys = false;
if(isArray(curCont)) {
if(isArrayOrTypedArray(curCont)) {
for(j = curCont.length - 1; j >= 0; j--) {
if(isDeletable(curCont[j], joinPropStr(propPart, j))) {
if(remainingKeys) curCont[j] = undefined;
Expand All @@ -287,7 +287,7 @@ function pruneContainers(containerLevels) {
function emptyObj(obj) {
if(obj === undefined || obj === null) return true;
if(typeof obj !== 'object') return false; // any plain value
if(isArray(obj)) return !obj.length; // []
if(isArrayOrTypedArray(obj)) return !obj.length; // []
return !Object.keys(obj).length; // {}
}

Expand Down
4 changes: 2 additions & 2 deletions src/lib/relink_private.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

'use strict';

var isArray = require('./is_array');
var isArrayOrTypedArray = require('./is_array').isArrayOrTypedArray;
var isPlainObject = require('./is_plain_object');

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

toContainer[k] = fromVal;
}
else if(isArray(fromVal) && isArray(toVal) && isPlainObject(fromVal[0])) {
else if(isArrayOrTypedArray(fromVal) && isArrayOrTypedArray(toVal) && isPlainObject(fromVal[0])) {

// filter out data_array items that can contain user objects
// most of the time the toVal === fromVal check will catch these early
Expand Down
4 changes: 2 additions & 2 deletions src/lib/stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'use strict';

var isNumeric = require('fast-isnumeric');

var isArrayOrTypedArray = require('./is_array').isArrayOrTypedArray;

/**
* aggNums() returns the result of an aggregate function applied to an array of
Expand All @@ -30,7 +30,7 @@ exports.aggNums = function(f, v, a, len) {
b;
if(!len || len > a.length) len = a.length;
if(!isNumeric(v)) v = false;
if(Array.isArray(a[0])) {
if(isArrayOrTypedArray(a[0])) {
b = new Array(len);
for(i = 0; i < len; i++) b[i] = exports.aggNums(f, v, a[i]);
a = b;
Expand Down
Loading

0 comments on commit f8e7ee4

Please sign in to comment.