react-sigma-conglei
Version:
Lightweight but powerful library for drawing network graphs built on top of dunnock/react-sigma
2,082 lines (1,751 loc) • 950 kB
JavaScript
var Sigma =
/******/ (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 = 137);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
/* global window */
var lodash;
if (true) {
try {
lodash = __webpack_require__(110);
} catch (e) {}
}
if (!lodash) {
lodash = window._;
}
module.exports = lodash;
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _ = __webpack_require__(0),
Graph = __webpack_require__(3).Graph;
module.exports = {
addDummyNode: addDummyNode,
simplify: simplify,
asNonCompoundGraph: asNonCompoundGraph,
successorWeights: successorWeights,
predecessorWeights: predecessorWeights,
intersectRect: intersectRect,
buildLayerMatrix: buildLayerMatrix,
normalizeRanks: normalizeRanks,
removeEmptyRanks: removeEmptyRanks,
addBorderNode: addBorderNode,
maxRank: maxRank,
partition: partition,
time: time,
notime: notime
};
/*
* Adds a dummy node to the graph and return v.
*/
function addDummyNode(g, type, attrs, name) {
var v;
do {
v = _.uniqueId(name);
} while (g.hasNode(v));
attrs.dummy = type;
g.setNode(v, attrs);
return v;
}
/*
* Returns a new graph with only simple edges. Handles aggregation of data
* associated with multi-edges.
*/
function simplify(g) {
var simplified = new Graph().setGraph(g.graph());
_.each(g.nodes(), function(v) { simplified.setNode(v, g.node(v)); });
_.each(g.edges(), function(e) {
var simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 },
label = g.edge(e);
simplified.setEdge(e.v, e.w, {
weight: simpleLabel.weight + label.weight,
minlen: Math.max(simpleLabel.minlen, label.minlen)
});
});
return simplified;
}
function asNonCompoundGraph(g) {
var simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
_.each(g.nodes(), function(v) {
if (!g.children(v).length) {
simplified.setNode(v, g.node(v));
}
});
_.each(g.edges(), function(e) {
simplified.setEdge(e, g.edge(e));
});
return simplified;
}
function successorWeights(g) {
var weightMap = _.map(g.nodes(), function(v) {
var sucs = {};
_.each(g.outEdges(v), function(e) {
sucs[e.w] = (sucs[e.w] || 0) + g.edge(e).weight;
});
return sucs;
});
return _.zipObject(g.nodes(), weightMap);
}
function predecessorWeights(g) {
var weightMap = _.map(g.nodes(), function(v) {
var preds = {};
_.each(g.inEdges(v), function(e) {
preds[e.v] = (preds[e.v] || 0) + g.edge(e).weight;
});
return preds;
});
return _.zipObject(g.nodes(), weightMap);
}
/*
* Finds where a line starting at point ({x, y}) would intersect a rectangle
* ({x, y, width, height}) if it were pointing at the rectangle's center.
*/
function intersectRect(rect, point) {
var x = rect.x;
var y = rect.y;
// Rectangle intersection algorithm from:
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
var dx = point.x - x;
var dy = point.y - y;
var w = rect.width / 2;
var h = rect.height / 2;
if (!dx && !dy) {
throw new Error("Not possible to find intersection inside of the rectangle");
}
var sx, sy;
if (Math.abs(dy) * w > Math.abs(dx) * h) {
// Intersection is top or bottom of rect.
if (dy < 0) {
h = -h;
}
sx = h * dx / dy;
sy = h;
} else {
// Intersection is left or right of rect.
if (dx < 0) {
w = -w;
}
sx = w;
sy = w * dy / dx;
}
return { x: x + sx, y: y + sy };
}
/*
* Given a DAG with each node assigned "rank" and "order" properties, this
* function will produce a matrix with the ids of each node.
*/
function buildLayerMatrix(g) {
var layering = _.map(_.range(maxRank(g) + 1), function() { return []; });
_.each(g.nodes(), function(v) {
var node = g.node(v),
rank = node.rank;
if (!_.isUndefined(rank)) {
layering[rank][node.order] = v;
}
});
return layering;
}
/*
* Adjusts the ranks for all nodes in the graph such that all nodes v have
* rank(v) >= 0 and at least one node w has rank(w) = 0.
*/
function normalizeRanks(g) {
var min = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
_.each(g.nodes(), function(v) {
var node = g.node(v);
if (_.has(node, "rank")) {
node.rank -= min;
}
});
}
function removeEmptyRanks(g) {
// Ranks may not start at 0, so we need to offset them
var offset = _.min(_.map(g.nodes(), function(v) { return g.node(v).rank; }));
var layers = [];
_.each(g.nodes(), function(v) {
var rank = g.node(v).rank - offset;
if (!layers[rank]) {
layers[rank] = [];
}
layers[rank].push(v);
});
var delta = 0,
nodeRankFactor = g.graph().nodeRankFactor;
_.each(layers, function(vs, i) {
if (_.isUndefined(vs) && i % nodeRankFactor !== 0) {
--delta;
} else if (delta) {
_.each(vs, function(v) { g.node(v).rank += delta; });
}
});
}
function addBorderNode(g, prefix, rank, order) {
var node = {
width: 0,
height: 0
};
if (arguments.length >= 4) {
node.rank = rank;
node.order = order;
}
return addDummyNode(g, "border", node, prefix);
}
function maxRank(g) {
return _.max(_.map(g.nodes(), function(v) {
var rank = g.node(v).rank;
if (!_.isUndefined(rank)) {
return rank;
}
}));
}
/*
* Partition a collection into two groups: `lhs` and `rhs`. If the supplied
* function returns true for an entry it goes into `lhs`. Otherwise it goes
* into `rhs.
*/
function partition(collection, fn) {
var result = { lhs: [], rhs: [] };
_.each(collection, function(value) {
if (fn(value)) {
result.lhs.push(value);
} else {
result.rhs.push(value);
}
});
return result;
}
/*
* Returns a new function that wraps `fn` with a timer. The wrapper logs the
* time it takes to execute the function.
*/
function time(name, fn) {
var start = _.now();
try {
return fn();
} finally {
console.log(name + " time: " + (_.now() - start) + "ms");
}
}
function notime(name, fn) {
return fn();
}
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
/* global window */
var lodash;
if (true) {
try {
lodash = __webpack_require__(124);
} catch (e) {}
}
if (!lodash) {
lodash = window._;
}
module.exports = lodash;
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
/* global window */
var graphlib;
if (true) {
try {
graphlib = __webpack_require__(111);
} catch (e) {}
}
if (!graphlib) {
graphlib = window.graphlib;
}
module.exports = graphlib;
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _ = __webpack_require__(0);
module.exports = {
longestPath: longestPath,
slack: slack
};
/*
* Initializes ranks for the input graph using the longest path algorithm. This
* algorithm scales well and is fast in practice, it yields rather poor
* solutions. Nodes are pushed to the lowest layer possible, leaving the bottom
* ranks wide and leaving edges longer than necessary. However, due to its
* speed, this algorithm is good for getting an initial ranking that can be fed
* into other algorithms.
*
* This algorithm does not normalize layers because it will be used by other
* algorithms in most cases. If using this algorithm directly, be sure to
* run normalize at the end.
*
* Pre-conditions:
*
* 1. Input graph is a DAG.
* 2. Input graph node labels can be assigned properties.
*
* Post-conditions:
*
* 1. Each node will be assign an (unnormalized) "rank" property.
*/
function longestPath(g) {
var visited = {};
function dfs(v) {
var label = g.node(v);
if (_.has(visited, v)) {
return label.rank;
}
visited[v] = true;
var rank = _.min(_.map(g.outEdges(v), function(e) {
return dfs(e.w) - g.edge(e).minlen;
}));
if (rank === Number.POSITIVE_INFINITY) {
rank = 0;
}
return (label.rank = rank);
}
_.each(g.sources(), dfs);
}
/*
* Returns the amount of slack for the given edge. The slack is defined as the
* difference between the length of the edge and its minimum length.
*/
function slack(g, e) {
return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
}
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _ = __webpack_require__(2);
module.exports = Graph;
var DEFAULT_EDGE_NAME = "\x00",
GRAPH_NODE = "\x00",
EDGE_KEY_DELIM = "\x01";
// Implementation notes:
//
// * Node id query functions should return string ids for the nodes
// * Edge id query functions should return an "edgeObj", edge object, that is
// composed of enough information to uniquely identify an edge: {v, w, name}.
// * Internally we use an "edgeId", a stringified form of the edgeObj, to
// reference edges. This is because we need a performant way to look these
// edges up and, object properties, which have string keys, are the closest
// we're going to get to a performant hashtable in JavaScript.
function Graph(opts) {
this._isDirected = _.has(opts, "directed") ? opts.directed : true;
this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false;
this._isCompound = _.has(opts, "compound") ? opts.compound : false;
// Label for the graph itself
this._label = undefined;
// Defaults to be set when creating a new node
this._defaultNodeLabelFn = _.constant(undefined);
// Defaults to be set when creating a new edge
this._defaultEdgeLabelFn = _.constant(undefined);
// v -> label
this._nodes = {};
if (this._isCompound) {
// v -> parent
this._parent = {};
// v -> children
this._children = {};
this._children[GRAPH_NODE] = {};
}
// v -> edgeObj
this._in = {};
// u -> v -> Number
this._preds = {};
// v -> edgeObj
this._out = {};
// v -> w -> Number
this._sucs = {};
// e -> edgeObj
this._edgeObjs = {};
// e -> label
this._edgeLabels = {};
}
/* Number of nodes in the graph. Should only be changed by the implementation. */
Graph.prototype._nodeCount = 0;
/* Number of edges in the graph. Should only be changed by the implementation. */
Graph.prototype._edgeCount = 0;
/* === Graph functions ========= */
Graph.prototype.isDirected = function() {
return this._isDirected;
};
Graph.prototype.isMultigraph = function() {
return this._isMultigraph;
};
Graph.prototype.isCompound = function() {
return this._isCompound;
};
Graph.prototype.setGraph = function(label) {
this._label = label;
return this;
};
Graph.prototype.graph = function() {
return this._label;
};
/* === Node functions ========== */
Graph.prototype.setDefaultNodeLabel = function(newDefault) {
if (!_.isFunction(newDefault)) {
newDefault = _.constant(newDefault);
}
this._defaultNodeLabelFn = newDefault;
return this;
};
Graph.prototype.nodeCount = function() {
return this._nodeCount;
};
Graph.prototype.nodes = function() {
return _.keys(this._nodes);
};
Graph.prototype.sources = function() {
return _.filter(this.nodes(), function(v) {
return _.isEmpty(this._in[v]);
}, this);
};
Graph.prototype.sinks = function() {
return _.filter(this.nodes(), function(v) {
return _.isEmpty(this._out[v]);
}, this);
};
Graph.prototype.setNodes = function(vs, value) {
var args = arguments;
_.each(vs, function(v) {
if (args.length > 1) {
this.setNode(v, value);
} else {
this.setNode(v);
}
}, this);
return this;
};
Graph.prototype.setNode = function(v, value) {
if (_.has(this._nodes, v)) {
if (arguments.length > 1) {
this._nodes[v] = value;
}
return this;
}
this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v);
if (this._isCompound) {
this._parent[v] = GRAPH_NODE;
this._children[v] = {};
this._children[GRAPH_NODE][v] = true;
}
this._in[v] = {};
this._preds[v] = {};
this._out[v] = {};
this._sucs[v] = {};
++this._nodeCount;
return this;
};
Graph.prototype.node = function(v) {
return this._nodes[v];
};
Graph.prototype.hasNode = function(v) {
return _.has(this._nodes, v);
};
Graph.prototype.removeNode = function(v) {
var self = this;
if (_.has(this._nodes, v)) {
var removeEdge = function(e) { self.removeEdge(self._edgeObjs[e]); };
delete this._nodes[v];
if (this._isCompound) {
this._removeFromParentsChildList(v);
delete this._parent[v];
_.each(this.children(v), function(child) {
this.setParent(child);
}, this);
delete this._children[v];
}
_.each(_.keys(this._in[v]), removeEdge);
delete this._in[v];
delete this._preds[v];
_.each(_.keys(this._out[v]), removeEdge);
delete this._out[v];
delete this._sucs[v];
--this._nodeCount;
}
return this;
};
Graph.prototype.setParent = function(v, parent) {
if (!this._isCompound) {
throw new Error("Cannot set parent in a non-compound graph");
}
if (_.isUndefined(parent)) {
parent = GRAPH_NODE;
} else {
// Coerce parent to string
parent += "";
for (var ancestor = parent;
!_.isUndefined(ancestor);
ancestor = this.parent(ancestor)) {
if (ancestor === v) {
throw new Error("Setting " + parent+ " as parent of " + v +
" would create create a cycle");
}
}
this.setNode(parent);
}
this.setNode(v);
this._removeFromParentsChildList(v);
this._parent[v] = parent;
this._children[parent][v] = true;
return this;
};
Graph.prototype._removeFromParentsChildList = function(v) {
delete this._children[this._parent[v]][v];
};
Graph.prototype.parent = function(v) {
if (this._isCompound) {
var parent = this._parent[v];
if (parent !== GRAPH_NODE) {
return parent;
}
}
};
Graph.prototype.children = function(v) {
if (_.isUndefined(v)) {
v = GRAPH_NODE;
}
if (this._isCompound) {
var children = this._children[v];
if (children) {
return _.keys(children);
}
} else if (v === GRAPH_NODE) {
return this.nodes();
} else if (this.hasNode(v)) {
return [];
}
};
Graph.prototype.predecessors = function(v) {
var predsV = this._preds[v];
if (predsV) {
return _.keys(predsV);
}
};
Graph.prototype.successors = function(v) {
var sucsV = this._sucs[v];
if (sucsV) {
return _.keys(sucsV);
}
};
Graph.prototype.neighbors = function(v) {
var preds = this.predecessors(v);
if (preds) {
return _.union(preds, this.successors(v));
}
};
Graph.prototype.filterNodes = function(filter) {
var copy = new this.constructor({
directed: this._isDirected,
multigraph: this._isMultigraph,
compound: this._isCompound
});
copy.setGraph(this.graph());
_.each(this._nodes, function(value, v) {
if (filter(v)) {
copy.setNode(v, value);
}
}, this);
_.each(this._edgeObjs, function(e) {
if (copy.hasNode(e.v) && copy.hasNode(e.w)) {
copy.setEdge(e, this.edge(e));
}
}, this);
var self = this;
var parents = {};
function findParent(v) {
var parent = self.parent(v);
if (parent === undefined || copy.hasNode(parent)) {
parents[v] = parent;
return parent;
} else if (parent in parents) {
return parents[parent];
} else {
return findParent(parent);
}
}
if (this._isCompound) {
_.each(copy.nodes(), function(v) {
copy.setParent(v, findParent(v));
});
}
return copy;
};
/* === Edge functions ========== */
Graph.prototype.setDefaultEdgeLabel = function(newDefault) {
if (!_.isFunction(newDefault)) {
newDefault = _.constant(newDefault);
}
this._defaultEdgeLabelFn = newDefault;
return this;
};
Graph.prototype.edgeCount = function() {
return this._edgeCount;
};
Graph.prototype.edges = function() {
return _.values(this._edgeObjs);
};
Graph.prototype.setPath = function(vs, value) {
var self = this,
args = arguments;
_.reduce(vs, function(v, w) {
if (args.length > 1) {
self.setEdge(v, w, value);
} else {
self.setEdge(v, w);
}
return w;
});
return this;
};
/*
* setEdge(v, w, [value, [name]])
* setEdge({ v, w, [name] }, [value])
*/
Graph.prototype.setEdge = function() {
var v, w, name, value,
valueSpecified = false,
arg0 = arguments[0];
if (typeof arg0 === "object" && arg0 !== null && "v" in arg0) {
v = arg0.v;
w = arg0.w;
name = arg0.name;
if (arguments.length === 2) {
value = arguments[1];
valueSpecified = true;
}
} else {
v = arg0;
w = arguments[1];
name = arguments[3];
if (arguments.length > 2) {
value = arguments[2];
valueSpecified = true;
}
}
v = "" + v;
w = "" + w;
if (!_.isUndefined(name)) {
name = "" + name;
}
var e = edgeArgsToId(this._isDirected, v, w, name);
if (_.has(this._edgeLabels, e)) {
if (valueSpecified) {
this._edgeLabels[e] = value;
}
return this;
}
if (!_.isUndefined(name) && !this._isMultigraph) {
throw new Error("Cannot set a named edge when isMultigraph = false");
}
// It didn't exist, so we need to create it.
// First ensure the nodes exist.
this.setNode(v);
this.setNode(w);
this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name);
var edgeObj = edgeArgsToObj(this._isDirected, v, w, name);
// Ensure we add undirected edges in a consistent way.
v = edgeObj.v;
w = edgeObj.w;
Object.freeze(edgeObj);
this._edgeObjs[e] = edgeObj;
incrementOrInitEntry(this._preds[w], v);
incrementOrInitEntry(this._sucs[v], w);
this._in[w][e] = edgeObj;
this._out[v][e] = edgeObj;
this._edgeCount++;
return this;
};
Graph.prototype.edge = function(v, w, name) {
var e = (arguments.length === 1
? edgeObjToId(this._isDirected, arguments[0])
: edgeArgsToId(this._isDirected, v, w, name));
return this._edgeLabels[e];
};
Graph.prototype.hasEdge = function(v, w, name) {
var e = (arguments.length === 1
? edgeObjToId(this._isDirected, arguments[0])
: edgeArgsToId(this._isDirected, v, w, name));
return _.has(this._edgeLabels, e);
};
Graph.prototype.removeEdge = function(v, w, name) {
var e = (arguments.length === 1
? edgeObjToId(this._isDirected, arguments[0])
: edgeArgsToId(this._isDirected, v, w, name)),
edge = this._edgeObjs[e];
if (edge) {
v = edge.v;
w = edge.w;
delete this._edgeLabels[e];
delete this._edgeObjs[e];
decrementOrRemoveEntry(this._preds[w], v);
decrementOrRemoveEntry(this._sucs[v], w);
delete this._in[w][e];
delete this._out[v][e];
this._edgeCount--;
}
return this;
};
Graph.prototype.inEdges = function(v, u) {
var inV = this._in[v];
if (inV) {
var edges = _.values(inV);
if (!u) {
return edges;
}
return _.filter(edges, function(edge) { return edge.v === u; });
}
};
Graph.prototype.outEdges = function(v, w) {
var outV = this._out[v];
if (outV) {
var edges = _.values(outV);
if (!w) {
return edges;
}
return _.filter(edges, function(edge) { return edge.w === w; });
}
};
Graph.prototype.nodeEdges = function(v, w) {
var inEdges = this.inEdges(v, w);
if (inEdges) {
return inEdges.concat(this.outEdges(v, w));
}
};
function incrementOrInitEntry(map, k) {
if (map[k]) {
map[k]++;
} else {
map[k] = 1;
}
}
function decrementOrRemoveEntry(map, k) {
if (!--map[k]) { delete map[k]; }
}
function edgeArgsToId(isDirected, v_, w_, name) {
var v = "" + v_;
var w = "" + w_;
if (!isDirected && v > w) {
var tmp = v;
v = w;
w = tmp;
}
return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM +
(_.isUndefined(name) ? DEFAULT_EDGE_NAME : name);
}
function edgeArgsToObj(isDirected, v_, w_, name) {
var v = "" + v_;
var w = "" + w_;
if (!isDirected && v > w) {
var tmp = v;
v = w;
w = tmp;
}
var edgeObj = { v: v, w: w };
if (name) {
edgeObj.name = name;
}
return edgeObj;
}
function edgeObjToId(isDirected, edgeObj) {
return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
}
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _ = __webpack_require__(0),
Graph = __webpack_require__(3).Graph,
slack = __webpack_require__(4).slack;
module.exports = feasibleTree;
/*
* Constructs a spanning tree with tight edges and adjusted the input node's
* ranks to achieve this. A tight edge is one that is has a length that matches
* its "minlen" attribute.
*
* The basic structure for this function is derived from Gansner, et al., "A
* Technique for Drawing Directed Graphs."
*
* Pre-conditions:
*
* 1. Graph must be a DAG.
* 2. Graph must be connected.
* 3. Graph must have at least one node.
* 5. Graph nodes must have been previously assigned a "rank" property that
* respects the "minlen" property of incident edges.
* 6. Graph edges must have a "minlen" property.
*
* Post-conditions:
*
* - Graph nodes will have their rank adjusted to ensure that all edges are
* tight.
*
* Returns a tree (undirected graph) that is constructed using only "tight"
* edges.
*/
function feasibleTree(g) {
var t = new Graph({ directed: false });
// Choose arbitrary node from which to start our tree
var start = g.nodes()[0],
size = g.nodeCount();
t.setNode(start, {});
var edge, delta;
while (tightTree(t, g) < size) {
edge = findMinSlackEdge(t, g);
delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge);
shiftRanks(t, g, delta);
}
return t;
}
/*
* Finds a maximal tree of tight edges and returns the number of nodes in the
* tree.
*/
function tightTree(t, g) {
function dfs(v) {
_.each(g.nodeEdges(v), function(e) {
var edgeV = e.v,
w = (v === edgeV) ? e.w : edgeV;
if (!t.hasNode(w) && !slack(g, e)) {
t.setNode(w, {});
t.setEdge(v, w, {});
dfs(w);
}
});
}
_.each(t.nodes(), dfs);
return t.nodeCount();
}
/*
* Finds the edge with the smallest slack that is incident on tree and returns
* it.
*/
function findMinSlackEdge(t, g) {
return _.min(g.edges(), function(e) {
if (t.hasNode(e.v) !== t.hasNode(e.w)) {
return slack(g, e);
}
});
}
function shiftRanks(t, g, delta) {
_.each(t.nodes(), function(v) {
g.node(v).rank += delta;
});
}
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
var _ = __webpack_require__(2);
module.exports = dfs;
/*
* A helper that preforms a pre- or post-order traversal on the input graph
* and returns the nodes in the order they were visited. This algorithm treats
* the input as undirected.
*
* Order must be one of "pre" or "post".
*/
function dfs(g, vs, order) {
if (!_.isArray(vs)) {
vs = [vs];
}
var acc = [],
visited = {};
_.each(vs, function(v) {
if (!g.hasNode(v)) {
throw new Error("Graph does not have node: " + v);
}
doDfs(g, v, order === "post", visited, acc);
});
return acc;
}
function doDfs(g, v, postorder, visited, acc) {
if (!_.has(visited, v)) {
visited[v] = true;
if (!postorder) { acc.push(v); }
_.each(g.neighbors(v), function(w) {
doDfs(g, w, postorder, visited, acc);
});
if (postorder) { acc.push(v); }
}
}
/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {
var _ = __webpack_require__(2),
PriorityQueue = __webpack_require__(11);
module.exports = dijkstra;
var DEFAULT_WEIGHT_FUNC = _.constant(1);
function dijkstra(g, source, weightFn, edgeFn) {
return runDijkstra(g, String(source),
weightFn || DEFAULT_WEIGHT_FUNC,
edgeFn || function(v) { return g.outEdges(v); });
}
function runDijkstra(g, source, weightFn, edgeFn) {
var results = {},
pq = new PriorityQueue(),
v, vEntry;
var updateNeighbors = function(edge) {
var w = edge.v !== v ? edge.v : edge.w,
wEntry = results[w],
weight = weightFn(edge),
distance = vEntry.distance + weight;
if (weight < 0) {
throw new Error("dijkstra does not allow negative edge weights. " +
"Bad edge: " + edge + " Weight: " + weight);
}
if (distance < wEntry.distance) {
wEntry.distance = distance;
wEntry.predecessor = v;
pq.decrease(w, distance);
}
};
g.nodes().forEach(function(v) {
var distance = v === source ? 0 : Number.POSITIVE_INFINITY;
results[v] = { distance: distance };
pq.add(v, distance);
});
while (pq.size() > 0) {
v = pq.removeMin();
vEntry = results[v];
if (vEntry.distance === Number.POSITIVE_INFINITY) {
break;
}
edgeFn(v).forEach(updateNeighbors);
}
return results;
}
/***/ }),
/* 9 */
/***/ (function(module, exports, __webpack_require__) {
var _ = __webpack_require__(2);
module.exports = tarjan;
function tarjan(g) {
var index = 0,
stack = [],
visited = {}, // node id -> { onStack, lowlink, index }
results = [];
function dfs(v) {
var entry = visited[v] = {
onStack: true,
lowlink: index,
index: index++
};
stack.push(v);
g.successors(v).forEach(function(w) {
if (!_.has(visited, w)) {
dfs(w);
entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
} else if (visited[w].onStack) {
entry.lowlink = Math.min(entry.lowlink, visited[w].index);
}
});
if (entry.lowlink === entry.index) {
var cmpt = [],
w;
do {
w = stack.pop();
visited[w].onStack = false;
cmpt.push(w);
} while (v !== w);
results.push(cmpt);
}
}
g.nodes().forEach(function(v) {
if (!_.has(visited, v)) {
dfs(v);
}
});
return results;
}
/***/ }),
/* 10 */
/***/ (function(module, exports, __webpack_require__) {
var _ = __webpack_require__(2);
module.exports = topsort;
topsort.CycleException = CycleException;
function topsort(g) {
var visited = {},
stack = {},
results = [];
function visit(node) {
if (_.has(stack, node)) {
throw new CycleException();
}
if (!_.has(visited, node)) {
stack[node] = true;
visited[node] = true;
_.each(g.predecessors(node), visit);
delete stack[node];
results.push(node);
}
}
_.each(g.sinks(), visit);
if (_.size(visited) !== g.nodeCount()) {
throw new CycleException();
}
return results;
}
function CycleException() {}
/***/ }),
/* 11 */
/***/ (function(module, exports, __webpack_require__) {
var _ = __webpack_require__(2);
module.exports = PriorityQueue;
/**
* A min-priority queue data structure. This algorithm is derived from Cormen,
* et al., "Introduction to Algorithms". The basic idea of a min-priority
* queue is that you can efficiently (in O(1) time) get the smallest key in
* the queue. Adding and removing elements takes O(log n) time. A key can
* have its priority decreased in O(log n) time.
*/
function PriorityQueue() {
this._arr = [];
this._keyIndices = {};
}
/**
* Returns the number of elements in the queue. Takes `O(1)` time.
*/
PriorityQueue.prototype.size = function() {
return this._arr.length;
};
/**
* Returns the keys that are in the queue. Takes `O(n)` time.
*/
PriorityQueue.prototype.keys = function() {
return this._arr.map(function(x) { return x.key; });
};
/**
* Returns `true` if **key** is in the queue and `false` if not.
*/
PriorityQueue.prototype.has = function(key) {
return _.has(this._keyIndices, key);
};
/**
* Returns the priority for **key**. If **key** is not present in the queue
* then this function returns `undefined`. Takes `O(1)` time.
*
* @param {Object} key
*/
PriorityQueue.prototype.priority = function(key) {
var index = this._keyIndices[key];
if (index !== undefined) {
return this._arr[index].priority;
}
};
/**
* Returns the key for the minimum element in this queue. If the queue is
* empty this function throws an Error. Takes `O(1)` time.
*/
PriorityQueue.prototype.min = function() {
if (this.size() === 0) {
throw new Error("Queue underflow");
}
return this._arr[0].key;
};
/**
* Inserts a new key into the priority queue. If the key already exists in
* the queue this function returns `false`; otherwise it will return `true`.
* Takes `O(n)` time.
*
* @param {Object} key the key to add
* @param {Number} priority the initial priority for the key
*/
PriorityQueue.prototype.add = function(key, priority) {
var keyIndices = this._keyIndices;
key = String(key);
if (!_.has(keyIndices, key)) {
var arr = this._arr;
var index = arr.length;
keyIndices[key] = index;
arr.push({key: key, priority: priority});
this._decrease(index);
return true;
}
return false;
};
/**
* Removes and returns the smallest key in the queue. Takes `O(log n)` time.
*/
PriorityQueue.prototype.removeMin = function() {
this._swap(0, this._arr.length - 1);
var min = this._arr.pop();
delete this._keyIndices[min.key];
this._heapify(0);
return min.key;
};
/**
* Decreases the priority for **key** to **priority**. If the new priority is
* greater than the previous priority, this function will throw an Error.
*
* @param {Object} key the key for which to raise priority
* @param {Number} priority the new priority for the key
*/
PriorityQueue.prototype.decrease = function(key, priority) {
var index = this._keyIndices[key];
if (priority > this._arr[index].priority) {
throw new Error("New priority is greater than current priority. " +
"Key: " + key + " Old: " + this._arr[index].priority + " New: " + priority);
}
this._arr[index].priority = priority;
this._decrease(index);
};
PriorityQueue.prototype._heapify = function(i) {
var arr = this._arr;
var l = 2 * i,
r = l + 1,
largest = i;
if (l < arr.length) {
largest = arr[l].priority < arr[largest].priority ? l : largest;
if (r < arr.length) {
largest = arr[r].priority < arr[largest].priority ? r : largest;
}
if (largest !== i) {
this._swap(i, largest);
this._heapify(largest);
}
}
};
PriorityQueue.prototype._decrease = function(index) {
var arr = this._arr;
var priority = arr[index].priority;
var parent;
while (index !== 0) {
parent = index >> 1;
if (arr[parent].priority < priority) {
break;
}
this._swap(index, parent);
index = parent;
}
};
PriorityQueue.prototype._swap = function(i, j) {
var arr = this._arr;
var keyIndices = this._keyIndices;
var origArrI = arr[i];
var origArrJ = arr[j];
arr[i] = origArrJ;
arr[j] = origArrI;
keyIndices[origArrJ.key] = i;
keyIndices[origArrI.key] = j;
};
/***/ }),
/* 12 */
/***/ (function(module, exports) {
var g;
// This works in non-strict mode
g = (function() {
return this;
})();
try {
// This works if eval is allowed (see CSP)
g = g || Function("return this")() || (1,eval)("this");
} catch(e) {
// This works if the window reference is available
if(typeof window === "object")
g = window;
}
// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}
module.exports = g;
/***/ }),
/* 13 */
/***/ (function(module, exports) {
module.exports = function(module) {
if(!module.webpackPolyfill) {
module.deprecate = function() {};
module.paths = [];
// module.parent = undefined by default
if(!module.children) module.children = [];
Object.defineProperty(module, "loaded", {
enumerable: true,
get: function() {
return module.l;
}
});
Object.defineProperty(module, "id", {
enumerable: true,
get: function() {
return module.i;
}
});
module.webpackPolyfill = 1;
}
return module;
};
/***/ }),
/* 14 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_dagre__ = __webpack_require__(85);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_dagre___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_dagre__);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_sigma_react_plugins_sigma_layouts_dagre_sigma_layout_dagre_js__ = __webpack_require__(126);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_sigma_react_plugins_sigma_layouts_dagre_sigma_layout_dagre_js___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_sigma_react_plugins_sigma_layouts_dagre_sigma_layout_dagre_js__);
window.dagre = __WEBPACK_IMPORTED_MODULE_0_dagre___default.a;
/***/ }),
/* 15 */,
/* 16 */,
/* 17 */,
/* 18 */,
/* 19 */,
/* 20 */,
/* 21 */,
/* 22 */,
/* 23 */,
/* 24 */,
/* 25 */,
/* 26 */,
/* 27 */,
/* 28 */,
/* 29 */,
/* 30 */,
/* 31 */,
/* 32 */,
/* 33 */,
/* 34 */,
/* 35 */,
/* 36 */,
/* 37 */,
/* 38 */,
/* 39 */,
/* 40 */,
/* 41 */,
/* 42 */,
/* 43 */,
/* 44 */,
/* 45 */,
/* 46 */,
/* 47 */,
/* 48 */,
/* 49 */,
/* 50 */,
/* 51 */,
/* 52 */,
/* 53 */,
/* 54 */,
/* 55 */,
/* 56 */,
/* 57 */,
/* 58 */,
/* 59 */,
/* 60 */,
/* 61 */,
/* 62 */,
/* 63 */,
/* 64 */,
/* 65 */,
/* 66 */,
/* 67 */,
/* 68 */,
/* 69 */,
/* 70 */,
/* 71 */,
/* 72 */,
/* 73 */,
/* 74 */,
/* 75 */,
/* 76 */,
/* 77 */,
/* 78 */,
/* 79 */,
/* 80 */,
/* 81 */,
/* 82 */,
/* 83 */,
/* 84 */,
/* 85 */
/***/ (function(module, exports, __webpack_require__) {
/*
Copyright (c) 2012-2014 Chris Pettitt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
module.exports = {
graphlib: __webpack_require__(3),
layout: __webpack_require__(92),
debug: __webpack_require__(90),
util: {
time: __webpack_require__(1).time,
notime: __webpack_require__(1).notime
},
version: __webpack_require__(109)
};
/***/ }),
/* 86 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _ = __webpack_require__(0),
greedyFAS = __webpack_require__(91);
module.exports = {
run: run,
undo: undo
};
function run(g) {
var fas = (g.graph().acyclicer === "greedy"
? greedyFAS(g, weightFn(g))
: dfsFAS(g));
_.each(fas, function(e) {
var label = g.edge(e);
g.removeEdge(e);
label.forwardName = e.name;
label.reversed = true;
g.setEdge(e.w, e.v, label, _.uniqueId("rev"));
});
function weightFn(g) {
return function(e) {
return g.edge(e).weight;
};
}
}
function dfsFAS(g) {
var fas = [],
stack = {},
visited = {};
function dfs(v) {
if (_.has(visited, v)) {
return;
}
visited[v] = true;
stack[v] = true;
_.each(g.outEdges(v), function(e) {
if (_.has(stack, e.w)) {
fas.push(e);
} else {
dfs(e.w);
}
});
delete stack[v];
}
_.each(g.nodes(), dfs);
return fas;
}
function undo(g) {
_.each(g.edges(), function(e) {
var label = g.edge(e);
if (label.reversed) {
g.removeEdge(e);
var forwardName = label.forwardName;
delete label.reversed;
delete label.forwardName;
g.setEdge(e.w, e.v, label, forwardName);
}
});
}
/***/ }),
/* 87 */
/***/ (function(module, exports, __webpack_require__) {
var _ = __webpack_require__(0),
util = __webpack_require__(1);
module.exports = addBorderSegments;
function addBorderSegments(g) {
function dfs(v) {
var children = g.children(v),
node = g.node(v);
if (children.length) {
_.each(children, dfs);
}
if (_.has(node, "minRank")) {
node.borderLeft = [];
node.borderRight = [];
for (var rank = node.minRank, maxRank = node.maxRank + 1;
rank < maxRank;
++rank) {
addBorderNode(g, "borderLeft", "_bl", v, node, rank);
addBorderNode(g, "borderRight", "_br", v, node, rank);
}
}
}
_.each(g.children(), dfs);
}
function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
var label = { width: 0, height: 0, rank: rank, borderType: prop },
prev = sgNode[prop][rank - 1],
curr = util.addDummyNode(g, "border", label, prefix);
sgNode[prop][rank] = curr;
g.setParent(curr, sg);
if (prev) {
g.setEdge(prev, curr, { weight: 1 });
}
}
/***/ }),
/* 88 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _ = __webpack_require__(0);
module.exports = {
adjust: adjust,
undo: undo
};
function adjust(g) {
var rankDir = g.graph().rankdir.toLowerCase();
if (rankDir === "lr" || rankDir === "rl") {
swapWidthHeight(g);
}
}
function undo(g) {
var rankDir = g.graph().rankdir.toLowerCase();
if (rankDir === "bt" || rankDir === "rl") {
reverseY(g);
}
if (rankDir === "lr" || rankDir === "rl") {
swapXY(g);
swapWidthHeight(g);
}
}
function swapWidthHeight(g) {
_.each(g.nodes(), function(v) { swapWidthHeightOne(g.node(v)); });
_.each(g.edges(), function(e) { swapWidthHeightOne(g.edge(e)); });
}
function swapWidthHeightOne(attrs) {
var w = attrs.width;
attrs.width = attrs.height;
attrs.height = w;
}
function reverseY(g) {
_.each(g.nodes(), function(v) { reverseYOne(g.node(v)); });
_.each(g.edges(), function(e) {
var edge = g.edge(e);
_.each(edge.points, reverseYOne);
if (_.has(edge, "y")) {
reverseYOne(edge);
}
});
}
function reverseYOne(attrs) {
attrs.y = -attrs.y;
}
function swapXY(g) {
_.each(g.nodes(), function(v) { swapXYOne(g.node(v)); });
_.each(g.edges(), function(e) {
var edge = g.edge(e);
_.each(edge.points, swapXYOne);
if (_.has(edge, "x")) {
swapXYOne(edge);
}
});
}
function swapXYOne(attrs) {
var x = attrs.x;
attrs.x = attrs.y;
attrs.y = x;
}
/***/ }),
/* 89 */
/***/ (function(module, exports) {
/*
* Simple doubly linked list implementation derived from Cormen, et al.,
* "Introduction to Algorithms".
*/
module.exports = List;
function List() {
var sentinel = {};
sentinel._next = sentinel._prev = sentinel;
this._sentinel = sentinel;
}
List.prototype.dequeue = function() {
var sentinel = this._sentinel,
entry = sentinel._prev;
if (entry !== sentinel) {
unlink(entry);
return entry;
}
};
List.prototype.enqueue = function(entry) {
var sentinel = this._sentinel;
if (entry._prev && entry._next) {
unlink(entry);
}
entry._next = sentinel._next;
sentinel._next._prev = entry;
sentinel._next = entry;
entry._prev = sentinel;
};
List.prototype.toString = function() {
var strs = [],
sentinel = this._sentinel,
curr = sentinel._prev;
while (curr !== sentinel) {
strs.push(JSON.stringify(curr, filterOutLinks));
curr = curr._prev;
}
return "[" + strs.join(", ") + "]";
};
function unlink(entry) {
entry._prev._next = entry._next;
entry._next._prev = entry._prev;
delete entry._next;
delete entry._prev;
}
function filterOutLinks(k, v) {
if (k !== "_next" && k !== "_prev") {
return v;
}
}
/***/ }),
/* 90 */
/***/ (function(module, exports, __webpack_require__) {
var _ = __webpack_require__(0),
util = __webpack_require__(1),
Graph = __webpack_require__(3).Graph;
module.exports = {
debugOrdering: debugOrdering
};
/* istanbul ignore next */
function debugOrdering(g) {
var layerMatrix = util.buildLayerMatrix(g);
var h = new Graph({ compound: true, multigraph: true }).setGraph({});
_.each(g.nodes(), function(v) {
h.setNode(v, { label: v });
h.setParent(v, "layer" + g.node(v).rank);
});
_.each(g.edges(), function(e) {
h.setEdge(e.v, e.w, {}, e.name);
});
_.each(layerMatrix, function(layer, i) {
var layerV = "layer" + i;
h.setNode(layerV, { rank: "same" });
_.reduce(layer, function(u, v) {
h.setEdge(u, v, { style: "invis" });
return v;
});
});
return h;
}
/***/ }),
/* 91 */
/***/ (function(module, exports, __webpack_require__) {
var _ = __webpack_require__(0),
Graph = __webpack_require__(3).Graph,
List = __webpack_require__(89);
/*
* A greedy heuristic for finding a feedback arc set for a graph. A feedback
* arc set is a set of edges that can be removed to make a graph acyclic.
* The algorithm comes from: P. Eades, X. Lin, and W. F. Smyth, "A fast and
* effective heuristic for the feedback arc set problem." This implementation
* adjusts that from the paper to allow for weighted edges.
*/
module.exports = greedyFAS;
var DEFAULT_WEIGHT_FN = _.constant(1);
function greedyFAS(g, weightFn) {
if (g.nodeCount() <= 1) {
return [];
}
var state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
var results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
// Expand multi-edges
return _.flatten(_.map(results, function(e) {
return g.outEdges(e.v, e.w);
}), true);
}
function doGreedyFAS(g, buckets, zeroIdx) {
var results = [],
sources = buckets[buckets.length - 1],
sinks = buckets[0];
var entry;
while (g.nodeCount()) {
while ((entry = sinks.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
while ((entry = sources.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
if (g.nodeCount()) {
for (var i = buckets.length - 2; i > 0; --i) {
entry = buckets[i].dequeue();
if (entry) {
results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
break;
}
}
}
}
return results;
}
function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
var results = collectPredecessors ? [] : undefined;
_.each(g.inEdges(entry.v), function(edge) {
var weight = g.edge(edge),
uEntry = g.node(edge.v);
if (collectPredecessors) {
results.push({ v: edge.v, w: edge.w });
}
uEntry.out -= weight;
assignBucket(buckets, zeroIdx, uEntry);
});
_.each(g.outEdges(entry.v), function(edge) {
var weight = g.edge(edge),
w = edge.w,
wEntry = g.node(w);
wEntry["in"] -= weight;
assignBucket(buckets, zeroIdx, wEntry);
});
g.removeNode(entry.v);
return results;
}
function buildState(g, weightFn) {
var fasGraph = new Graph(),
maxIn = 0,
maxOut = 0;
_.each(g.nodes(), function(v) {
fasGraph.setNode(v, { v: v, "in": 0, out: 0 });
});
// Aggregate weights on nodes, but also sum the weights across multi-edges
// into a single edge for the fasGraph.
_.each(g.edges(), function(e) {
var prevWeight = fasGraph.edge(e.v, e.w) || 0,
weight = weightFn(e),
edgeWeight = prevWeight + weight;
fasGraph.setEdge(e.v, e.w, edgeWeight);
maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight);
maxIn = Math.max(maxIn, fasGraph.node(e.w)["in"] += weight);
});
var buckets = _.range(maxOut + maxIn + 3).map(function() { return new List(); });
var zeroIdx = maxIn + 1;
_.each(fasGraph.nodes(), function(v) {
assignBucket(buckets, zeroIdx, fasGraph.node(v));
});
return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx };
}
function assignBucket(buckets, zeroIdx, entry) {
if (!entry.out) {
buckets[0].enqueue(entry);
} else if (!entry["in"]) {
buckets[buckets.length - 1].enqueue(entry);
} else {
buckets[entry.out - entry["in"] + zeroIdx].enqueue(entry);
}
}
/***/ }),
/* 92 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _ = __webpack_require__(0),
acyclic = __webpack_require__(86),
normalize = __webpack_require__(94),
rank = __webpack_require__(107),
normalizeRanks = __webpack_require__(1).normalizeRanks,
parentDummyChains = __webpack_require__(104),
removeEmptyRanks = __webpack_require__(1).removeEmptyRanks,
nestingGraph = __webpack_require__(93),
addBorderSegments = __webpack_require__(87),
coordinateSystem = __webpack_require__(88),
order = __webpack_require__(99),
position = __webpack_require__(106),
util = __webpack_require__(1),
Graph = __webpack_require__(3).Graph;
module.exports = layout;
function layout(g, opts) {
var time = opts && opts.debugTiming ? util.time : util.notime;
time("layout", function() {
var layoutGraph = time(" buildLayoutGraph",
function() { return buildLayoutGraph(g); });
time(" runLayout", function() { runLayout(layoutGraph, time); });
time(" updateInputGraph", function() { updateInputGraph(g, layoutGraph); });
});
}
function runLayout(g, time) {
time(" makeSpaceForEdgeLabels", function() { makeSpaceForEdgeLabels(g); });
time(" removeSelfEdges", function() { removeSelfEdges(g); });
time(" acyclic", function() { acyclic.run(g); });
time(" nestingGraph.run", function() { nestingGraph.run(g); });
time(" rank", function() { rank(util.asNonCompoundGraph(g)); });
time(" injectEdgeLabelProxies", function() { injectEdgeLabelProxies(g); });
time(" removeEmptyRanks", function() { removeEmptyRanks(g); });
time(" nestingGraph.cleanup", function() { nestingGraph.cleanup(g); });
time(" normalizeRanks", function() { normalizeRanks(g); });
time(" assignRankMinMax", function() { assignRankMinMax(g); });
time(" removeEdgeLabelProxies", function() { removeEdgeLabelProxies(g); });
time(" normalize.run", function() { normalize.run(g); });
time(" parentDummyChains", function() { parentDummyChains(g); });
time(" addBorderSegments", function() { addBorderSegments(g); });
time(" order", function() { order(g); });
time(" insertSelfEdges", function() { insertSelfEdges(g); });
time(" adjustCoordinateSystem", function() { coordinateSystem.adjust(g); });
time(" position", function() { position(g); });
time(" positionSelfEdges", function() { positionSelfEdges(g); });
time(" removeBorderNodes", function() { removeBorderNodes(g); });
time(" normalize.undo", function() { normalize.undo(g); });
time(" fixupEdgeLabelCoords", function() { fixupEdgeLabelCoords(g); });
time(" undoCoordinateSystem", function() { coordinateSystem.undo(g); });
time(" translateGraph", function() { translateGraph(g); });
time(" assignNodeIntersects", f