-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add support for encoding TypedArrays as primitive objects for serialization #2911
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
636e644
5030d3a
dfd44d5
ec21714
8de7b5a
5107c97
5cdb828
1ec957a
a7c3814
2b9bda9
669e8be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,8 @@ exports.restyle = main.restyle; | |
exports.relayout = main.relayout; | ||
exports.redraw = main.redraw; | ||
exports.update = main.update; | ||
exports.decode = main.decode; | ||
exports.encode = main.encode; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We may start with underscore (i.e. kind of private) methods here. exports._decode = main.decode;
exports._encode = main.encode; If we want to expose these functionality, then using a more specific name could be considered. exports.decodeArray = main.decode;
exports.encodeArray = main.encode; |
||
exports.react = main.react; | ||
exports.extendTraces = main.extendTraces; | ||
exports.prependTraces = main.prependTraces; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
var d3 = require('d3'); | ||
var isNumeric = require('fast-isnumeric'); | ||
var hasHover = require('has-hover'); | ||
var b64 = require('base64-arraybuffer'); | ||
|
||
var Lib = require('../lib'); | ||
var Events = require('../lib/events'); | ||
|
@@ -2192,6 +2193,181 @@ exports.update = function update(gd, traceUpdate, layoutUpdate, _traces) { | |
}); | ||
}; | ||
|
||
|
||
/** | ||
* Get TypedArray type for a given dtype string | ||
* @param {String} dtype: Data type string | ||
* @returns {TypedArray} | ||
*/ | ||
function getTypedArrayTypeForDtypeString(dtype) { | ||
if(dtype === 'int8' && typeof Int8Array !== 'undefined') { | ||
return Int8Array; | ||
} else if(dtype === 'uint8' && typeof Uint8Array !== 'undefined') { | ||
return Uint8Array; | ||
} else if(dtype === 'uint8_clamped' && typeof Uint8ClampedArray !== 'undefined') { | ||
return Uint8ClampedArray; | ||
} else if(dtype === 'int16' && typeof Int16Array !== 'undefined') { | ||
return Int16Array; | ||
} else if(dtype === 'uint16' && typeof Uint16Array !== 'undefined') { | ||
return Uint16Array; | ||
} else if(dtype === 'int32' && typeof Int32Array !== 'undefined') { | ||
return Int32Array; | ||
} else if(dtype === 'uint32' && typeof Uint32Array !== 'undefined') { | ||
return Uint32Array; | ||
} else if(dtype === 'float32' && typeof Float32Array !== 'undefined') { | ||
return Float32Array; | ||
} else if(dtype === 'float64' && typeof Float64Array !== 'undefined') { | ||
return Float64Array; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You may consider rewrite this: function getArrayType(t) {
return (typeof t !== 'undefined') ? t : undefined;
}
var validInt8Array = getArrayType(Int8Array);
var validUint8Array = getArrayType(Uint8Array);
...
/**
* Get TypedArray type for a given dtype string
* @param {String} dtype: Data type string
* @returns {TypedArray}
*/
function getTypedArrayTypeForDtypeString(dtype) {
switch(dtyle) {
case 'int8':
return validInt8Array;
case 'uint8':
return validUint8Array;
...
}
} |
||
|
||
/** | ||
* Convert a TypedArray encoding object into a TypedArray | ||
* @param {object} v: Object with `dtype` and `value` properties that | ||
* represents a TypedArray. | ||
* | ||
* @returns {TypedArray} | ||
*/ | ||
function decodeTypedArray(v) { | ||
|
||
var coercedV; | ||
var value = v.value; | ||
var TypeArrayType = getTypedArrayTypeForDtypeString(v.dtype); | ||
|
||
if(TypeArrayType) { | ||
if(value instanceof ArrayBuffer) { | ||
// value is an ArrayBuffer | ||
coercedV = new TypeArrayType(value); | ||
} else if(value.constructor === DataView) { | ||
// value has a buffer property, where the buffer is an ArrayBuffer | ||
coercedV = new TypeArrayType(value.buffer); | ||
} else if(Array.isArray(value)) { | ||
// value is a primitive array | ||
coercedV = new TypeArrayType(value); | ||
} else if(typeof value === 'string' || | ||
value instanceof String) { | ||
// value is a base64 encoded string | ||
var buffer = b64.decode(value); | ||
coercedV = new TypeArrayType(buffer); | ||
} | ||
} else { | ||
// Either v.dtype was an invalid array type, or this browser doesn't | ||
// support this typed array type. | ||
} | ||
return coercedV; | ||
} | ||
|
||
/** | ||
* Recursive helper function to perform decoding | ||
*/ | ||
function performDecode(v) { | ||
if(Lib.isTypedArrayEncoding(v)) { | ||
return decodeTypedArray(v); | ||
} else if(Array.isArray(v)) { | ||
return v.map(performDecode); | ||
} else if(Lib.isPlainObject(v)) { | ||
var result = {}; | ||
for(var k in v) { | ||
if(v.hasOwnProperty(k)) { | ||
result[k] = performDecode(v[k]); | ||
} | ||
} | ||
return result; | ||
} else { | ||
return v; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can drop last |
||
} | ||
|
||
/** | ||
* Plotly.decode: | ||
* Attempt to recursively decode an object or array into a form supported | ||
* by Plotly.js. This function is the inverse of Plotly.encode. | ||
* | ||
* @param {object} v: Value to be decoded | ||
* @returns {object}: Decoded value | ||
*/ | ||
exports.decode = function(v) { | ||
return performDecode(v); | ||
}; | ||
|
||
/** | ||
* Get data type string for TypedArray | ||
* @param {TypedArray} v: A TypedArray instance | ||
* @returns {String} | ||
*/ | ||
function getDtypeStringForTypedArray(v) { | ||
if(typeof Int8Array !== 'undefined' && v instanceof Int8Array) { | ||
return 'int8'; | ||
} else if(typeof Uint8Array !== 'undefined' && v instanceof Uint8Array) { | ||
return 'uint8'; | ||
} else if(typeof Uint8ClampedArray !== 'undefined' && v instanceof Uint8ClampedArray) { | ||
return 'uint8_clamped'; | ||
} else if(typeof Int16Array !== 'undefined' && v instanceof Int16Array) { | ||
return 'int16'; | ||
} else if(typeof Uint16Array !== 'undefined' && v instanceof Uint16Array) { | ||
return 'uint16'; | ||
} else if(typeof Int32Array !== 'undefined' && v instanceof Int32Array) { | ||
return 'int32'; | ||
} else if(typeof Uint32Array !== 'undefined' && v instanceof Uint32Array) { | ||
return 'uint32'; | ||
} else if(typeof Float32Array !== 'undefined' && v instanceof Float32Array) { | ||
return 'float32'; | ||
} else if(typeof Float64Array !== 'undefined' && v instanceof Float64Array) { | ||
return 'float64'; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be of interest to support There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Big integers could be useful for storing time in milliseconds. |
||
} | ||
|
||
|
||
/** | ||
* Convert a TypedArray instance into a JSON-serializable object that | ||
* represents it. | ||
* | ||
* @param {TypedArray} v: A TypedArray instance | ||
* | ||
* @returns {object} Object with `dtype` and `value` properties that | ||
* represents a TypedArray. | ||
*/ | ||
function encodeTypedArray(v) { | ||
var dtype = getDtypeStringForTypedArray(v); | ||
var buffer = b64.encode(v.buffer); | ||
return {'value': buffer, 'dtype': dtype}; | ||
} | ||
|
||
|
||
/** | ||
* Recursive helper function to perform encoding | ||
* @param v | ||
*/ | ||
function performEncode(v) { | ||
if(Lib.isTypedArray(v)) { | ||
return encodeTypedArray(v); | ||
} else if(Array.isArray(v)) { | ||
return v.map(performEncode); | ||
} else if(Lib.isPlainObject(v)) { | ||
var result = {}; | ||
for(var k in v) { | ||
if(v.hasOwnProperty(k)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we may list the keys using Object.getOwnPropertyNames and loop through them. |
||
result[k] = performEncode(v[k]); | ||
} | ||
} | ||
return result; | ||
} else { | ||
return v; | ||
} | ||
} | ||
|
||
/** | ||
* Plotly.encode | ||
* Recursively encode a Plotly.js object or array into a form that is JSON | ||
* serializable | ||
* | ||
* @param {object} v: Value to be encode | ||
* @returns {object}: Encoded value | ||
*/ | ||
exports.encode = function(v) { | ||
return performEncode(v); | ||
}; | ||
|
||
/** | ||
* Plotly.react: | ||
* A plot/update method that takes the full plot state (same API as plot/newPlot) | ||
|
Uh oh!
There was an error while loading. Please reload this page.