711 lines
No EOL
19 KiB
JavaScript
711 lines
No EOL
19 KiB
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["cytoscapeAutomove"] = factory();
|
|
else
|
|
root["cytoscapeAutomove"] = 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;
|
|
/******/
|
|
/******/ // identity function for calling harmony imports with the correct context
|
|
/******/ __webpack_require__.i = function(value) { return value; };
|
|
/******/
|
|
/******/ // 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 = 3);
|
|
/******/ })
|
|
/************************************************************************/
|
|
/******/ ([
|
|
/* 0 */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|
|
|
var defaults = __webpack_require__(2);
|
|
|
|
var typeofStr = _typeof('');
|
|
var typeofObj = _typeof({});
|
|
var typeofFn = _typeof(function () {});
|
|
|
|
var isObject = function isObject(x) {
|
|
return (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === typeofObj;
|
|
};
|
|
var isString = function isString(x) {
|
|
return (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === typeofStr;
|
|
};
|
|
var isFunction = function isFunction(x) {
|
|
return (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === typeofFn;
|
|
};
|
|
var isCollection = function isCollection(x) {
|
|
return isObject(x) && isFunction(x.collection);
|
|
};
|
|
|
|
// Object.assign() polyfill
|
|
var assign = __webpack_require__(1);
|
|
|
|
var eleExists = function eleExists(ele) {
|
|
return ele != null && !ele.removed();
|
|
};
|
|
|
|
var _elesHasEle = function elesHasEle(eles, ele) {
|
|
if (eles.has != undefined) {
|
|
// 3.x
|
|
_elesHasEle = function elesHasEle(eles, ele) {
|
|
return eles.has(ele);
|
|
};
|
|
} else {
|
|
// 2.x
|
|
_elesHasEle = function elesHasEle(eles, ele) {
|
|
return eles.intersection(ele).length > 0;
|
|
};
|
|
}
|
|
|
|
return _elesHasEle(eles, ele);
|
|
};
|
|
|
|
var getEleMatchesSpecFn = function getEleMatchesSpecFn(spec) {
|
|
if (isString(spec)) {
|
|
return function (ele) {
|
|
return ele.is(spec);
|
|
};
|
|
} else if (isFunction(spec)) {
|
|
return spec;
|
|
} else if (isCollection(spec)) {
|
|
return function (ele) {
|
|
return _elesHasEle(spec, ele);
|
|
};
|
|
} else {
|
|
throw new Error('Can not create match function for spec', spec);
|
|
}
|
|
};
|
|
|
|
var bindings = [];
|
|
|
|
var bind = function bind(cy, events, selector, fn) {
|
|
var b = { cy: cy, events: events, selector: selector || 'node', fn: fn };
|
|
|
|
bindings.push(b);
|
|
|
|
cy.on(b.events, b.selector, b.fn);
|
|
|
|
return b;
|
|
};
|
|
|
|
var bindOnRule = function bindOnRule(rule, cy, events, selector, fn) {
|
|
var b = bind(cy, events, selector, fn);
|
|
var bindings = rule.bindings = rule.bindings || [];
|
|
|
|
bindings.push(b);
|
|
};
|
|
|
|
var unbindAllOnRule = function unbindAllOnRule(rule) {
|
|
var unbind = function unbind(b) {
|
|
b.cy.off(b.events, b.selector, b.fn);
|
|
};
|
|
|
|
rule.bindings.forEach(unbind);
|
|
|
|
rule.bindings = [];
|
|
};
|
|
|
|
var getRepositioner = function getRepositioner(rule, cy) {
|
|
var r = rule.reposition;
|
|
|
|
if (r === 'mean') {
|
|
return meanNeighborhoodPosition(getEleMatchesSpecFn(rule.meanIgnores));
|
|
} else if (r === 'viewport') {
|
|
return viewportPosition(cy);
|
|
} else if (r === 'drag') {
|
|
return dragAlong(rule);
|
|
} else if (isObject(r)) {
|
|
if (r.type == undefined || r.type == "inside") {
|
|
return boxPosition(r);
|
|
} else if (r.type == "outside") {
|
|
return outsideBoxPosition(r);
|
|
}
|
|
} else {
|
|
return r;
|
|
}
|
|
};
|
|
|
|
var dragAlong = function dragAlong(rule) {
|
|
return function (node) {
|
|
var pos = node.position();
|
|
var delta = rule.delta;
|
|
|
|
if (rule.delta != null && !node.same(rule.grabbedNode) && !node.grabbed()) {
|
|
return {
|
|
x: pos.x + delta.x,
|
|
y: pos.y + delta.y
|
|
};
|
|
}
|
|
};
|
|
};
|
|
|
|
var meanNeighborhoodPosition = function meanNeighborhoodPosition(ignore) {
|
|
return function (node) {
|
|
var nhood = node.neighborhood();
|
|
var avgPos = { x: 0, y: 0 };
|
|
var nhoodSize = 0;
|
|
|
|
for (var i = 0; i < nhood.length; i++) {
|
|
var nhoodEle = nhood[i];
|
|
|
|
if (nhoodEle.isNode() && !ignore(nhoodEle)) {
|
|
var pos = nhoodEle.position();
|
|
|
|
avgPos.x += pos.x;
|
|
avgPos.y += pos.y;
|
|
|
|
nhoodSize++;
|
|
}
|
|
}
|
|
|
|
// the position should remain unchanged if we would stack the nodes on top of each other
|
|
if (nhoodSize < 2) {
|
|
return undefined;
|
|
}
|
|
|
|
avgPos.x /= nhoodSize;
|
|
avgPos.y /= nhoodSize;
|
|
|
|
return avgPos;
|
|
};
|
|
};
|
|
|
|
var constrain = function constrain(val, min, max) {
|
|
return val < min ? min : val > max ? max : val;
|
|
};
|
|
|
|
var constrainInBox = function constrainInBox(node, bb) {
|
|
var pos = node.position();
|
|
|
|
return {
|
|
x: constrain(pos.x, bb.x1, bb.x2),
|
|
y: constrain(pos.y, bb.y1, bb.y2)
|
|
};
|
|
};
|
|
|
|
var boxPosition = function boxPosition(bb) {
|
|
return function (node) {
|
|
return constrainInBox(node, bb);
|
|
};
|
|
};
|
|
|
|
var constrainOutsideBox = function constrainOutsideBox(node, bb) {
|
|
var pos = node.position();
|
|
var x = pos.x,
|
|
y = pos.y;
|
|
var x1 = bb.x1,
|
|
y1 = bb.y1,
|
|
x2 = bb.x2,
|
|
y2 = bb.y2;
|
|
|
|
var inX = x1 <= x && x <= x2;
|
|
var inY = y1 <= y && y <= y2;
|
|
var abs = Math.abs;
|
|
|
|
if (inX && inY) {
|
|
// inside
|
|
var dx1 = abs(x1 - x);
|
|
var dx2 = abs(x2 - x);
|
|
var dy1 = abs(y1 - y);
|
|
var dy2 = abs(y2 - y);
|
|
var min = Math.min(dx1, dx2, dy1, dy2); // which side of box is closest?
|
|
|
|
// get position outside, by closest side of box
|
|
if (min === dx1) {
|
|
return { x: x1, y: y };
|
|
} else if (min === dx2) {
|
|
return { x: x2, y: y };
|
|
} else if (min === dy1) {
|
|
return { x: x, y: y1 };
|
|
} else {
|
|
// min === dy2
|
|
return { x: x, y: y2 };
|
|
}
|
|
} else {
|
|
// outside already
|
|
return { x: x, y: y };
|
|
}
|
|
};
|
|
|
|
var outsideBoxPosition = function outsideBoxPosition(bb) {
|
|
return function (node) {
|
|
return constrainOutsideBox(node, bb);
|
|
};
|
|
};
|
|
|
|
var viewportPosition = function viewportPosition(cy) {
|
|
return function (node) {
|
|
var extent = cy.extent();
|
|
var w = node.outerWidth();
|
|
var h = node.outerHeight();
|
|
var bb = {
|
|
x1: extent.x1 + w / 2,
|
|
x2: extent.x2 - w / 2,
|
|
y1: extent.y1 + h / 2,
|
|
y2: extent.y2 - h / 2
|
|
};
|
|
|
|
return constrainInBox(node, bb);
|
|
};
|
|
};
|
|
|
|
var meanListener = function meanListener(rule) {
|
|
return function (update, cy) {
|
|
var matches = function matches(ele) {
|
|
// must meet ele set and be connected to more than (1 edge + 1 node)
|
|
return rule.matches(ele) && ele.neighborhood().length > 2 && !ele.grabbed();
|
|
};
|
|
|
|
bindOnRule(rule, cy, 'position', 'node', function () {
|
|
var movedNode = this;
|
|
|
|
if (movedNode.neighborhood().some(matches) || rule.meanOnSelfPosition(movedNode) && matches(movedNode)) {
|
|
update(cy, [rule]);
|
|
}
|
|
});
|
|
|
|
bindOnRule(rule, cy, 'add remove', 'edge', function () {
|
|
var edge = this;
|
|
var src = cy.getElementById(edge.data('source'));
|
|
var tgt = cy.getElementById(edge.data('target'));
|
|
|
|
if ([src, tgt].some(matches)) {
|
|
update(cy, [rule]);
|
|
}
|
|
});
|
|
};
|
|
};
|
|
|
|
var dragListener = function dragListener(rule) {
|
|
return function (update, cy) {
|
|
bindOnRule(rule, cy, 'grab', 'node', function () {
|
|
var node = this;
|
|
|
|
if (rule.dragWithMatches(node)) {
|
|
var p = node.position();
|
|
|
|
rule.grabbedNode = node;
|
|
rule.p1 = { x: p.x, y: p.y };
|
|
rule.delta = { x: 0, y: 0 };
|
|
}
|
|
});
|
|
|
|
bindOnRule(rule, cy, 'drag', 'node', function () {
|
|
var node = this;
|
|
|
|
if (node.same(rule.grabbedNode)) {
|
|
var d = rule.delta;
|
|
var p1 = rule.p1;
|
|
var p = node.position();
|
|
var p2 = { x: p.x, y: p.y };
|
|
|
|
d.x = p2.x - p1.x;
|
|
d.y = p2.y - p1.y;
|
|
|
|
rule.p1 = p2;
|
|
|
|
update(cy, [rule]);
|
|
}
|
|
});
|
|
|
|
bindOnRule(rule, cy, 'free', 'node', function () {
|
|
rule.grabbedNode = null;
|
|
rule.delta = null;
|
|
rule.p1 = null;
|
|
});
|
|
};
|
|
};
|
|
|
|
var matchingNodesListener = function matchingNodesListener(rule) {
|
|
return function (update, cy) {
|
|
bindOnRule(rule, cy, 'position', 'node', function () {
|
|
var movedNode = this;
|
|
|
|
if (rule.matches(movedNode)) {
|
|
update(cy, [rule]);
|
|
}
|
|
});
|
|
};
|
|
};
|
|
|
|
var getListener = function getListener(cy, rule) {
|
|
if (rule.reposition === 'mean') {
|
|
return meanListener(rule);
|
|
} else if (rule.reposition === 'drag') {
|
|
return dragListener(rule);
|
|
} else if (isObject(rule.reposition) || rule.when === 'matching' || rule.reposition === 'viewport') {
|
|
return matchingNodesListener(rule);
|
|
} else {
|
|
return rule.when;
|
|
}
|
|
};
|
|
|
|
var addRule = function addRule(cy, scratch, options) {
|
|
var rule = assign({}, defaults, options);
|
|
|
|
rule.getNewPos = getRepositioner(rule, cy);
|
|
rule.listener = getListener(cy, rule);
|
|
|
|
var nodesAreCollection = isCollection(rule.nodesMatching);
|
|
|
|
if (nodesAreCollection) {
|
|
rule.nodes = rule.nodesMatching.slice();
|
|
|
|
rule.matches = function (ele) {
|
|
return eleExists(ele) && _elesHasEle(rule.nodes, ele);
|
|
};
|
|
} else {
|
|
var matches = getEleMatchesSpecFn(rule.nodesMatching);
|
|
|
|
rule.matches = function (ele) {
|
|
return eleExists(ele) && matches(ele);
|
|
};
|
|
}
|
|
|
|
if (rule.dragWith != null) {
|
|
rule.dragWithMatches = getEleMatchesSpecFn(rule.dragWith);
|
|
}
|
|
|
|
rule.listener(function () {
|
|
update(cy, [rule]);
|
|
}, cy);
|
|
|
|
rule.enabled = true;
|
|
|
|
scratch.rules.push(rule);
|
|
|
|
return rule;
|
|
};
|
|
|
|
var bindForNodeList = function bindForNodeList(cy, scratch) {
|
|
scratch.onAddNode = function (evt) {
|
|
var target = evt.target;
|
|
|
|
scratch.nodes.merge(target);
|
|
};
|
|
|
|
scratch.onRmNode = function (evt) {
|
|
var target = evt.target;
|
|
|
|
scratch.nodes.unmerge(target);
|
|
};
|
|
|
|
cy.on('add', 'node', scratch.onAddNode);
|
|
cy.on('remove', 'node', scratch.onRmNode);
|
|
};
|
|
|
|
var unbindForNodeList = function unbindForNodeList(cy, scratch) {
|
|
cy.removeListener('add', 'node', scratch.onAddNode);
|
|
cy.removeListener('remove', 'node', scratch.onRmNode);
|
|
};
|
|
|
|
var update = function update(cy, rules) {
|
|
var scratch = cy.scratch().automove;
|
|
|
|
rules = rules != null ? rules : scratch.rules;
|
|
|
|
cy.batch(function () {
|
|
// batch for performance
|
|
for (var i = 0; i < rules.length; i++) {
|
|
var rule = rules[i];
|
|
|
|
if (rule.destroyed || !rule.enabled) {
|
|
break;
|
|
} // ignore destroyed rules b/c user may use custom when()
|
|
|
|
var nodes = rule.nodes || scratch.nodes;
|
|
|
|
for (var j = nodes.length - 1; j >= 0; j--) {
|
|
var node = nodes[j];
|
|
|
|
if (node.removed()) {
|
|
// remove from list for perf
|
|
nodes.unmerge(node);
|
|
continue;
|
|
}
|
|
|
|
if (!rule.matches(node)) {
|
|
continue;
|
|
}
|
|
|
|
var pos = node.position();
|
|
var newPos = rule.getNewPos(node);
|
|
var newPosIsDiff = newPos != null && (pos.x !== newPos.x || pos.y !== newPos.y);
|
|
|
|
if (newPosIsDiff) {
|
|
// only update on diff for perf
|
|
node.position(newPos);
|
|
|
|
node.trigger('automove', [rule]);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
var automove = function automove(options) {
|
|
var cy = this;
|
|
|
|
var scratch = cy.scratch().automove = cy.scratch().automove || {
|
|
rules: []
|
|
};
|
|
|
|
if (scratch.rules.length === 0) {
|
|
scratch.nodes = cy.nodes().slice();
|
|
|
|
bindForNodeList(cy, scratch);
|
|
}
|
|
|
|
if (options === 'destroy') {
|
|
scratch.rules.forEach(function (r) {
|
|
r.destroy();
|
|
});
|
|
scratch.rules.splice(0, scratch.rules.length);
|
|
|
|
unbindForNodeList(cy, scratch);
|
|
|
|
return;
|
|
}
|
|
|
|
var rule = addRule(cy, scratch, options);
|
|
|
|
update(cy, [rule]); // do an initial update to make sure the start state is correct
|
|
|
|
return {
|
|
apply: function apply() {
|
|
update(cy, [rule]);
|
|
},
|
|
|
|
disable: function disable() {
|
|
this.toggle(false);
|
|
},
|
|
|
|
enable: function enable() {
|
|
this.toggle(true);
|
|
},
|
|
|
|
enabled: function enabled() {
|
|
return rule.enabled;
|
|
},
|
|
|
|
toggle: function toggle(on) {
|
|
rule.enabled = on !== undefined ? on : !rule.enabled;
|
|
|
|
if (rule.enabled) {
|
|
update(cy, [rule]);
|
|
}
|
|
},
|
|
|
|
destroy: function destroy() {
|
|
var rules = scratch.rules;
|
|
|
|
unbindAllOnRule(rule);
|
|
|
|
rule.destroyed = true;
|
|
|
|
rules.splice(rules.indexOf(rule), 1);
|
|
|
|
if (rules.length === 0) {
|
|
unbindForNodeList(cy, scratch);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
};
|
|
};
|
|
|
|
module.exports = automove;
|
|
|
|
/***/ }),
|
|
/* 1 */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
// Simple, internal Object.assign() polyfill for options objects etc.
|
|
|
|
module.exports = Object.assign != null ? Object.assign.bind(Object) : function (tgt) {
|
|
for (var _len = arguments.length, srcs = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
srcs[_key - 1] = arguments[_key];
|
|
}
|
|
|
|
srcs.forEach(function (src) {
|
|
Object.keys(src).forEach(function (k) {
|
|
return tgt[k] = src[k];
|
|
});
|
|
});
|
|
|
|
return tgt;
|
|
};
|
|
|
|
/***/ }),
|
|
/* 2 */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
/* eslint-disable no-unused-vars */
|
|
var defaults = {
|
|
// specify nodes that should be automoved with one of
|
|
// - a function that returns true for matching nodes
|
|
// - a selector that matches the nodes
|
|
// - a collection of nodes (very good for performance)
|
|
nodesMatching: function nodesMatching(node) {
|
|
return false;
|
|
},
|
|
|
|
// specify how a node's position should be updated with one of
|
|
// - function( node ){ return { x: 1, y: 2 }; } => put the node where the function returns
|
|
// - { x1, y1, x2, y2 } => constrain the node position within the bounding box (in model co-ordinates)
|
|
// - { x1, y1, x2, y2, type: 'inside' } => constrain the node position within the bounding box (in model co-ordinates)
|
|
// - { x1, y1, x2, y2, type: 'outside' } => constrain the node position outside the bounding box (in model co-ordinates)
|
|
// - 'mean' => put the node in the average position of its neighbourhood
|
|
// - 'viewport' => keeps the node body within the viewport
|
|
// - 'drag' => matching nodes are effectively dragged along
|
|
reposition: 'mean',
|
|
|
|
// specify when the repositioning should occur by specifying a function that
|
|
// calls update() when reposition updates should occur
|
|
// - function( update ){ /* ... */ update(); } => a manual function for updating
|
|
// - 'matching' => automatically update on position events for nodesMatching
|
|
// - set efficiently and automatically for
|
|
// - reposition: 'mean'
|
|
// - reposition: { x1, y1, x2, y2 }
|
|
// - reposition: 'viewport'
|
|
// - reposition: 'drag'
|
|
// - default/undefined => on a position event for any node (not as efficient...)
|
|
when: undefined,
|
|
|
|
//
|
|
// customisation options for non-function `reposition` values
|
|
//
|
|
|
|
// `reposition: 'mean'`
|
|
|
|
// specify nodes that should be ignored in the mean calculation
|
|
// - a function that returns true for nodes to be ignored
|
|
// - a selector that matches the nodes to be ignored
|
|
// - a collection of nodes to be ignored (very good for performance)
|
|
meanIgnores: function meanIgnores(node) {
|
|
return false;
|
|
},
|
|
|
|
// specify whether moving a particular `nodesMatching` node causes repositioning
|
|
// - true : the mid node can't be independently moved/dragged
|
|
// - false : the mid node can be independently moved/dragged (useful if you want the mid node to use `reposition: 'drag' in another rule with its neighbourhood`)
|
|
meanOnSelfPosition: function meanOnSelfPosition(node) {
|
|
return true;
|
|
},
|
|
|
|
// `reposition: 'drag'`
|
|
|
|
// specify nodes that when dragged cause the matched nodes to move along (i.e. the master nodes)
|
|
// - a function that returns true for nodes to be listened to for drag events
|
|
// - a selector that matches the nodes to be listened to for drag events
|
|
// - a collection of nodes to be listened to for drag events (very good for performance)
|
|
dragWith: function dragWith(node) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/* eslint-enable */
|
|
|
|
module.exports = defaults;
|
|
|
|
/***/ }),
|
|
/* 3 */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
"use strict";
|
|
|
|
|
|
var automove = __webpack_require__(0);
|
|
|
|
// registers the extension on a cytoscape lib ref
|
|
var register = function register(cytoscape) {
|
|
if (!cytoscape) {
|
|
return;
|
|
} // can't register if cytoscape unspecified
|
|
|
|
cytoscape('core', 'automove', automove); // register with cytoscape.js
|
|
};
|
|
|
|
if (typeof cytoscape !== 'undefined') {
|
|
// expose to global cytoscape (i.e. window.cytoscape)
|
|
register(cytoscape);
|
|
}
|
|
|
|
module.exports = register;
|
|
|
|
/***/ })
|
|
/******/ ]);
|
|
}); |