aboutsummaryrefslogblamecommitdiffstats
path: root/html/js/git-deps-layout.coffee
blob: 8e88ddea7657194bab83c394923a451c155514b8 (plain) (tree)



















































































































                                                                          
$ = require "jquery"
dagre = require "dagre"

gdd = require "./git-deps-data.coffee"

# The list of constraints to feed into WebCola.
constraints = []

# Group nodes by row, as assigned by the y coordinates returned from
# dagre's layout().  This will map a y coordinate onto all nodes
# within that row.
row_groups = {}

# Expose a container for externally accessible objects.  We can't
# directly expose the objects themselves because the references
# change each time they're constructed.  However we don't need this
# trick for the constraints arrays since we can easily empty that by
# setting length to 0.
externs = {}

dagre_layout = ->
    g = new dagre.graphlib.Graph()
    externs.graph = g
    
    # Set an object for the graph label
    g.setGraph {}
    
    # Default to assigning a new object as a label for each new edge.
    g.setDefaultEdgeLabel -> {}

    $.each gdd.nodes, (i, node) ->
        g.setNode node.sha1,
            label: node.name
            width: node.rect_width or 70
            height: node.rect_height or 30

    $.each gdd.deps, (parent_sha1, children) ->
        $.each children, (child_sha1, bool) ->
            g.setEdge parent_sha1, child_sha1

    dagre.layout g
    return g

dagre_row_groups = ->
    g = dagre_layout()
    row_groups = {}
    externs.row_groups = row_groups
    g.nodes().forEach (sha1) ->
        x = g.node(sha1).x
        y = g.node(sha1).y
        row_groups[y] = []  unless y of row_groups
        row_groups[y].push
            sha1: sha1
            x: x
    return row_groups

build_constraints = ->
    row_groups = dagre_row_groups()

    constraints.length = 0 # FIXME: only rebuild constraints which changed
    
    # We want alignment constraints between all nodes which dagre
    # assigned the same y value.
    for y of row_groups
        row_nodes = row_groups[y]
        
        # No point having an alignment group with only one node in.
        if row_nodes.length > 1
            constraints.push build_alignment_constraint(row_nodes)
    
    # We also need separation constraints ensuring that the
    # top-to-bottom ordering assigned by dagre is preserved.  Since
    # all nodes within a single row are already constrained to the
    # same y coordinate from above, it should be enough to only
    # have separation between a single node in adjacent rows.
    row_y_coords = Object.keys(row_groups).sort()

    i = 0
    while i < row_y_coords.length - 1
        upper_y = row_y_coords[i]
        lower_y = row_y_coords[i + 1]
        upper_node = row_groups[upper_y][0]
        lower_node = row_groups[lower_y][0]
        constraints.push
            gap: 30
            axis: "y"
            left: gdd.node_index[upper_node.sha1]
            right: gdd.node_index[lower_node.sha1]

        i++

build_alignment_constraint = (row_nodes) ->
    constraint =
        axis: "y"
        type: "alignment"
        offsets: []

    for i of row_nodes
        node = row_nodes[i]
        constraint.offsets.push
            node: gdd.node_index[node.sha1]
            offset: 0

    return constraint

node = (sha1) ->
    externs.graph.node sha1

module.exports =
    # Variables
    constraints: constraints
    g: externs
    
    # Functions
    build_constraints: build_constraints
    node: node