vinayakb | 70b63e2 | 2012-02-03 13:13:01 +0000 | [diff] [blame] | 1 | Graphs = {}; |
| 2 | |
| 3 | Graphs.DAG = function() { |
| 4 | this.nodeMap = {}; |
| 5 | this.edgeMap = {}; |
| 6 | } |
| 7 | |
| 8 | Graphs.DAG.prototype.addNode = function(key, attachment) { |
| 9 | var node = new Graphs.Node(this, key, attachment); |
| 10 | this.nodeMap[key] = node; |
| 11 | return node; |
| 12 | } |
| 13 | |
| 14 | Graphs.DAG.prototype.addEdge = function(key, attachment, sNode, sIndex, tNode, tIndex) { |
| 15 | var edge = new Graphs.DirectedEdge(this, key, attachment, sNode, sIndex, tNode, tIndex); |
| 16 | this.edgeMap[key] = edge; |
| 17 | sNode.outEdges[sIndex] = edge; |
| 18 | tNode.inEdges[tIndex] = edge; |
| 19 | return edge; |
| 20 | } |
| 21 | |
| 22 | Graphs.DAG.prototype.lookupNode = function(key) { |
| 23 | return this.nodeMap[key]; |
| 24 | } |
| 25 | |
| 26 | Graphs.DAG.prototype.lookupEdge = function(key) { |
| 27 | return this.edgeMap[key]; |
| 28 | } |
| 29 | |
| 30 | Graphs.DAG.prototype.walkNodes = function(callback) { |
| 31 | for ( var nKey in this.nodeMap) { |
| 32 | callback(this.nodeMap[nKey]); |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | Graphs.DAG.prototype.walkEdges = function(callback) { |
| 37 | for ( var eKey in this.edgeMap) { |
| 38 | callback(this.edgeMap[eKey]); |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | Graphs.DAG.prototype.findRoots = function() { |
| 43 | var roots = []; |
| 44 | var callback = function(node) { |
| 45 | if (node.inEdges.length == 0) { |
| 46 | roots.push(node); |
| 47 | } |
| 48 | } |
| 49 | this.walkNodes(callback); |
| 50 | return roots; |
| 51 | } |
| 52 | |
| 53 | Graphs.DAG.prototype.findLeaves = function() { |
| 54 | var leaves = []; |
| 55 | var callback = function(node) { |
| 56 | if (node.outEdges.length == 0) { |
| 57 | leaves.push(node); |
| 58 | } |
| 59 | } |
| 60 | this.walkNodes(callback); |
| 61 | return leaves; |
| 62 | } |
| 63 | |
| 64 | Graphs.DAG.prototype.tsort = function() { |
| 65 | var sortedNodes = []; |
| 66 | var nodeState = {}; |
| 67 | |
| 68 | function visit(node) { |
| 69 | if (!nodeState[node.key]) { |
| 70 | nodeState[node.key] = true; |
| 71 | for ( var i = 0; i < node.inEdges.length; ++i) { |
| 72 | visit(node.inEdges[i].sNode); |
| 73 | } |
| 74 | sortedNodes.push(node); |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | var roots = this.findLeaves(); |
| 79 | for ( var i = 0; i < roots.length; ++i) { |
| 80 | visit(roots[i]); |
| 81 | } |
| 82 | return sortedNodes; |
| 83 | } |
| 84 | |
| 85 | Graphs.DAG.prototype.stratify = function() { |
| 86 | var sortedNodes = this.tsort(); |
| 87 | var stratumMap = {}; |
| 88 | var strata = []; |
| 89 | for ( var i = 0; i < sortedNodes.length; ++i) { |
| 90 | var node = sortedNodes[i]; |
| 91 | var maxParentStratum = -1; |
| 92 | for ( var j = 0; j < node.inEdges.length; ++j) { |
| 93 | var edge = node.inEdges[j]; |
| 94 | maxParentStratum = Math.max(maxParentStratum, stratumMap[edge.sNode.key]); |
| 95 | } |
| 96 | var stratum = maxParentStratum + 1; |
| 97 | stratumMap[node.key] = stratum; |
| 98 | var stratumList = strata[stratum]; |
| 99 | if (!stratumList) { |
| 100 | stratumList = []; |
| 101 | strata[stratum] = stratumList; |
| 102 | } |
| 103 | stratumList.push(node); |
| 104 | } |
| 105 | return strata; |
| 106 | } |
| 107 | |
| 108 | Graphs.Node = function(dag, key, attachment) { |
| 109 | this.dag = dag; |
| 110 | this.key = key; |
| 111 | this.attachment = attachment; |
| 112 | this.inEdges = []; |
| 113 | this.outEdges = []; |
| 114 | } |
| 115 | |
| 116 | Graphs.DirectedEdge = function(dag, key, attachment, sNode, sIndex, tNode, tIndex) { |
| 117 | this.dag = dag; |
| 118 | this.key = key; |
| 119 | this.attachment = attachment; |
| 120 | this.sNode = sNode; |
| 121 | this.sIndex = sIndex; |
| 122 | this.tNode = tNode; |
| 123 | this.tIndex = tIndex; |
| 124 | } |
| 125 | |
| 126 | Graphs.JsPlumbRenderer = function(dag, element, options) { |
| 127 | this.dag = dag; |
| 128 | this.element = element; |
vinayakb | 77a6709 | 2012-02-05 23:53:54 +0000 | [diff] [blame] | 129 | this.options = options || { |
| 130 | levelStep : 100 |
| 131 | }; |
| 132 | } |
| 133 | |
| 134 | Graphs.JsPlumbRenderer.prototype.configureDiv = function(div, node, stratum, inStratumIndex, stratumWidth) { |
| 135 | div.id = node.key; |
| 136 | div.dagNode = node; |
| 137 | /* |
| 138 | * div.style.position = 'absolute'; div.style.left = (stratum * |
| 139 | * this.options.levelStep) + 'px'; div.style.top = (inStratumIndex * 100) + |
| 140 | * 'px'; div.style.width = '50px'; div.style.height = '50px'; |
| 141 | * div.style.border = 'thick solid #000000'; |
| 142 | */ |
vinayakb | 70b63e2 | 2012-02-03 13:13:01 +0000 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | Graphs.JsPlumbRenderer.prototype.refresh = function() { |
| 146 | var strata = this.dag.stratify(); |
| 147 | |
| 148 | while (this.element.hasChildNodes()) { |
| 149 | this.element.removeChild(this.element.lastChild); |
| 150 | } |
| 151 | for ( var i = 0; i < strata.length; ++i) { |
| 152 | var stratumList = strata[i]; |
| 153 | for ( var j = 0; j < stratumList.length; ++j) { |
| 154 | var node = stratumList[j]; |
| 155 | var div = document.createElement('div'); |
vinayakb | 77a6709 | 2012-02-05 23:53:54 +0000 | [diff] [blame] | 156 | this.configureDiv(div, node, i, j, stratumList.length); |
vinayakb | 70b63e2 | 2012-02-03 13:13:01 +0000 | [diff] [blame] | 157 | this.element.appendChild(div); |
| 158 | } |
| 159 | } |
| 160 | } |