diff --git a/src/graph.coffee b/src/graph.coffee index 0e3e1cc..a40f5ed 100644 --- a/src/graph.coffee +++ b/src/graph.coffee @@ -94,6 +94,7 @@ class GraphLayout ranks: {} nodes: {} edges: {} + reach: {} graph: null constructor: (@ranks = {}, @nodes = {}, @edges = {}) -> @@ -105,15 +106,20 @@ class GraphLayout for n, _ of newnodes graph.addNode n @graph.addNode n - for i, e of newedges - graph.addEdge e[0], e[1] - @edges[i] = e + for i, [s, t, o] of newedges when s != t + graph.addNode s if s not of newnodes + graph.addNode t if t not of newnodes + graph.addEdge s, t + @edges[i] = [s, t, o] # INIT RANKS for n, _ of newnodes rank = 0 - for t from graph.adges n when rank >= @ranks[t] - rank = @ranks[t]-1 - @ranks[n] = rank if rank > 0 + for t from graph.adges n + if rank >= @ranks[t] + rank = @ranks[t]-1 + @ranks[n] = rank if rank < 0 + if 0 not of @graph.edges + new Error('Graph must containt node with id = 0!') @ranks[0] = 0 # ADD RANKS queue = new UniqueQueue Queue, ([n, @ranks[n], n] for n, _ of newnodes when n of @ranks) @@ -123,49 +129,56 @@ class GraphLayout if n != t and (t not of @ranks or r == @ranks[t]) queue.insert t, r-1, t # ORIENT EDGES - for e, [s,t,o] of newedges + for e, [s,t,o] of newedges when s != t [s,t] = [t,s] if @ranks[s] < @ranks[t] @graph.addEdge s, t @edges[e] = [s,t,o] for n, _ of @ranks - sort @graph.edges[n], (a) => @graph.rdges[a].length - sort @graph.rdges[n], (a) => @graph.rdges[a].length - + sort @graph.edges[n], (a) => @graph.rdges[a].length + 1/a + sort @graph.rdges[n], (a) => @graph.rdges[a].length + 1/a # ADD NODES for i, _ of newnodes @nodes[i] = [null, null] + # INIT REACH (PARALLEL PATHS) + + # ADD REACH + +# console.log ([n, @ranks[n]] for n,_ of newnodes) layout: () => - [xs, ys, x, y] = [[], [], 0, 0] + # PRELIMINARY + [remains, xs, ys, x, y] = [[], [], [], 0, 0] queue = new UniqueQueue Stack, ([n, 1, 1] for n, r of @ranks when r == 0) + console.log @ranks, queue.queue.stack + for n, _ of @nodes + remains[n] = @graph.rdges[n].length for [n, _, _] from queue.iter() @nodes[n][1] = x++ xs.push n + console.log n, @graph.edges[n] for t from @graph.edges[n] - queue.insert t, 1, 1 if @graph.rdges[t][0] == parseInt(n) + queue.insert t, 1, 1 if --remains[t] == 0 queue = new UniqueQueue Stack, ([n, 1, 1] for n, r of @ranks when r == 0) queue.queue.stack = queue.queue.stack.reverse() + for n, _ of @nodes + remains[n] = @graph.rdges[n].length for [n, _, _] from queue.iter() @nodes[n][0] = y++ ys.push n for t from @graph.edges[n].reverse() - queue.insert t, 1, 1 if last(@graph.rdges[t]) == parseInt(n) - [x, y] = [0, 0] - nx = {} - @nodes[xs[0]][1] = 0 - @nodes[ys[0]][0] = 0 - for i in [0..xs.length-2] - x++ if @nodes[xs[i]][0] > @nodes[xs[i+1]][0] or @graph.edges[xs[i]] == 1 and @graph.rdges[xs[i+1]] == 1 - nx[xs[i+1]] = x - for i in [0..ys.length-2] - y++ if @nodes[ys[i]][1] > @nodes[ys[i+1]][1] or @graph.edges[ys[i]] == 1 and @graph.rdges[ys[i+1]] == 1 - @nodes[ys[i+1]][0] = y - for n, x of nx - @nodes[n][1] = x + queue.insert t, 1, 1 if --remains[t] == 0 + # COMPACTION for n, pos of @nodes - pos[1] = pos[1] - pos[0] - pos[0] = pos[1] + pos[0] * 2 +# pos[1] = pos[1] - pos[0] + pos[0] = @ranks[n] #pos[1] + pos[0] * 2 +# [x, xs] = [0, sort (n for n,[_,x] of @nodes when x <= 0), (n) => -@nodes[n][1]] +# for i in [0..xs.length-2] +# @nodes[xs[i+1]][1] = if int(xs[i+1]) in @graph.edges[xs[i]] then x else --x + ns = sort (n for n,[_,x] of @nodes when x > 0), (n) => @nodes[n][1] + xs = (-1 for _ of @nodes) + for n in ns + @nodes[n][1] = xs[-@ranks[n]] = Math.max xs[-@ranks[n]-1], xs[-@ranks[n]]+1 class State @@ -179,7 +192,15 @@ class State for transition from @input for n in transition.remove.nodes delete @graph.nodes[n] + delete @graph.ranks[n] + delete @graph.graph.edges[n] + delete @graph.graph.rdges[n] for e in transition.remove.edges + [s, t] = @graph.edges[e] + if s of @graph.nodes + @graph.graph.edges[s] = @graph.graph.edges[s].filter (x) => x != t + if t of @graph.nodes + @graph.graph.rdges[t] = @graph.graph.rdges[t].filter (x) => x != s delete @graph.edges[e] @graph.step transition.insert.nodes, transition.insert.edges @@ -187,9 +208,9 @@ class State int = parseInt -readCSV = (fileNodes, fileEdges) -> - nodes = ((s.replace(/\s+/g, '') for s in line.split(',')) for line in fs.readFileSync(fileNodes, 'utf8').split('\n')) - edges = ((s.replace(/\s+/g, '') for s in line.split(',')) for line in fs.readFileSync(fileEdges, 'utf8').split('\n')) +readCSV = (file) -> + nodes = ((s.replace(/\s+/g, '') for s in line.split(',')) for line in fs.readFileSync(file+'/nodes.csv', 'utf8').split('\n')) + edges = ((s.replace(/\s+/g, '') for s in line.split(',')) for line in fs.readFileSync(file+'/edges.csv', 'utf8').split('\n')) [n, e] = [1, 1] while nodes[n++][0] != 'END' and edges[e++][0] != 'END' t = {remove: {nodes: [], edges: []}, insert: {nodes: {}, edges: {}}} @@ -205,19 +226,20 @@ readCSV = (fileNodes, fileEdges) -> e++ yield t -state = new State readCSV '../data/nodes.csv', '../data/edges.csv' - +state = new State readCSV '../data/27f' +i=0 for graph from state.iter() - graph.nodes[n][0] = r for n, r of graph.ranks - graph.layout() - - file = fs.openSync('./layoutdata.coffee', 'w') - fs.writeSync(file, "export graph =\n") - fs.writeSync(file, " nodes:\n") - fs.writeSync(file, " " + n + " : [" + d + "]\n") for n, d of graph.nodes - fs.writeSync(file, " edges:\n") - fs.writeSync(file, " " + e + " : [" + d + "]\n") for e, d of graph.edges - fs.closeSync(file) - break + if i++ == 3 + graph.nodes[n][0] = r for n, r of graph.ranks + graph.layout() + + file = fs.openSync('./layoutdata.coffee', 'w') + fs.writeSync(file, "export graph =\n") + fs.writeSync(file, " nodes:\n") + fs.writeSync(file, " " + n + " : [" + d + "]\n") for n, d of graph.nodes + fs.writeSync(file, " edges:\n") + fs.writeSync(file, " " + e + " : [" + d + "]\n") for e, d of graph.edges + fs.closeSync(file) + break diff --git a/src/main.coffee b/src/main.coffee index d7bca0c..14c4895 100644 --- a/src/main.coffee +++ b/src/main.coffee @@ -7,21 +7,13 @@ import {graph} from 'layoutdata' G = 15 -scene = basegl.scene - domElement: 'scene' - width: 2048 - height: 2048 - - -eventReactor = new KeyboardMouseReactor scene - addNode = (n, [y, x]) -> r = G/6 # name = basegl.text {str: "HELLO", scene: scene, fontFamily: 'SourceCodePro', size: 16} node = scene.add basegl.symbol basegl.expr -> circle(r).move(r, r) node.bbox.xy = [2*r, 2*r] node.position.xy = [G*x, G*y] - node.addEventListener "mouseover", (e) -> console.log "OVER NODE!" + node.addEventListener "mouseover", (e) => alert "Node: " + n group [node] addEdge = ([ys, xs], [yt, xt], offset) -> @@ -49,9 +41,24 @@ addLine = ([ys, xs], [yt, xt]) -> line -for _, pos of graph.nodes - pos[1] += 50 -for n, pos of graph.nodes - addNode n, pos -for _, [s, t, offset] of graph.edges - addLine graph.nodes[s], graph.nodes[t] +main = () -> + basegl.fontManager.register 'SourceCodePro', 'fonts/SourceCodePro.ttf' + await basegl.fontManager.load 'SourceCodePro' + + eventReactor = new KeyboardMouseReactor scene + + for _, pos of graph.nodes + pos[1] += 50 + pos[0] += 60 + for _, [s, t, offset] of graph.edges + addLine graph.nodes[s], graph.nodes[t] + for n, pos of graph.nodes + addNode n, pos + + +scene = basegl.scene + domElement: 'scene' + width: 2048 + height: 2048 + +main() \ No newline at end of file