sigmajs-react
Version:
Lightweight but powerful library for drawing network graphs built on top of SigmaJS
1,959 lines (1,661 loc) • 951 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__(119);
} 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__(133);
} 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__(120);
} 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 */,
/* 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 */
/***/ (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__(94);
/* 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__(81);
/* 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;
/***/ }),
/* 80 */,
/* 81 */
/***/ (function(module, exports) {
/*** IMPORTS FROM imports-loader ***/
(function () {
;(function (undefined) {
'use strict';
if (typeof sigma === 'undefined') throw new Error('sigma is not declared');
if (typeof dagre === 'undefined' || typeof dagre.graphlib === 'undefined') console.warn('to use the dagre plugin, ' + 'you have to include dagre and dagre.graphlib');
// Initialize package:
sigma.utils.pkg('sigma.layouts.dagre');
/**
* Sigma Dagre layout
* ===============================
*
* Require https://github.com/cpettitt/dagre
* Author: Sébastien Heymann @ Linkurious
* Version: 0.1
*/
// see https://github.com/cpettitt/dagre/wiki#configuring-the-layout
var settings = {
directed: true, // take edge direction into account
multigraph: true, // allows multiple edges between the same pair of nodes
compound: false, //
// dagre algo options
rankDir: 'TB' // Direction for rank nodes. Can be TB, BT, LR, or RL,
// where T = top, B = bottom, L = left, and R = right.
};
var _instance = {};
/**
* Event emitter Object
* ------------------
*/
var _eventEmitter = {};
function getBoundaries(nodes, prefix) {
var i,
l,
prefix = prefix || '',
sizeMax = -Infinity,
minX = Infinity,
minY = Infinity,
maxX = -Infinity,
maxY = -Infinity;
for (i = 0, l = nodes.length; i < l; i++) {
sizeMax = Math.max(nodes[i][prefix + 'size'], sizeMax);
maxX = Math.max(nodes[i][prefix + 'x'], maxX);
minX = Math.min(nodes[i][prefix + 'x'], minX);
maxY = Math.max(nodes[i][prefix + 'y'], maxY);
minY = Math.min(nodes[i][prefix + 'y'], minY);
}
sizeMax = sizeMax || 1;
return {
sizeMax: sizeMax,
minX: minX,
minY: minY,
maxX: maxX,
maxY: maxY
};
};
function scaleRange(value, baseMin, baseMax, limitMin, limitMax) {
return (limitMax - limitMin) * (value - baseMin) / (baseMax - baseMin) + limitMin;
};
function rescalePosition(point, baseBox, limitBox) {
return {
x: scaleRange(point.x, baseBox.minX, baseBox.maxX, limitBox.minX, limitBox.maxX),
y: scaleRange(point.y, baseBox.minY, baseBox.maxY, limitBox.minY, limitBox.maxY)
};
};
/**
* Dagre Object
* ------------------
*/
function dagreLayout() {
if (typeof dagre === 'undefined') throw new Error('dagre is not declared');
if (typeof dagre.graphlib === 'undefined') throw new Error('dagre.graphlib is not declared');
var self = this,
dg;
this.init = function (sigInst, options) {
options = options || {};
if (options.nodes) {
this.nodes = options.nodes;
delete options.nodes;
}
if (options.boundingBox) {
this.boundingBox = options.boundingBox;
delete options.boundingBox;
}
// Properties
this.sigInst = sigInst;
this.config = sigma.utils.extend(options, settings);
this.easing = options.easing;
this.duration = options.duration;
if (this.easing && (!sigma.plugins || typeof sigma.plugins.animate === 'undefined')) {
throw new Error('sigma.plugins.animate is not declared');
}
// State
this.running = false;
};
this.start = function () {
if (this.running) return;
this.running = true;
// Create a new directed graph
dg = new dagre.graphlib.Graph({
directed: this.config.directed,
multigraph: this.config.multigraph,
compound: this.config.compound
});
// Set an object for the graph label
dg.setGraph(this.config);
var nodes = this.nodes || this.sigInst.graph.nodes();
for (var i = 0; i < nodes.length; i++) {
if (!nodes[i].fixed) {
dg.setNode(nodes[i].id, {});
}
}
if (this.boundingBox === true) {
this.boundingBox = getBoundaries(nodes);
}
var edges = this.sigInst.graph.edges();
for (var i = 0; i < edges.length; i++) {
if (dg.node(edges[i].source) != null && dg.node(edges[i].target) != null) {
dg.setEdge(edges[i].source, edges[i].target, { id: edges[i].id });
}
};
_eventEmitter[self.sigInst.id].dispatchEvent('start');
// console.time('sigma.layouts.dagre');
dagre.layout(dg);
// console.timeEnd('sigma.layouts.dagre');
var edge;
dg.edges().map(function (e) {
edge = self.sigInst.graph.edges(dg.edge(e).id);
edge.points = dg.edge(e).points;
});
this.stop();
};
this.stop = function () {
if (!dg) return;
var nodes = dg.nodes().map(function (nid) {
return self.sigInst.graph.nodes(nid) || self.sigInst.graph.nodes(Number(nid));
});
var coord;
if (this.boundingBox) {
var baseBoundingBox = getBoundaries(dg.nodes().map(function (nid) {
return dg.node(nid);
}));
}
this.running = false;
if (this.easing) {
// Set new node coordinates
for (var i = 0; i < nodes.length; i++) {
if (this.boundingBox) {
coord = rescalePosition(dg.node(nodes[i].id), baseBoundingBox, self.boundingBox);
nodes[i].dagre_x = coord.x;
nodes[i].dagre_y = coord.y;
} else {
nodes[i].dagre_x = dg.node(nodes[i].id).x;
nodes[i].dagre_y = dg.node(nodes[i].id).y;
}
}
_eventEmitter[self.sigInst.id].dispatchEvent('interpolate');
sigma.plugins.animate(self.sigInst, {
x: 'dagre_x',
y: 'dagre_y'
}, {
nodes: nodes,
easing: self.easing,
onComplete: function onComplete() {
for (var i = 0; i < nodes.length; i++) {
nodes[i].dagre_x = null;
nodes[i].dagre_y = null;
}
_eventEmitter[self.sigInst.id].dispatchEvent('stop');
self.sigInst.refresh();
},
duration: self.duration
});
} else {
// Apply changes
var node;
dg.nodes().forEach(function (nid) {
node = self.sigInst.graph.nodes(nid);
node.x = dg.node(nid).x;
node.y = dg.node(nid).y;
});
_eventEmitter[self.sigInst.id].dispatchEvent('stop');
this.sigInst.refresh();
}
};
this.kill = function () {
this.sigInst = null;
this.config = null;
this.easing = null;
};
};
/**
* Interface
* ----------
*/
/**
* Configure the layout algorithm.
* Recognized options:
* **********************
* Here is the exhaustive list of every accepted parameters in the settings
* object:
*
* {?array} nodes The subset of nodes to apply the layout.
* {?object} boundingBox Constrain layout bounds. Value: {minX, maxX, minY, maxY}
* or true (all current positions of the given nodes)
* {?boolean} directed If `true`, take edge direction into
* account. Default: `true`.
* {?boolean} multigraph If `true`, allows multiple edges between
* the same pair of nodes. Default: `true`.
* {?boolean} compound If `true`, allows ompound nodes, i.e.
* nodes which can be the parent of other
* nodes. Default: `false`.
* {?string} rankDir Direction for rank nodes. Can be TB, BT,
* LR, or RL, where T = top, B = bottom,
* L = left, and R = right.
* {?(function|string)} easing Either the name of an easing in the
* sigma.utils.easings package or a
* function. If not specified, the
* quadraticInOut easing from this package
* will be used instead.
* {?number} duration The duration of the animation. If not
* specified, the "animationsTime" setting
* value of the sigma instance will be used
* instead.
*
*
* @param {sigma} sigInst The related sigma instance.
* @param {object} config The optional configuration object.
*
* @return {sigma.classes.dispatcher} Returns an event emitter.
*/
sigma.layouts.dagre.configure = function (sigInst, config) {
if (!sigInst) throw new Error('Missing argument: "sigInst"');
if (!config) throw new Error('Missing argument: "config"');
// Create instance if undefined
if (!_instance[sigInst.id]) {
_instance[sigInst.id] = new dagreLayout();
_eventEmitter[sigInst.id] = {};
sigma.classes.dispatcher.extend(_eventEmitter[sigInst.id]);
// Binding on kill to clear the references
sigInst.bind('kill', function () {
_instance[sigInst.id].kill();
_instance[sigInst.id] = null;
_eventEmitter[sigInst.id] = null;
});
}
_instance[sigInst.id].init(sigInst, config);
return _eventEmitter[sigInst.id];
};
/**
* Start the layout algorithm. It will use the existing configuration if no
* new configuration is passed.
* Recognized options:
* **********************
* Here is the exhaustive list of every accepted parameters in the settings
* object:
*
* {?array} nodes The subset of nodes to apply the layout.
* {?object} boundingBox Constrain layout bounds. Value: {minX, maxX, minY, maxY}
* or true (all current positions of the given nodes).
* {?boolean} directed If `true`, take edge direction into
* account. Default: `true`.
* {?boolean} multigraph If `true`, allows multiple edges between
* the same pair of nodes. Default: `true`.
* {?boolean} compound If `true`, allows ompound nodes, i.e.
* nodes which can be the parent of other
* nodes. Default: `false`.
* {?string} rankDir Direction for rank nodes. Can be TB, BT,
* LR, or RL, where T = top, B = bottom,
* L = left, and R = right.
* {?(function|string)} easing Either the name of an easing in the
* sigma.utils.easings package or a
* function. If not specified, the
* quadraticInOut easing from this package
* will be used instead.
* {?number} duration The duration of the animation. If not
* specified, the "animationsTime" setting
* value of the sigma instance will be used
* instead.
*
*
* @param {sigma} sigInst The related sigma instance.
* @param {?object} config The optional configuration object.
*
* @return {sigma.classes.dispatcher} Returns an event emitter.
*/
sigma.layouts.dagre.start = function (sigInst, config) {
if (!sigInst) throw new Error('Missing argument: "sigInst"');
if (config) {
this.configure(sigInst, config);
}
_instance[sigInst.id].start();
return _eventEmitter[sigInst.id];
};
/**
* Returns true if the layout has started and is not completed.
*
* @param {sigma} sigInst The related sigma instance.
*
* @return {boolean}
*/
sigma.layouts.dagre.isRunning = function (sigInst) {
if (!sigInst) throw new Error('Missing argument: "sigInst"');
return !!_instance[sigInst.id] && _instance[sigInst.id].running;
};
}).call(this);
}).call(window);
/***/ }),
/* 82 */,
/* 83 */,
/* 84 */,
/* 85 */,
/* 86 */,
/* 87 */,
/* 88 */,
/* 89 */,
/* 90 */,
/* 91 */,
/* 92 */,
/* 93 */,
/* 94 */
/***/ (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 O