Commit 3e5b5bfb authored by jgould's avatar jgould

use papa parse

parent cb788dc8
......@@ -66,7 +66,7 @@ module.exports = function (grunt) {
'js/hopscotch.min.js', 'js/typed.min.js',
'js/jquery.event.drag-2.2.js',
'js/clipboard.min.js', 'js/slick.min.js',
'js/js.cookie.js', 'js/d3.layout.cloud.js']
'js/js.cookie.js', 'js/d3.layout.cloud.js', 'js/papaparse.min.js']
},
morpheus: {
nonull: true,
......
This diff is collapsed.
This diff is collapsed.
morpheus.ContentRangeNetworkInputStream = function(url, options) {
var _this = this;
this.options = options || {};
this.url = url;
this.bytePosition = 0;
this.chunkSize = options.chunkSize || 1024 * 1024 * 10; // 50 MB
this.bytesRead = 0;
this.fileSize = -1;
this.read();
};
morpheus.ContentRangeNetworkInputStream.prototype = {
read : function() {
var _this = this;
var oReq = new XMLHttpRequest();
oReq.open('GET', this.url, true);
oReq.responseType = 'arraybuffer';
oReq.onload = function(oEvent) {
var arrayBuffer = oReq.response;
var byteArray = new Uint8Array(arrayBuffer);
var contentRange = oReq.getResponseHeader('Content-Range');
var index = contentRange.lastIndexOf('/');
_this.fileSize = parseInt(contentRange.substring(index + 1));
_this.bytePosition += byteArray.length;
_this.bytesRead += byteArray.length;
_this.options.bytes(byteArray);
if (_this.bytesRead < _this.fileSize) {
_this.read();
} else {
_this.options.complete();
}
};
var end = this.bytePosition + this.chunkSize - 1;
if (this.fileSize !== -1) {
end = Math.min(end, this.fileSize - 1);
}
// byte range is inclusive
oReq
.setRequestHeader('Range', 'bytes=' + this.bytePosition + '-'
+ end);
oReq.setRequestHeader('If-None-Match', 'webkit-no-cache'); //
// https://bugs.webkit.org/show_bug.cgi?id=82672
oReq.onerror = function() {
console.log('error');
};
oReq.send(null);
}
};
morpheus.FetchNetworkInputStream = function(url, options) {
var bytesRead = 0;
var fileSize = 0;
function pump(reader) {
return reader.read().then(function(result) {
if (result.done) {
options.complete();
return;
}
var chunk = result.value;
bytesRead += chunk.byteLength;
options.bytes(chunk);
return pump(reader);
});
}
fetch(url).then(function(res) {
// _this.fileSize = res.headers.get('Content-Length');
return pump(res.body.getReader());
});
};
morpheus.FileInputStream = function(file, options) {
var _this = this;
this.options = options || {};
this.reader = new FileReader();
this.reader.onloadend = function(evt) {
if (evt.target.readyState === FileReader.DONE) {
var arrayBuffer = evt.target.result;
var byteArray = new Uint8Array(arrayBuffer);
_this.bytePosition += byteArray.length;
_this.bytesRead += byteArray.length;
_this.options.bytes(byteArray);
if (_this.bytesRead < _this.fileSize) {
_this.read();
} else {
options.complete();
}
}
};
this.file = file;
this.bytePosition = 0;
this.chunkSize = options.chunkSize || 1024 * 1024 * 10; // 10 MB
this.bytesRead = 0;
this.fileSize = file.size;
this.read();
};
morpheus.FileInputStream.prototype = {
read : function() {
var _this = this;
var end = this.bytePosition + this.chunkSize;
end = Math.min(end, this.fileSize);
// byte
// range is
// exclusive
var blob = this.file.slice(this.bytePosition, end);
this.reader.readAsArrayBuffer(blob);
}
};
\ No newline at end of file
......@@ -7,42 +7,170 @@ morpheus.GctReader.prototype = {
return 'gct';
},
read: function (fileOrUrl, callback) {
var _this = this;
var name = morpheus.Util.getBaseFileName(morpheus.Util
.getFileName(fileOrUrl));
morpheus.BufferedReader.getArrayBuffer(fileOrUrl, function (err,
arrayBuffer) {
if (err) {
callback(err);
} else {
try {
callback(null, _this._read(name,
new morpheus.BufferedReader(new Uint8Array(
arrayBuffer))));
} catch (x) {
if (x.stack) {
console.log(x.stack);
var lineNumber = 0;
var version;
var numRowAnnotations = 1; // in addition to row id
var numColumnAnnotations = 0; // in addition to column id
var nrows = -1;
var ncols = -1;
var version = 2;
var rowMetadataNames = [];
var columnMetadataNames = [];
var rowMetadata = [[]];
var columnMetadata = [[]];
var dataColumnStart;
var matrix = [];
var dataMatrixLineNumberStart;
var columnIdFieldName = 'id';
var rowIdFieldName = 'id';
var columnNamesArray;
Papa.parse(fileOrUrl, {
delimiter: "\t", // auto-detect
newline: "", // auto-detect
header: false,
dynamicTyping: false,
preview: 0,
encoding: "",
worker: false,
comments: false,
step: function (result) {
if (lineNumber === 0) {
var text = result.data[0][0].trim();
if ('#1.2' === text) {
version = 2;
} else if ('#1.3' === text) {
version = 3;
} else {
console.log('Unknown version: assuming version 2');
}
} else if (lineNumber === 1) {
var dimensions = result.data[0];
if (version === 3) {
if (dimensions.length >= 4) {
nrows = parseInt(dimensions[0]);
ncols = parseInt(dimensions[1]);
numRowAnnotations = parseInt(dimensions[2]);
numColumnAnnotations = parseInt(dimensions[3]);
} else { // no dimensions specified
numRowAnnotations = parseInt(dimensions[0]);
numColumnAnnotations = parseInt(dimensions[1]);
}
} else {
nrows = parseInt(dimensions[0]);
ncols = parseInt(dimensions[1]);
if (nrows <= 0 || ncols <= 0) {
callback(
'Number of rows and columns must be greater than 0.');
}
}
dataColumnStart = numRowAnnotations + 1;
} else if (lineNumber === 2) {
columnNamesArray = result.data[0];
if (ncols === -1) {
ncols = columnNamesArray.length - numRowAnnotations - 1;
}
if (version == 2) {
var expectedColumns = ncols + 2;
if (columnNamesArray.length !== expectedColumns) {
callback('Expected ' + (expectedColumns - 2)
+ ' column names, but read '
+ (columnNamesArray.length - 2) + ' column names.');
}
}
var name = columnNamesArray[0];
var slashIndex = name.lastIndexOf('/');
if (slashIndex != -1 && slashIndex < (name.length - 1)) {
rowIdFieldName = name.substring(0, slashIndex);
columnIdFieldName = name.substring(slashIndex + 1);
}
rowMetadataNames.push(rowIdFieldName);
columnMetadataNames.push(columnIdFieldName);
for (var j = 0; j < ncols; j++) {
var index = j + numRowAnnotations + 1;
var columnName = index < columnNamesArray.length ? columnNamesArray[index]
: null;
columnMetadata[0].push(String(columnName));
}
for (var j = 0; j < numRowAnnotations; j++) {
var rowMetadataName = '' === columnNamesArray[1] ? 'description'
: columnNamesArray[j + 1];
rowMetadataNames.push(
rowMetadataName);
rowMetadata.push([]);
}
dataMatrixLineNumberStart = 3 + numColumnAnnotations;
} else { // lines >=3
var tokens = result.data[0];
if (lineNumber < dataMatrixLineNumberStart) {
var metadataName = tokens[0];
var v = [];
columnMetadata.push(v);
columnMetadataNames.push(metadataName);
for (var j = 0; j < ncols; j++) {
v.push(String(tokens[j + dataColumnStart]));
}
} else { // data lines
if (tokens[0] !== '') {
var array = new Float32Array(ncols);
matrix.push(array);
// we iterate to numRowAnnotations + 1 to include id row
// metadata field
for (var rowAnnotationIndex = 0; rowAnnotationIndex <= numRowAnnotations; rowAnnotationIndex++) {
var rowMetadataValue = tokens[rowAnnotationIndex];
rowMetadata[rowAnnotationIndex].push(
String(rowMetadataValue));
}
for (var columnIndex = 0; columnIndex < ncols; columnIndex++) {
var token = tokens[columnIndex + dataColumnStart];
array[columnIndex] = parseFloat(token);
}
}
}
callback(x);
}
}
});
lineNumber++;
},
complete: function () {
var dataset = new morpheus.Dataset({
name: morpheus.Util.getBaseFileName(morpheus.Util
.getFileName(fileOrUrl)),
rows: matrix.length,
columns: ncols,
array: matrix,
dataType: 'Float32'
});
for (var i = 0; i < rowMetadataNames.length; i++) {
dataset.getRowMetadata().add(rowMetadataNames[i]).array = rowMetadata[i];
}
for (var i = 0; i < columnMetadataNames.length; i++) {
dataset.getColumnMetadata().add(columnMetadataNames[i]).array = columnMetadata[i];
}
morpheus.MetadataUtil.maybeConvertStrings(dataset.getRowMetadata(), 1);
morpheus.MetadataUtil.maybeConvertStrings(dataset.getColumnMetadata(),
1);
callback(null, dataset);
},
error: function (err) {
callback(err);
},
download: !(fileOrUrl instanceof File),
skipEmptyLines: false,
chunk: undefined,
fastMode: true,
beforeFirstChunk: undefined,
withCredentials: undefined
});
},
_read: function (datasetName, reader) {
var tab = /\t/;
var versionLine = $.trim(reader.readLine());
if (versionLine === '') {
throw new Error('Missing version line');
}
var tab = /\t/;
var dimensionsLine = reader.readLine();
if (dimensionsLine == null) {
throw new Error('No dimensions specified');
}
var columnNamesLine = reader.readLine();
if (columnNamesLine == null) {
throw new Error('No column annotations');
}
var version = 2;
if ('#1.2' === versionLine) {
version = 2;
......@@ -51,6 +179,10 @@ morpheus.GctReader.prototype = {
} else {
console.log('Unknown version: assuming version 2');
}
var dimensionsLine = reader.readLine();
if (dimensionsLine == null) {
throw new Error('No dimensions specified');
}
// <numRows> <tab> <numCols>
var dimensions = dimensionsLine.split(/[ \t]/);
var numRowAnnotations = 1; // in addition to row id
......@@ -75,6 +207,10 @@ morpheus.GctReader.prototype = {
'Number of rows and columns must be greater than 0.');
}
}
var columnNamesLine = reader.readLine();
if (columnNamesLine == null) {
throw new Error('No column annotations');
}
var columnNamesArray = columnNamesLine.split(tab);
if (ncols === -1) {
......@@ -281,5 +417,28 @@ morpheus.GctReader.prototype = {
return dataset;
}
},
_read: function (fileOrUrl, callback) {
var _this = this;
var name = morpheus.Util.getBaseFileName(morpheus.Util
.getFileName(fileOrUrl));
morpheus.BufferedReader.getArrayBuffer(fileOrUrl, function (err,
arrayBuffer) {
if (err) {
callback(err);
} else {
try {
callback(null, _this._read(name,
new morpheus.BufferedReader(new Uint8Array(
arrayBuffer))));
} catch (x) {
if (x.stack) {
console.log(x.stack);
}
callback(x);
}
}
});
}
};
morpheus.LineReader = function(fileOrUrl, options) {
var _this = this;
this.str = '';
var isString = _.isString(fileOrUrl);
if (typeof TextDecoder !== 'undefined') {
var textDecoder = new TextDecoder();
this.decoder = function(buf, start, end) {
return textDecoder.decode(buf.subarray(start, end));
};
} else {
this.decoder = function(buf, start, end) {
// TODO convert in chunks
var s = '';
for (var i = start; i < end; i++) {
s += String.fromCharCode(buf[i]);
}
return s;
};
}
var inputStreamOptions = {
bytes : function(buf) {
_this.str += _this.decoder(buf, 0, buf.length);
var split = morpheus.LineReader._split(_this.str);
if (split.lines.length > 0) {
var lines = split.lines;
for (var i = 0, nlines = lines.length; i < nlines; i++) {
var line = lines[i];
if (line !== '') {
options.line(line);
}
}
_this.str = split.remainder;
}
},
complete : function() {
options.complete();
}
};
isString ? new morpheus.FetchNetworkInputStream(fileOrUrl,
inputStreamOptions) : new morpheus.FileInputStream(fileOrUrl,
inputStreamOptions);
};
morpheus.LineReader._split = function(str) {
var lines = [];
var start = 0;
var length = str.length;
for (var i = 0; i < length; i++) {
var c = str[i];
if (c === '\n' || c === '\r') {
var end = i;
if ((i < length - 1) && (str[i + 1] === '\n')) { // check for
// \r\n
i++;
}
lines.push(str.substring(start, end));
start = i + 1;
}
}
return {
lines : lines,
remainder : start <= length ? str.substring(start, length) : ''
};
};
// code taken from KineticJS
morpheus.Events = function() {
morpheus.Events = function () {
};
morpheus.Events.prototype = {
/**
* Pass in a string of events delimmited by a space to bind multiple events
* at once such as 'mousedown mouseup mousemove'. Include a namespace to
* bind an event by name such as 'click.foobar'.
*
*
* @param {String}
* evtStr e.g. 'click', 'mousedown touchstart', 'mousedown.foo
* touchstart.foo'
* @param {Function}
* handler The handler function is passed an event object
*/
on : function(evtStr, handler) {
on: function (evtStr, handler) {
if (!handler) {
throw Error('Handler not specified');
}
......@@ -35,19 +35,28 @@ morpheus.Events.prototype = {
this.eventListeners[baseEvent] = [];
}
this.eventListeners[baseEvent].push({
name : name,
handler : handler
name: name,
handler: handler
});
}
return this;
},
getListeners: function () {
if (!this.eventListeners) {
this.eventListeners = {};
}
return this.eventListeners;
},
setListeners: function (eventListeners) {
this.eventListeners = eventListeners;
},
/**
* Fire an event.
*
*
* @param eventType
* @param evt
*/
trigger : function(eventType, evt) {
trigger: function (eventType, evt) {
if (!this.eventListeners) {
this.eventListeners = {};
}
......@@ -62,7 +71,7 @@ morpheus.Events.prototype = {
if (events) {
var len = events.length;
for (var i = 0; i < len; i++) {
events[i].handler.apply(this, [ evt ]);
events[i].handler.apply(this, [evt]);
}
}
return this;
......@@ -73,11 +82,11 @@ morpheus.Events.prototype = {
* mouseup mousemove'. include a namespace to remove an event binding by
* name such as 'click.foobar'. If you only give a name like '.foobar', all
* events in that namespace will be removed.
*
*
* @param {String}
* evtStr e.g. 'click', 'mousedown.foo touchstart', '.foobar'
*/
off : function(evtStr, handler) {
off: function (evtStr, handler) {
if (!this.eventListeners) {
this.eventListeners = {};
}
......@@ -105,14 +114,14 @@ morpheus.Events.prototype = {
}
return this;
},
_off : function(type, name, handler) {
_off: function (type, name, handler) {
var evtListeners = this.eventListeners[type], i, evtName;
for (i = 0; i < evtListeners.length; i++) {
evtName = evtListeners[i].name;
// check if an event name is not specified, or if one is specified,
// it matches the current event name
if ((!name || evtName === name)
&& (handler == null || handler == evtListeners[i].handler)) {
&& (handler == null || handler == evtListeners[i].handler)) {
evtListeners.splice(i, 1);
if (evtListeners.length === 0) {
delete this.eventListeners[type];
......@@ -121,5 +130,5 @@ morpheus.Events.prototype = {
i--;
}
}
},
};
\ No newline at end of file
}
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment