|
var LGraph;
|
|
var LEdge = require('./LEdge');
|
|
|
|
function LGraphManager(layout) {
|
|
LGraph = require('./LGraph');
|
|
this.layout = layout;
|
|
|
|
this.graphs = [];
|
|
this.edges = [];
|
|
}
|
|
|
|
LGraphManager.prototype.addRoot = function ()
|
|
{
|
|
var ngraph = this.layout.newGraph();
|
|
var nnode = this.layout.newNode(null);
|
|
var root = this.add(ngraph, nnode);
|
|
this.setRootGraph(root);
|
|
return this.rootGraph;
|
|
};
|
|
|
|
LGraphManager.prototype.add = function (newGraph, parentNode, newEdge, sourceNode, targetNode)
|
|
{
|
|
|
|
if (newEdge == null && sourceNode == null && targetNode == null) {
|
|
if (newGraph == null) {
|
|
throw "Graph is null!";
|
|
}
|
|
if (parentNode == null) {
|
|
throw "Parent node is null!";
|
|
}
|
|
if (this.graphs.indexOf(newGraph) > -1) {
|
|
throw "Graph already in this graph mgr!";
|
|
}
|
|
|
|
this.graphs.push(newGraph);
|
|
|
|
if (newGraph.parent != null) {
|
|
throw "Already has a parent!";
|
|
}
|
|
if (parentNode.child != null) {
|
|
throw "Already has a child!";
|
|
}
|
|
|
|
newGraph.parent = parentNode;
|
|
parentNode.child = newGraph;
|
|
|
|
return newGraph;
|
|
}
|
|
else {
|
|
|
|
targetNode = newEdge;
|
|
sourceNode = parentNode;
|
|
newEdge = newGraph;
|
|
var sourceGraph = sourceNode.getOwner();
|
|
var targetGraph = targetNode.getOwner();
|
|
|
|
if (!(sourceGraph != null && sourceGraph.getGraphManager() == this)) {
|
|
throw "Source not in this graph mgr!";
|
|
}
|
|
if (!(targetGraph != null && targetGraph.getGraphManager() == this)) {
|
|
throw "Target not in this graph mgr!";
|
|
}
|
|
|
|
if (sourceGraph == targetGraph)
|
|
{
|
|
newEdge.isInterGraph = false;
|
|
return sourceGraph.add(newEdge, sourceNode, targetNode);
|
|
}
|
|
else
|
|
{
|
|
newEdge.isInterGraph = true;
|
|
|
|
|
|
newEdge.source = sourceNode;
|
|
newEdge.target = targetNode;
|
|
|
|
|
|
if (this.edges.indexOf(newEdge) > -1) {
|
|
throw "Edge already in inter-graph edge list!";
|
|
}
|
|
|
|
this.edges.push(newEdge);
|
|
|
|
|
|
if (!(newEdge.source != null && newEdge.target != null)) {
|
|
throw "Edge source and/or target is null!";
|
|
}
|
|
|
|
if (!(newEdge.source.edges.indexOf(newEdge) == -1 && newEdge.target.edges.indexOf(newEdge) == -1)) {
|
|
throw "Edge already in source and/or target incidency list!";
|
|
}
|
|
|
|
newEdge.source.edges.push(newEdge);
|
|
newEdge.target.edges.push(newEdge);
|
|
|
|
return newEdge;
|
|
}
|
|
}
|
|
};
|
|
|
|
LGraphManager.prototype.remove = function (lObj) {
|
|
if (lObj instanceof LGraph) {
|
|
var graph = lObj;
|
|
if (graph.getGraphManager() != this) {
|
|
throw "Graph not in this graph mgr";
|
|
}
|
|
if (!(graph == this.rootGraph || (graph.parent != null && graph.parent.graphManager == this))) {
|
|
throw "Invalid parent node!";
|
|
}
|
|
|
|
|
|
var edgesToBeRemoved = [];
|
|
|
|
edgesToBeRemoved = edgesToBeRemoved.concat(graph.getEdges());
|
|
|
|
var edge;
|
|
var s = edgesToBeRemoved.length;
|
|
for (var i = 0; i < s; i++)
|
|
{
|
|
edge = edgesToBeRemoved[i];
|
|
graph.remove(edge);
|
|
}
|
|
|
|
|
|
var nodesToBeRemoved = [];
|
|
|
|
nodesToBeRemoved = nodesToBeRemoved.concat(graph.getNodes());
|
|
|
|
var node;
|
|
s = nodesToBeRemoved.length;
|
|
for (var i = 0; i < s; i++)
|
|
{
|
|
node = nodesToBeRemoved[i];
|
|
graph.remove(node);
|
|
}
|
|
|
|
|
|
if (graph == this.rootGraph)
|
|
{
|
|
this.setRootGraph(null);
|
|
}
|
|
|
|
|
|
var index = this.graphs.indexOf(graph);
|
|
this.graphs.splice(index, 1);
|
|
|
|
|
|
graph.parent = null;
|
|
}
|
|
else if (lObj instanceof LEdge) {
|
|
edge = lObj;
|
|
if (edge == null) {
|
|
throw "Edge is null!";
|
|
}
|
|
if (!edge.isInterGraph) {
|
|
throw "Not an inter-graph edge!";
|
|
}
|
|
if (!(edge.source != null && edge.target != null)) {
|
|
throw "Source and/or target is null!";
|
|
}
|
|
|
|
|
|
|
|
if (!(edge.source.edges.indexOf(edge) != -1 && edge.target.edges.indexOf(edge) != -1)) {
|
|
throw "Source and/or target doesn't know this edge!";
|
|
}
|
|
|
|
var index = edge.source.edges.indexOf(edge);
|
|
edge.source.edges.splice(index, 1);
|
|
index = edge.target.edges.indexOf(edge);
|
|
edge.target.edges.splice(index, 1);
|
|
|
|
|
|
|
|
if (!(edge.source.owner != null && edge.source.owner.getGraphManager() != null)) {
|
|
throw "Edge owner graph or owner graph manager is null!";
|
|
}
|
|
if (edge.source.owner.getGraphManager().edges.indexOf(edge) == -1) {
|
|
throw "Not in owner graph manager's edge list!";
|
|
}
|
|
|
|
var index = edge.source.owner.getGraphManager().edges.indexOf(edge);
|
|
edge.source.owner.getGraphManager().edges.splice(index, 1);
|
|
}
|
|
};
|
|
|
|
LGraphManager.prototype.updateBounds = function ()
|
|
{
|
|
this.rootGraph.updateBounds(true);
|
|
};
|
|
|
|
LGraphManager.prototype.getGraphs = function ()
|
|
{
|
|
return this.graphs;
|
|
};
|
|
|
|
LGraphManager.prototype.getAllNodes = function ()
|
|
{
|
|
if (this.allNodes == null)
|
|
{
|
|
var nodeList = [];
|
|
var graphs = this.getGraphs();
|
|
var s = graphs.length;
|
|
for (var i = 0; i < s; i++)
|
|
{
|
|
nodeList = nodeList.concat(graphs[i].getNodes());
|
|
}
|
|
this.allNodes = nodeList;
|
|
}
|
|
return this.allNodes;
|
|
};
|
|
|
|
LGraphManager.prototype.resetAllNodes = function ()
|
|
{
|
|
this.allNodes = null;
|
|
};
|
|
|
|
LGraphManager.prototype.resetAllEdges = function ()
|
|
{
|
|
this.allEdges = null;
|
|
};
|
|
|
|
LGraphManager.prototype.resetAllNodesToApplyGravitation = function ()
|
|
{
|
|
this.allNodesToApplyGravitation = null;
|
|
};
|
|
|
|
LGraphManager.prototype.getAllEdges = function ()
|
|
{
|
|
if (this.allEdges == null)
|
|
{
|
|
var edgeList = [];
|
|
var graphs = this.getGraphs();
|
|
var s = graphs.length;
|
|
for (var i = 0; i < graphs.length; i++)
|
|
{
|
|
edgeList = edgeList.concat(graphs[i].getEdges());
|
|
}
|
|
|
|
edgeList = edgeList.concat(this.edges);
|
|
|
|
this.allEdges = edgeList;
|
|
}
|
|
return this.allEdges;
|
|
};
|
|
|
|
LGraphManager.prototype.getAllNodesToApplyGravitation = function ()
|
|
{
|
|
return this.allNodesToApplyGravitation;
|
|
};
|
|
|
|
LGraphManager.prototype.setAllNodesToApplyGravitation = function (nodeList)
|
|
{
|
|
if (this.allNodesToApplyGravitation != null) {
|
|
throw "assert failed";
|
|
}
|
|
|
|
this.allNodesToApplyGravitation = nodeList;
|
|
};
|
|
|
|
LGraphManager.prototype.getRoot = function ()
|
|
{
|
|
return this.rootGraph;
|
|
};
|
|
|
|
LGraphManager.prototype.setRootGraph = function (graph)
|
|
{
|
|
if (graph.getGraphManager() != this) {
|
|
throw "Root not in this graph mgr!";
|
|
}
|
|
|
|
this.rootGraph = graph;
|
|
|
|
if (graph.parent == null)
|
|
{
|
|
graph.parent = this.layout.newNode("Root node");
|
|
}
|
|
};
|
|
|
|
LGraphManager.prototype.getLayout = function ()
|
|
{
|
|
return this.layout;
|
|
};
|
|
|
|
LGraphManager.prototype.isOneAncestorOfOther = function (firstNode, secondNode)
|
|
{
|
|
if (!(firstNode != null && secondNode != null)) {
|
|
throw "assert failed";
|
|
}
|
|
|
|
if (firstNode == secondNode)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
var ownerGraph = firstNode.getOwner();
|
|
var parentNode;
|
|
|
|
do
|
|
{
|
|
parentNode = ownerGraph.getParent();
|
|
|
|
if (parentNode == null)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (parentNode == secondNode)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
ownerGraph = parentNode.getOwner();
|
|
if (ownerGraph == null)
|
|
{
|
|
break;
|
|
}
|
|
} while (true);
|
|
|
|
ownerGraph = secondNode.getOwner();
|
|
|
|
do
|
|
{
|
|
parentNode = ownerGraph.getParent();
|
|
|
|
if (parentNode == null)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (parentNode == firstNode)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
ownerGraph = parentNode.getOwner();
|
|
if (ownerGraph == null)
|
|
{
|
|
break;
|
|
}
|
|
} while (true);
|
|
|
|
return false;
|
|
};
|
|
|
|
LGraphManager.prototype.calcLowestCommonAncestors = function ()
|
|
{
|
|
var edge;
|
|
var sourceNode;
|
|
var targetNode;
|
|
var sourceAncestorGraph;
|
|
var targetAncestorGraph;
|
|
|
|
var edges = this.getAllEdges();
|
|
var s = edges.length;
|
|
for (var i = 0; i < s; i++)
|
|
{
|
|
edge = edges[i];
|
|
|
|
sourceNode = edge.source;
|
|
targetNode = edge.target;
|
|
edge.lca = null;
|
|
edge.sourceInLca = sourceNode;
|
|
edge.targetInLca = targetNode;
|
|
|
|
if (sourceNode == targetNode)
|
|
{
|
|
edge.lca = sourceNode.getOwner();
|
|
continue;
|
|
}
|
|
|
|
sourceAncestorGraph = sourceNode.getOwner();
|
|
|
|
while (edge.lca == null)
|
|
{
|
|
edge.targetInLca = targetNode;
|
|
targetAncestorGraph = targetNode.getOwner();
|
|
|
|
while (edge.lca == null)
|
|
{
|
|
if (targetAncestorGraph == sourceAncestorGraph)
|
|
{
|
|
edge.lca = targetAncestorGraph;
|
|
break;
|
|
}
|
|
|
|
if (targetAncestorGraph == this.rootGraph)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (edge.lca != null) {
|
|
throw "assert failed";
|
|
}
|
|
edge.targetInLca = targetAncestorGraph.getParent();
|
|
targetAncestorGraph = edge.targetInLca.getOwner();
|
|
}
|
|
|
|
if (sourceAncestorGraph == this.rootGraph)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (edge.lca == null)
|
|
{
|
|
edge.sourceInLca = sourceAncestorGraph.getParent();
|
|
sourceAncestorGraph = edge.sourceInLca.getOwner();
|
|
}
|
|
}
|
|
|
|
if (edge.lca == null) {
|
|
throw "assert failed";
|
|
}
|
|
}
|
|
};
|
|
|
|
LGraphManager.prototype.calcLowestCommonAncestor = function (firstNode, secondNode)
|
|
{
|
|
if (firstNode == secondNode)
|
|
{
|
|
return firstNode.getOwner();
|
|
}
|
|
var firstOwnerGraph = firstNode.getOwner();
|
|
|
|
do
|
|
{
|
|
if (firstOwnerGraph == null)
|
|
{
|
|
break;
|
|
}
|
|
var secondOwnerGraph = secondNode.getOwner();
|
|
|
|
do
|
|
{
|
|
if (secondOwnerGraph == null)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (secondOwnerGraph == firstOwnerGraph)
|
|
{
|
|
return secondOwnerGraph;
|
|
}
|
|
secondOwnerGraph = secondOwnerGraph.getParent().getOwner();
|
|
} while (true);
|
|
|
|
firstOwnerGraph = firstOwnerGraph.getParent().getOwner();
|
|
} while (true);
|
|
|
|
return firstOwnerGraph;
|
|
};
|
|
|
|
LGraphManager.prototype.calcInclusionTreeDepths = function (graph, depth) {
|
|
if (graph == null && depth == null) {
|
|
graph = this.rootGraph;
|
|
depth = 1;
|
|
}
|
|
var node;
|
|
|
|
var nodes = graph.getNodes();
|
|
var s = nodes.length;
|
|
for (var i = 0; i < s; i++)
|
|
{
|
|
node = nodes[i];
|
|
node.inclusionTreeDepth = depth;
|
|
|
|
if (node.child != null)
|
|
{
|
|
this.calcInclusionTreeDepths(node.child, depth + 1);
|
|
}
|
|
}
|
|
};
|
|
|
|
LGraphManager.prototype.includesInvalidEdge = function ()
|
|
{
|
|
var edge;
|
|
|
|
var s = this.edges.length;
|
|
for (var i = 0; i < s; i++)
|
|
{
|
|
edge = this.edges[i];
|
|
|
|
if (this.isOneAncestorOfOther(edge.source, edge.target))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
module.exports = LGraphManager;
|
|
|