@dd-decaf/escher
Version:
Escher: A Web Application for Building, Sharing, and Embedding Data-Rich Visualizations of Metabolic Pathways
1,570 lines (1,410 loc) • 1.34 MB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["escher"] = factory();
else
root["escher"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 117);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_creator__ = __webpack_require__(36);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "creator", function() { return __WEBPACK_IMPORTED_MODULE_0__src_creator__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__src_local__ = __webpack_require__(133);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "local", function() { return __WEBPACK_IMPORTED_MODULE_1__src_local__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__src_matcher__ = __webpack_require__(60);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "matcher", function() { return __WEBPACK_IMPORTED_MODULE_2__src_matcher__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__src_mouse__ = __webpack_require__(134);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "mouse", function() { return __WEBPACK_IMPORTED_MODULE_3__src_mouse__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__src_namespace__ = __webpack_require__(37);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "namespace", function() { return __WEBPACK_IMPORTED_MODULE_4__src_namespace__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__src_namespaces__ = __webpack_require__(38);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "namespaces", function() { return __WEBPACK_IMPORTED_MODULE_5__src_namespaces__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__src_point__ = __webpack_require__(26);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "clientPoint", function() { return __WEBPACK_IMPORTED_MODULE_6__src_point__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__src_select__ = __webpack_require__(135);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "select", function() { return __WEBPACK_IMPORTED_MODULE_7__src_select__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__src_selectAll__ = __webpack_require__(163);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "selectAll", function() { return __WEBPACK_IMPORTED_MODULE_8__src_selectAll__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__src_selection_index__ = __webpack_require__(6);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "selection", function() { return __WEBPACK_IMPORTED_MODULE_9__src_selection_index__["b"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__src_selector__ = __webpack_require__(41);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "selector", function() { return __WEBPACK_IMPORTED_MODULE_10__src_selector__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__src_selectorAll__ = __webpack_require__(61);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "selectorAll", function() { return __WEBPACK_IMPORTED_MODULE_11__src_selectorAll__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__src_selection_style__ = __webpack_require__(64);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "style", function() { return __WEBPACK_IMPORTED_MODULE_12__src_selection_style__["b"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__src_touch__ = __webpack_require__(164);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "touch", function() { return __WEBPACK_IMPORTED_MODULE_13__src_touch__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_14__src_touches__ = __webpack_require__(165);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "touches", function() { return __WEBPACK_IMPORTED_MODULE_14__src_touches__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__src_window__ = __webpack_require__(42);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "window", function() { return __WEBPACK_IMPORTED_MODULE_15__src_window__["a"]; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__src_selection_on__ = __webpack_require__(40);
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "event", function() { return __WEBPACK_IMPORTED_MODULE_16__src_selection_on__["c"]; });
/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "customEvent", function() { return __WEBPACK_IMPORTED_MODULE_16__src_selection_on__["a"]; });
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* global Blob, XMLSerializer, Image, btoa */
var vkbeautify = __webpack_require__(56);
var _ = __webpack_require__(2);
var Consts = __webpack_require__(57);
var d3_json = __webpack_require__(24).json;
var d3_text = __webpack_require__(24).text;
var d3_csvParseRows = __webpack_require__(34).csvParseRows;
var d3_selection = __webpack_require__(0).selection;
try {
var saveAs = __webpack_require__(166).saveAs;
} catch (e) {
console.warn('Not a browser, so FileSaver.js not available.');
}
module.exports = {
set_options: set_options,
remove_child_nodes: remove_child_nodes,
load_css: load_css,
load_files: load_files,
load_the_file: load_the_file,
make_class: make_class,
class_with_optional_new: class_with_optional_new,
setup_defs: setup_defs,
draw_an_object: draw_an_object,
draw_a_nested_object: draw_a_nested_object,
make_array: make_array,
make_array_ref: make_array_ref,
compare_arrays: compare_arrays,
arrayToObject: arrayToObject,
clone: clone,
extend: extend,
uniqueConcat: uniqueConcat,
unique_strings_array: unique_strings_array,
debounce: debounce,
object_slice_for_ids: object_slice_for_ids,
object_slice_for_ids_ref: object_slice_for_ids_ref,
c_plus_c: c_plus_c,
c_minus_c: c_minus_c,
c_times_scalar: c_times_scalar,
download_json: download_json,
load_json: load_json,
load_json_or_csv: load_json_or_csv,
downloadSvg: downloadSvg,
downloadPng: downloadPng,
rotate_coords_recursive: rotate_coords_recursive,
rotate_coords: rotate_coords,
get_angle: get_angle,
to_degrees: to_degrees,
angleNorm: angleNorm,
to_radians: to_radians,
to_radians_norm: to_radians_norm,
angle_for_event: angle_for_event,
distance: distance,
check_undefined: check_undefined,
compartmentalize: compartmentalize,
decompartmentalize: decompartmentalize,
mean: mean,
median: median,
quartiles: quartiles,
random_characters: random_characters,
generate_map_id: generate_map_id,
check_for_parent_tag: check_for_parent_tag,
name_to_url: name_to_url,
get_document: get_document,
get_window: get_window,
d3_transform_catch: d3_transform_catch,
// check_browser: check_browser
calculate_fva_opacity: calculate_fva_opacity,
findMap: findMap,
isMetabolite: isMetabolite,
htmlToElement: htmlToElement,
object_slice_for_bigg: object_slice_for_bigg,
get_central_or_last_nodes: get_central_or_last_nodes
/**
* Check if Blob is available, and alert if it is not.
*/
};function _check_filesaver() {
try {
var isFileSaverSupported = !!new Blob();
} catch (e) {
alert('Blob not supported');
}
}
function set_options(options, defaults, must_be_float) {
if (options === undefined || options === null) {
return defaults;
}
var i = -1;
var out = {};
for (var key in defaults) {
var has_key = key in options && options[key] !== null && options[key] !== undefined;
var val = has_key ? options[key] : defaults[key];
if (must_be_float && key in must_be_float) {
val = parseFloat(val);
if (isNaN(val)) {
if (has_key) {
console.warn('Bad float for option ' + key);
val = parseFloat(defaults[key]);
if (isNaN(val)) {
console.warn('Bad float for default ' + key);
val = null;
}
} else {
console.warn('Bad float for default ' + key);
val = null;
}
}
}
out[key] = val;
}
return out;
}
function remove_child_nodes(selection) {
/** Removes all child nodes from a d3 selection
*/
var node = selection.node();
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
}
function load_css(css_path, callback) {
var css = "";
if (css_path) {
d3_text(css_path, function (error, text) {
if (error) {
console.warn(error);
}
css = text;
callback(css);
});
}
return false;
}
function _ends_with(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
/**
* Load a file.
* @param {} t - this context for callback. Should be an object.
* @param {} files_to_load - A filename to load. Must be JSON or CSS.
* @param {} callback - Function to run after the file is loaded. Takes the
* arguments error and data.
* @param {} value - If the value is specified, just assign it and do not
* execute the ajax query.
*/
function load_the_file(t, file, callback, value) {
if (value) {
if (file) console.warn('File ' + file + ' overridden by value.');
callback.call(t, null, value);
return;
}
if (!file) {
callback.call(t, 'No filename', null);
return;
}
if (_ends_with(file, 'json')) {
d3_json(file, function (e, d) {
callback.call(t, e, d);
});
} else if (_ends_with(file, 'css')) {
d3_text(file, function (e, d) {
callback.call(t, e, d);
});
} else {
callback.call(t, 'Unrecognized file type', null);
}
return;
}
function load_files(t, files_to_load, final_callback) {
/** Load multiple files asynchronously by calling utils.load_the_file.
t: this context for callback. Should be an object.
files_to_load: A list of objects with the attributes:
{ file: a_filename.json, callback: a_callback_fn }
File must be JSON or CSS.
final_callback: Function that runs after all files have loaded.
*/
if (files_to_load.length === 0) final_callback.call(t);
var i = -1,
remaining = files_to_load.length;
while (++i < files_to_load.length) {
load_the_file(t, files_to_load[i].file, function (e, d) {
this.call(t, e, d);
if (! --remaining) final_callback.call(t);
}.bind(files_to_load[i].callback), files_to_load[i].value);
}
}
/**
* Create a constructor that returns a new object with our without the 'new'
* keyword.
*
* Adapted from Hubert Kauker (MIT Licensed), John Resig (MIT Licensed).
* http://stackoverflow.com/questions/7892884/simple-class-instantiation
*/
function make_class() {
var is_internal;
var constructor = function constructor(args) {
if (this instanceof constructor) {
if (typeof this.init === 'function') {
this.init.apply(this, is_internal ? args : arguments);
}
} else {
is_internal = true;
var instance = new constructor(arguments);
is_internal = false;
return instance;
}
};
return constructor;
}
/**
* Return a class that can be instantiated without the new keyword.
* @param {Class} AClass - Any ES6 class.
*/
function class_with_optional_new(AClass) {
return new Proxy(AClass, {
apply: function apply(Target, thisArg, args) {
return new (Function.prototype.bind.apply(Target, [null].concat(args)))();
}
});
}
function setup_defs(svg, style) {
// add stylesheet
svg.select("defs").remove();
var defs = svg.append("defs");
// make sure the defs is the first node
var node = defs.node();
node.parentNode.insertBefore(node, node.parentNode.firstChild);
defs.append("style").attr("type", "text/css").text(style);
return defs;
}
/**
* Run through the d3 data binding steps for an object. Also checks to make sure
* none of the values in the *object* are undefined, and ignores those.
*
* The create_function, update_function, and exit_function CAN modify the input
* data object.
*
* @param {} container_sel - A d3 selection containing all objects.
*
* @param {} parent_node_selector - A selector string for a subselection of
* container_sel.
*
* @param {} children_selector - A selector string for each DOM element to bind.
*
* @param {} object - An object to bind to the selection.
*
* @param {} id_key - The key that will be used to store object IDs in the bound
* data points.
*
* @param {} create_function - A function for enter selection. Create function
* must return a selection of the new nodes.
*
* @param {} update_function - A function for update selection.
*
* @param {} exit_function - A function for exit selection.
*/
function draw_an_object(container_sel, parent_node_selector, children_selector, object, id_key, create_function, update_function, exit_function) {
var draw_object = {};
for (var id in object) {
if (object[id] === undefined) {
console.warn('Undefined value for id ' + id + ' in object. Ignoring.');
} else {
draw_object[id] = object[id];
}
}
var sel = container_sel.select(parent_node_selector).selectAll(children_selector).data(make_array_ref(draw_object, id_key), function (d) {
return d[id_key];
});
// enter: generate and place reaction
var update_sel = create_function ? create_function(sel.enter()).merge(sel) : sel;
// update: update when necessary
if (update_function) {
update_sel.call(update_function);
}
// exit
if (exit_function) {
sel.exit().call(exit_function);
}
}
/**
* Run through the d3 data binding steps for an object that is nested within
* another element with D3 data.
*
* The create_function, update_function, and exit_function CAN modify the input
* data object.
*
* @param {} container_sel - A d3 selection containing all objects.
*
* @param {} children_selector - A selector string for each DOM element to bind.
*
* @param {} object_data_key - A key for the parent object containing data for
* the new selection.
*
* @param {} id_key - The key that will be used to store object IDs in the bound
* data points.
*
* @param {} create_function - A function for enter selection. Create function
* must return a selection of the new nodes.
*
* @param {} update_function - A function for update selection.
*
* @param {} exit_function - A function for exit selection.
*/
function draw_a_nested_object(container_sel, children_selector, object_data_key, id_key, create_function, update_function, exit_function) {
var sel = container_sel.selectAll(children_selector).data(function (d) {
return make_array_ref(d[object_data_key], id_key);
}, function (d) {
return d[id_key];
});
// enter: generate and place reaction
var update_sel = create_function ? create_function(sel.enter()).merge(sel) : sel;
// update: update when necessary
if (update_function) {
update_sel.call(update_function);
}
// exit
if (exit_function) {
sel.exit().call(exit_function);
}
}
function make_array(obj, id_key) {
// is this super slow?
var array = [];
for (var key in obj) {
// copy object
var it = clone(obj[key]);
// add key as 'id'
it[id_key] = key;
// add object to array
array.push(it);
}
return array;
}
function make_array_ref(obj, id_key) {
/** Turn the object into an array, but only by reference. Faster than
make_array.
*/
var array = [];
for (var key in obj) {
// copy object
var it = obj[key];
// add key as 'id'
it[id_key] = key;
// add object to array
array.push(it);
}
return array;
}
function compare_arrays(a1, a2) {
/** Compares two simple (not-nested) arrays.
*/
if (!a1 || !a2) return false;
if (a1.length != a2.length) return false;
for (var i = 0, l = a1.length; i < l; i++) {
if (a1[i] != a2[i]) {
// Warning - two different object instances will never be equal: {x:20} != {x:20}
return false;
}
}
return true;
}
/**
* Convert an array of objects to an object with all keys and values
* that are arrays of the same length as arr. Fills in spaces with null.
*
* For example, [ { a: 1 }, { b: 2 }] becomes { a: [1, null], b: [null, 2] }.
*/
function arrayToObject(arr) {
// new object
var obj = {};
// for each element of the array
for (var i = 0, l = arr.length; i < l; i++) {
var column = arr[i];
var keys = Object.keys(column);
for (var k = 0, nk = keys.length; k < nk; k++) {
var id = keys[k];
if (!(id in obj)) {
var n = [];
// fill spaces with null
for (var j = 0; j < l; j++) {
n[j] = null;
}
n[i] = column[id];
obj[id] = n;
} else {
obj[id][i] = column[id];
}
}
}
return obj;
}
/**
* Deep copy for array and object types. All other types are returned by
* reference.
* @param {T<Object|Array|*>} obj - The object to copy.
* @return {T} The copied object.
*/
function clone(obj) {
if (_.isArray(obj)) return _.map(obj, function (t) {
return clone(t);
});else if (_.isObject(obj)) return _.mapObject(obj, function (t, k) {
return clone(t);
});else return obj;
}
function extend(obj1, obj2, overwrite) {
/** Extends obj1 with keys/values from obj2. Performs the extension
cautiously, and does not override attributes, unless the overwrite
argument is true.
Arguments
---------
obj1: Object to extend
obj2: Object with which to extend.
overwrite: (Optional, Default false) Overwrite attributes in obj1.
*/
if (overwrite === undefined) overwrite = false;
for (var attrname in obj2) {
if (!(attrname in obj1) || overwrite) // UNIT TEST This
obj1[attrname] = obj2[attrname];else throw new Error('Attribute ' + attrname + ' already in object.');
}
}
function uniqueConcat(arrays) {
var newArray = [];
arrays.forEach(function (a) {
a.forEach(function (x) {
if (newArray.indexOf(x) < 0) {
newArray.push(x);
}
});
});
return newArray;
}
/**
* Return unique values in array of strings.
*
* http://stackoverflow.com/questions/1960473/unique-values-in-an-array
*/
function unique_strings_array(arr) {
var a = [];
for (var i = 0, l = arr.length; i < l; i++) {
if (a.indexOf(arr[i]) === -1) {
a.push(arr[i]);
}
}
return a;
}
/**
* Returns a function, that, as long as it continues to be invoked, will not be
* triggered. The function will be called after it stops being called for N
* milliseconds. If "immediate" is passed, trigger the function on the leading
* edge, instead of the trailing.
*/
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this;
var args = arguments;
var later = function later() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
/**
* Return a copy of the object with just the given ids.
* @param {} obj - An object
* @param {} ids - An array of id strings
*/
function object_slice_for_ids(obj, ids) {
var subset = {};
var i = -1;
while (++i < ids.length) {
subset[ids[i]] = clone(obj[ids[i]]);
}
if (ids.length !== Object.keys(subset).length) {
console.warn('did not find correct reaction subset');
}
return subset;
}
/**
* Return a reference of the object with just the given ids. Faster than
* object_slice_for_ids.
* @param {} obj - An object.
* @param {} ids - An array of id strings.
*/
function object_slice_for_ids_ref(obj, ids) {
var subset = {};
var i = -1;
while (++i < ids.length) {
subset[ids[i]] = obj[ids[i]];
}
if (ids.length !== Object.keys(subset).length) {
console.warn('did not find correct reaction subset');
}
return subset;
}
function c_plus_c(coords1, coords2) {
if (coords1 === null || coords2 === null || coords1 === undefined || coords2 === undefined) {
return null;
}
return {
x: coords1.x + coords2.x,
y: coords1.y + coords2.y
};
}
function c_minus_c(coords1, coords2) {
if (coords1 === null || coords2 === null || coords1 === undefined || coords2 === undefined) {
return null;
}
return {
x: coords1.x - coords2.x,
y: coords1.y - coords2.y
};
}
function c_times_scalar(coords, scalar) {
return {
x: coords.x * scalar,
y: coords.y * scalar
};
}
/**
* Download JSON file in a blob.
*/
function download_json(json, name) {
// Alert if blob isn't going to work
_check_filesaver();
var j = JSON.stringify(json);
var blob = new Blob([j], { type: 'application/json' });
saveAs(blob, name + '.json');
}
/**
* Try to load the file as JSON.
* @param {} f - The file path
* @param {} callback - A callback function that accepts arguments: error, data.
* @param {} pre_fn (optional) - A function to call before loading the data.
* @param {} failure_fn (optional) - A function to call if the load fails or is
* aborted.
*/
function load_json(f, callback, pre_fn, failure_fn) {
// Check for the various File API support
if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
callback('The File APIs are not fully supported in this browser.', null);
}
var reader = new window.FileReader();
// Closure to capture the file information.
reader.onload = function (event) {
var result = event.target.result;
var data;
// Try JSON
try {
data = JSON.parse(result);
} catch (e) {
// If it failed, return the error
callback(e, null);
return;
}
// If successful, return the data
callback(null, data);
};
if (pre_fn !== undefined && pre_fn !== null) {
try {
pre_fn();
} catch (e) {
console.warn(e);
}
}
reader.onabort = function (event) {
try {
failure_fn();
} catch (e) {
console.warn(e);
}
};
reader.onerror = function (event) {
try {
failure_fn();
} catch (e) {
console.warn(e);
}
};
// Read in the image file as a data URL
reader.readAsText(f);
}
/**
* Try to load the file as JSON or CSV (JSON first).
* @param {String} f - The file path
* @param {Function} csv_converter - A function to convert the CSV output to equivalent JSON.
* @param {Function} callback - A callback function that accepts arguments: error, data.
* @param {} pre_fn (optional) - A function to call before loading the data.
* @param {} failure_fn (optional) - A function to call if the load fails or is
* aborted.
* @param {} debug_event (optional) - An event, with a string at
* event.target.result, to load as though it was the contents of a loaded file.
*/
function load_json_or_csv(f, csv_converter, callback, pre_fn, failure_fn, debug_event) {
// Capture the file information.
var onload_function = function onload_function(event) {
var result = event.target.result;
var data;
var errors;
// try JSON
try {
data = JSON.parse(result);
} catch (e) {
errors = 'JSON error: ' + e;
// try csv
try {
data = csv_converter(d3_csvParseRows(result));
} catch (e) {
// if both failed, return the errors
callback(errors + '\nCSV error: ' + e, null);
return;
}
}
// if successful, return the data
callback(null, data);
};
if (debug_event !== undefined && debug_event !== null) {
console.warn('Debugging load_json_or_csv');
return onload_function(debug_event);
}
// Check for the various File API support.
if (!(window.File && window.FileReader && window.FileList && window.Blob)) callback("The File APIs are not fully supported in this browser.", null);
var reader = new window.FileReader();
if (pre_fn !== undefined && pre_fn !== null) {
try {
pre_fn();
} catch (e) {
console.warn(e);
}
}
reader.onabort = function (event) {
try {
failure_fn();
} catch (e) {
console.warn(e);
}
};
reader.onerror = function (event) {
try {
failure_fn();
} catch (e) {
console.warn(e);
}
};
// Read in the image file as a data URL.
reader.onload = onload_function;
reader.readAsText(f);
}
/**
* Download an svg file using FileSaver.js.
* @param {String} name - The filename (without extension)
* @param {D3 Selection} svg_sel - The d3 selection for the SVG element
* @param {Boolean} do_beautify - If true, then beautify the SVG output
*/
function downloadSvg(name, svg_sel, do_beautify) {
// Alert if blob isn't going to work
_check_filesaver();
// Make the xml string
var xml = new XMLSerializer().serializeToString(svg_sel.node());
if (do_beautify) xml = vkbeautify.xml(xml);
xml = '<?xml version="1.0" encoding="utf-8"?>\n' + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"\n' + ' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' + xml;
// Save
var blob = new Blob([xml], { type: 'image/svg+xml' });
saveAs(blob, name + '.svg');
}
/**
* Download a png file using FileSaver.js.
* @param {String} name - The filename (without extension).
* @param {D3 Selection} svg_sel - The d3 selection for the SVG element.
*/
function downloadPng(name, svg_sel) {
// Alert if blob isn't going to work
_check_filesaver();
// Make the xml string
var xml = new XMLSerializer().serializeToString(svg_sel.node());
xml = '<?xml version="1.0" encoding="utf-8"?>\n' + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"\n' + ' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' + xml;
// Canvas to hold the image
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
// Get SVG size
var svg_size = svg_sel.node().getBBox();
var svg_width = svg_size.width + svg_size.x;
var svg_height = svg_size.height + svg_size.y;
// Canvas size = SVG size. Constrained to 10000px for very large SVGs
if (svg_width < 10000 && svg_height < 10000) {
canvas.width = svg_width;
canvas.height = svg_height;
} else {
if (canvas.width > canvas.height) {
canvas.width = 10000;
canvas.height = 10000 * (svg_height / svg_width);
} else {
canvas.width = 10000 * (svg_width / svg_height);
canvas.height = 10000;
}
}
// Image element appended with data
var base_image = new Image();
base_image.src = 'data:image/svg+xml;base64,' + btoa(xml);
base_image.onload = function () {
// Draw image to canvas with white background
context.fillStyle = '#FFF';
context.fillRect(0, 0, canvas.width, canvas.height);
context.drawImage(base_image, 0, 0, canvas.width, canvas.height);
// Save image
canvas.toBlob(function (blob) {
saveAs(blob, name + '.png');
});
};
}
function rotate_coords_recursive(coords_array, angle, center) {
return coords_array.map(function (c) {
return rotate_coords(c, angle, center);
});
}
/**
* Calculates displacement { x: dx, y: dy } based on rotating point c around
* center with angle.
*/
function rotate_coords(c, angle, center) {
var dx = Math.cos(-angle) * (c.x - center.x) + Math.sin(-angle) * (c.y - center.y) + center.x - c.x;
var dy = -Math.sin(-angle) * (c.x - center.x) + Math.cos(-angle) * (c.y - center.y) + center.y - c.y;
return { x: dx, y: dy };
}
/**
* Get the angle between coordinates
* @param {Object} coords - Array of 2 coordinate objects { x: 1, y: 1 }
* @return {Number} angle between 0 and 2PI.
*/
function get_angle(coords) {
var denominator = coords[1].x - coords[0].x;
var numerator = coords[1].y - coords[0].y;
if (denominator === 0 && numerator >= 0) {
return Math.PI / 2;
} else if (denominator === 0 && numerator < 0) {
return 3 * Math.PI / 2;
} else if (denominator >= 0 && numerator >= 0) {
return Math.atan(numerator / denominator);
} else if (denominator >= 0) {
return Math.atan(numerator / denominator) + 2 * Math.PI;
} else {
return Math.atan(numerator / denominator) + Math.PI;
}
}
function to_degrees(radians) {
return radians * 180 / Math.PI;
}
/**
* Force to domain -PI to PI
*/
function angleNorm(radians) {
if (radians < -Math.PI) {
return radians + Math.floor((radians - Math.PI) / (-2 * Math.PI)) * 2 * Math.PI;
} else if (radians > Math.PI) {
return radians - Math.floor((radians + Math.PI) / (2 * Math.PI)) * 2 * Math.PI;
} else {
return radians;
}
}
function to_radians(degrees) {
return Math.PI / 180 * degrees;
}
/**
* Convert to radians, and force to domain -PI to PI
*/
function to_radians_norm(degrees) {
var radians = to_radians(degrees);
return angleNorm(radians);
}
function angle_for_event(displacement, point, center) {
var gamma = Math.atan2(point.x - center.x, center.y - point.y);
var beta = Math.atan2(point.x - center.x + displacement.x, center.y - point.y - displacement.y);
var angle = beta - gamma;
return angle;
}
function distance(start, end) {
return Math.sqrt(Math.pow(end.y - start.y, 2) + Math.pow(end.x - start.x, 2));
}
/**
* Report an error if any of the arguments are undefined. Call by passing in
* "arguments" from any function and an array of argument names.
*/
function check_undefined(args, names) {
names.forEach(function (name, i) {
if (args[i] === undefined) {
console.error('Argument is undefined: ' + names[i]);
}
});
}
function compartmentalize(bigg_id, compartment_id) {
return bigg_id + '_' + compartment_id;
}
/**
* Returns an array of [bigg_id, compartment id]. Matches compartment ids with
* length 1 or 2. Return [ id, null ] if no match is found.
*/
function decompartmentalize(id) {
var reg = /(.*)_([a-z0-9]{1,2})$/;
var result = reg.exec(id);
return result !== null ? result.slice(1, 3) : [id, null];
}
function mean(array) {
var sum = array.reduce(function (a, b) {
return a + b;
});
var avg = sum / array.length;
return avg;
}
function median(array) {
array.sort(function (a, b) {
return a - b;
});
var half = Math.floor(array.length / 2);
if (array.length % 2 == 1) {
return array[half];
} else {
return (array[half - 1] + array[half]) / 2.0;
}
}
function quartiles(array) {
array.sort(function (a, b) {
return a - b;
});
var half = Math.floor(array.length / 2);
if (array.length === 1) {
return [array[0], array[0], array[0]];
} else if (array.length % 2 === 1) {
return [median(array.slice(0, half)), array[half], median(array.slice(half + 1))];
} else {
return [median(array.slice(0, half)), (array[half - 1] + array[half]) / 2.0, median(array.slice(half))];
}
}
/**
* Generate random characters
*
* Thanks to @csharptest.net
* http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript
*/
function random_characters(num) {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < num; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
function generate_map_id() {
return random_characters(12);
}
/**
* Check that the selection has the given parent tag.
* @param {D3 Selection|DOM Node} el - A D3 Selection or DOM Node to check.
* @param {String} tag - A tag name (case insensitive).
*/
function check_for_parent_tag(el, tag) {
// make sure it is a node
if (el instanceof d3_selection) {
el = el.node();
}
while (el.parentNode !== null) {
el = el.parentNode;
if (el.tagName === undefined) {
continue;
}
if (el.tagName.toLowerCase() === tag.toLowerCase()) {
return true;
}
}
return false;
}
/**
* Convert model or map name to url.
* @param {String} name - The short name, e.g. e_coli.iJO1366.central_metabolism.
* @param {String} download_url (optional) - The url to prepend.
*/
function name_to_url(name, download_url) {
if (download_url !== undefined && download_url !== null) {
// strip download_url
download_url = download_url.replace(/^\/|\/$/g, '');
name = [download_url, name].join('/');
}
// strip final path
return name.replace(/^\/|\/$/g, '') + '.json';
}
/**
* Get the document for the node
*/
function get_document(node) {
return node.ownerDocument;
}
/**
* Get the window for the node
*/
function get_window(node) {
return get_document(node).defaultView;
}
/**
* Get translation and rotation values for a transform string. This used to be
* in d3, but since v4, I just adapted a solution from SO:
*
* http://stackoverflow.com/questions/38224875/replacing-d3-transform-in-d3-v4
*
* To get skew and scale out, go back to that example.
*
* TODO rename function without "catch"
*
* @param {String} transform_attr - A transform string.
*/
function d3_transform_catch(transform_attr) {
if (transform_attr.indexOf('skew') !== -1 || transform_attr.indexOf('matrix') !== -1) {
throw new Error('d3_transform_catch does not work with skew or matrix');
}
var translate_res = /translate\s*\(\s*([0-9.-]+)\s*,\s*([0-9.-]+)\s*\)/.exec(transform_attr);
var tn = _.isNull(translate_res);
var tx = tn ? 0.0 : Number(translate_res[1]);
var ty = tn ? 0.0 : Number(translate_res[2]);
var rotate_res = /rotate\s*\(\s*([0-9.-]+)\s*\)/.exec(transform_attr);
var rn = _.isNull(rotate_res);
var r = rn ? 0.0 : Number(rotate_res[1]);
var scale_res = /scale\s*\(\s*([0-9.-]+)\s*\)/.exec(transform_attr);
var sn = _.isNull(scale_res);
var s = sn ? 0.0 : Number(scale_res[1]);
return { translate: [tx, ty], rotate: r, scale: s
// // Create a dummy g for calculation purposes only. This will new be appended
// // to the DOM and will be discarded once this function returns.
// var g = document.createElementNS('http://www.w3.org/2000/svg', 'g')
// // Set the transform attribute to the provided string value.
// g.setAttributeNS(null, 'transform', transform_attr)
// // Consolidate the SVGTransformList containing all Try to a single
// // SVGTransform of type SVG_TRANSFORM_MATRIX and get its SVGMatrix.
// var matrix = g.transform.baseVal.consolidate().matrix
// // Below calculations are taken and adapted from the private func
// // transform/decompose.js of D3's module d3-interpolate.
// var a = matrix.a
// var b = matrix.b
// var c = matrix.c
// var d = matrix.d
// var e = matrix.e
// var f = matrix.f
// var scaleX = Math.sqrt(a * a + b * b)
// if (scaleX) {
// a /= scaleX
// b /= scaleX
// }
// if (a * d < b * c) {
// a = -a
// b = -b
// }
// return {
// translate: [ e, f ],
// rotate: Math.atan2(b, a) * Math.PI / 180,
// }
};
}
/**
* Look for name in the user agent string.
*/
// function check_browser (name) {
// var browser = function() {
// // Thanks to
// // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
// var ua = navigator.userAgent
// var M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []
// var tem
// if (/trident/i.test(M[1])) {
// tem = /\brv[ :]+(\d+)/g.exec(ua) || []
// return 'IE '+ (tem[1] || '')
// }
// if (M[1] === 'Chrome') {
// tem = ua.match(/\b(OPR|Edge)\/(\d+)/)
// if (tem != null) return tem.slice(1).join(' ').replace('OPR', 'Opera')
// }
// M = M[2] ? [ M[1], M[2] ]: [ navigator.appName, navigator.appVersion, '-?' ]
// if ((tem = ua.match(/version\/(\d+)/i)) !== null) {
// M.splice(1, 1, tem[1])
// }
// return M.join(' ')
// }
// try {
// // navigator.userAgent is deprecated, so don't count on it
// return browser().toLowerCase().indexOf(name) > -1
// } catch (e) {
// return false
// }
// }
function calculate_fva_opacity(flux, lower, upper) {
if (Math.abs(lower - upper) < 1e-6) {
return 1;
} else if (lower < 0 && upper > 0) {
return 0.2;
} else if (lower <= 1e-6 || upper >= -1e-6) {
return 0.5;
} else if (lower > 1e-6 || upper < -1e-6) {
return 0.8;
}
}
// returns the first element
function findMap(array, pred) {
return array.reduce(function (accumulator, next) {
return accumulator || pred(next);
}, null);
}
function isMetabolite(metabolite) {
var cofactors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Consts.cofactors;
return !cofactors.includes(decompartmentalize(metabolite)[0]);
}
function htmlToElement(html) {
var template = document.createElement('template');
html = html.trim(); // Never return a text node of whitespace as the result
template.innerHTML = html;
return template.content.firstChild;
}
function object_slice_for_bigg(obj, bigg_ids) {
/** Return a copy of the object with just the given bigg ids.
Arguments
---------
obj: An object.
ids: An array of bigg id strings.
*/
return _.pick(obj, function (r) {
return _.contains(bigg_ids, r.bigg_id);
});
}
/**
*
* @param {*} reactions
*/
function get_central_or_last_nodes(reactions) {
return Object.assign.apply(Object, [{}].concat(Object.entries(reactions).map(function (_ref) {
var _ref2;
var r_id = _ref[0],
segments = _ref[1].segments;
segments = Object.values(segments);
if (segments.length >= 5) {
segments = segments.filter(function (segment) {
return segment.b1 === null && segment.b2 === null;
});
}
var nodes = segments.map(function (seg) {
return [seg.from_node_id, seg.to_node_id];
});
var node = void 0;
if (nodes.length === 1) {
// Use the last node for reactions with one segment
node = nodes[0][1];
} else {
// Extract a not ending node
node = nodes[0].filter(function (x) {
return new Set(nodes[1]).has(x);
});
}
return _ref2 = {}, _ref2[r_id] = [node], _ref2;
})));
}
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// Underscore.js 1.8.3
// http://underscorejs.org
// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Underscore may be freely distributed under the MIT license.
(function() {
// Baseline setup
// --------------
// Establish the root object, `window` in the browser, or `exports` on the server.
var root = this;
// Save the previous value of the `_` variable.
var previousUnderscore = root._;
// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
// Create quick reference variables for speed access to core prototypes.
var
push = ArrayProto.push,
slice = ArrayProto.slice,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;
// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
var
nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeBind = FuncProto.bind,
nativeCreate = Object.create;
// Naked function reference for surrogate-prototype-swapping.
var Ctor = function(){};
// Create a safe reference to the Underscore object for use below.
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
};
// Export the Underscore object for **Node.js**, with
// backwards-compatibility for the old `require()` API. If we're in
// the browser, add `_` as a global object.
if (true) {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else {
root._ = _;
}
// Current version.
_.VERSION = '1.8.3';
// Internal function that returns an efficient (for current engines) version
// of the passed-in callback, to be repeatedly applied in other Underscore
// functions.
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func;
switch (argCount == null ? 3 : argCount) {
case 1: return function(value) {
return func.call(context, value);
};
case 2: return function(value, other) {
return func.call(context, value, other);
};
case 3: return function(value, index, collection) {
return func.call(context, value, index, collection);
};
case 4: return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
return function() {
return func.apply(context, arguments);
};
};
// A mostly-internal function to generate callbacks that can be applied
// to each element in a collection, returning the desired result — either
// identity, an arbitrary callback, a property matcher, or a property accessor.
var cb = function(value, context, argCount) {
if (value == null) return _.identity;
if (_.isFunction(value)) return optimizeCb(value, context, argCount);
if (_.isObject(value)) return _.matcher(value);
return _.property(value);
};
_.iteratee = function(value, context) {
return cb(value, context, Infinity);
};
// An internal function for creating assigner functions.
var createAssigner = function(keysFunc, undefinedOnly) {
return function(obj) {
var length = arguments.length;
if (length < 2 || obj == null) return obj;
for (var index = 1; index < length; index++) {
var source = arguments[index],
keys = keysFunc(source),
l = keys.length;
for (var i = 0; i < l; i++) {
var key = keys[i];
if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
}
}
return obj;
};
};
// An internal function for creating a new object that inherits from another.
var baseCreate = function(prototype) {
if (!_.isObject(prototype)) return {};
if (nativeCreate) return nativeCreate(prototype);
Ctor.prototype = prototype;
var result = new Ctor;
Ctor.prototype = null;
return result;
};
var property = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};
// Helper for collection methods to determine whether a collection
// should be iterated as an array or as an object
// Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
// Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
var length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};
// Collection Functions
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
// Handles raw objects in addition to array-likes. Treats all
// sparse array-likes as if they were dense.
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context);
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
// Return the results of applying the iteratee to each element.
_.map = _.collect = function(obj, iteratee, context) {
iteratee = cb(iteratee, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
results = Array(length);
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
// Create a reducing function iterating left or right.
function createReduce(dir) {
// Optimized iterator function as using arguments.length
// in the main function will deoptimize the, see #1991.
function iterator(obj, iteratee, memo, keys, index, length) {
for (; index >= 0 && index < length; index += dir) {
var currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
}
return function(obj, iteratee, memo, context) {
iteratee = optimizeCb(iteratee, context, 4);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
index = dir > 0 ? 0 : length - 1;
// Determine the initial value if none is provided.
if (arguments.length < 3) {
memo = obj[keys ? keys[index] : index];
index += dir;
}
return iterator(obj, iteratee, memo, keys, index, length);
};
}
// **Reduce** builds up a single result from a list of values, aka `inject`,
// or `foldl`.
_.reduce = _.foldl = _.inject = createReduce(1);
// The right-associative version of reduce, also known as `foldr`.
_.reduceRight = _.foldr = createReduce(-1);
// Return the first value which passes a truth test. Aliased as `detect`.
_.find = _.detect = function(obj, predicate, context) {
var key;
if (isArrayLike(obj)) {
key = _.findIndex(obj, predicate, context);
} else {
key = _.findKey(obj, predicate, context);
}
if (key !== void 0 && key !== -1) return obj[key];
};
// Return all the elements that pass a truth test.
// Aliased as `select`.
_.filter = _.select = function(obj, predicate, context) {
var results = [];
predicate = cb(predicate, context);
_.each(obj, function(value, index, list) {
if (predicate(value, index, list)) results.push(value);
});
return results;
};
// Return all the elements for which a truth test fails.
_.reject = function(obj, predicate, context) {
return _.filter(obj, _.negate(cb(predicate)), context);
};
// Determine whether all of the elements match a truth test.
// Aliased as `all`.
_.every = _.all = function(obj, predicate, context) {
predicate = cb(predicate, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length;
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
if (!predicate(obj[currentKey], currentKey, obj)) return false;
}
return true;
};
// Determine if at least one element in the object matches a truth test.
// Aliased as `any`.
_.some = _.any = function(obj, predicate, context) {
predicate = cb(predicate, context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length;
for (var index = 0; index < length; index++) {
var currentKey = keys ? keys[index] : index;
if (predicate(obj[currentKey], currentKey, obj)) return true;
}
return false;