function relayout_sdfg(ctx, sdfg) {
    let STATE_MARGIN = 4*LINEHEIGHT;

    // Layout the SDFG as a dagre graph
    let g = new dagre.graphlib.Graph();
    g.setGraph({});
    g.setDefaultEdgeLabel(function (u, v) { return {}; });

    // layout each state to get its size
    sdfg.nodes.forEach((state) => {
        let stateinfo = {};

        stateinfo.label = state.id;
        let state_g = null;
        if (state.attributes.is_collapsed) {
            stateinfo.width = ctx.measureText(stateinfo.label).width;
            stateinfo.height = LINEHEIGHT;
        }
        else {
            state_g = relayout_state(ctx, state, sdfg);
            stateinfo = calculateBoundingBox(state_g);
        }
        stateinfo.width += 2*STATE_MARGIN;
        stateinfo.height += 2*STATE_MARGIN;
        g.setNode(state.id, new State({state: state,
                                                layout: stateinfo,
                                                graph: state_g}, state.id, sdfg));
    });

    sdfg.edges.forEach((edge, id) => {
        g.setEdge(edge.src, edge.dst, new Edge(edge.attributes.data, id, sdfg));
    });

    dagre.layout(g);

    // Annotate the sdfg with its layout info
    sdfg.nodes.forEach(function (state) {
        let gnode = g.node(state.id);
        state.attributes.layout = {};
        state.attributes.layout.x = gnode.x;
        state.attributes.layout.y = gnode.y;
        state.attributes.layout.width = gnode.width;
        state.attributes.layout.height = gnode.height;
    });

    sdfg.edges.forEach(function (edge) {
        let gedge = g.edge(edge.src, edge.dst);
        let bb = calculateEdgeBoundingBox(gedge);
        // Convert from top-left to center
        bb.x += bb.width / 2.0;
        bb.y += bb.height / 2.0;

        gedge.x = bb.x;
        gedge.y = bb.y;
        gedge.width = bb.width;
        gedge.height = bb.height;
        edge.attributes.layout = {};
        edge.attributes.layout.width = bb.width;
        edge.attributes.layout.height = bb.height;
        edge.attributes.layout.x = bb.x;
        edge.attributes.layout.y = bb.y;
        edge.attributes.layout.points = gedge.points;
    });

    // Offset node and edge locations to be in state margins
    sdfg.nodes.forEach((s, sid) => {
        if (s.attributes.is_collapsed)
            return;

        let state = g.node(sid);
        let topleft = state.topleft();
        offset_state(s, state, {x: topleft.x + STATE_MARGIN,
                                         y: topleft.y + STATE_MARGIN});
    });

    return g;
}
// Layout SDFG elements (states, nodes, scopes, nested SDFGs)
Layout SDFG elements (states, nodes, scopes, nested SDFGs)
Layout SDFG elements ( states nodes scopes nested SDFGs )
function relayout_sdfg(ctx, sdfg) {
    let STATE_MARGIN = 4*LINEHEIGHT;
    let g = new dagre.graphlib.Graph();
    g.setGraph({});
    g.setDefaultEdgeLabel(function (u, v) { return {}; });
    sdfg.nodes.forEach((state) => {
        let stateinfo = {};
        stateinfo.label = state.id;
        let state_g = null;
        if (state.attributes.is_collapsed) {
            stateinfo.width = ctx.measureText(stateinfo.label).width;
            stateinfo.height = LINEHEIGHT;
        }
        else {
            state_g = relayout_state(ctx, state, sdfg);
            stateinfo = calculateBoundingBox(state_g);
        }
        stateinfo.width += 2*STATE_MARGIN;
        stateinfo.height += 2*STATE_MARGIN;
        g.setNode(state.id, new State({state: state,
                                                layout: stateinfo,
                                                graph: state_g}, state.id, sdfg));
    });
    sdfg.edges.forEach((edge, id) => {
        g.setEdge(edge.src, edge.dst, new Edge(edge.attributes.data, id, sdfg));
    });
    dagre.layout(g);
    sdfg.nodes.forEach(function (state) {
        let gnode = g.node(state.id);
        state.attributes.layout = {};
        state.attributes.layout.x = gnode.x;
        state.attributes.layout.y = gnode.y;
        state.attributes.layout.width = gnode.width;
        state.attributes.layout.height = gnode.height;
    });
    sdfg.edges.forEach(function (edge) {
        let gedge = g.edge(edge.src, edge.dst);
        let bb = calculateEdgeBoundingBox(gedge);
        bb.x += bb.width / 2.0;
        bb.y += bb.height / 2.0;
        gedge.x = bb.x;
        gedge.y = bb.y;
        gedge.width = bb.width;
        gedge.height = bb.height;
        edge.attributes.layout = {};
        edge.attributes.layout.width = bb.width;
        edge.attributes.layout.height = bb.height;
        edge.attributes.layout.x = bb.x;
        edge.attributes.layout.y = bb.y;
        edge.attributes.layout.points = gedge.points;
    });
    sdfg.nodes.forEach((s, sid) => {
        if (s.attributes.is_collapsed)
            return;
        let state = g.node(sid);
        let topleft = state.topleft();
        offset_state(s, state, {x: topleft.x + STATE_MARGIN,
                                         y: topleft.y + STATE_MARGIN});
    });
    return g;
}
function relayout_sdfg ( ctx , sdfg ) { let STATE_MARGIN = 4 * LINEHEIGHT ; let g = new dagre . graphlib . Graph ( ) ; g . setGraph ( { } ) ; g . setDefaultEdgeLabel ( function ( u , v ) { return { } ; } ) ; sdfg . nodes . forEach ( ( state ) => { let stateinfo = { } ; stateinfo . label = state . id ; let state_g = null ; if ( state . attributes . is_collapsed ) { stateinfo . width = ctx . measureText ( stateinfo . label ) . width ; stateinfo . height = LINEHEIGHT ; } else { state_g = relayout_state ( ctx , state , sdfg ) ; stateinfo = calculateBoundingBox ( state_g ) ; } stateinfo . width += 2 * STATE_MARGIN ; stateinfo . height += 2 * STATE_MARGIN ; g . setNode ( state . id , new State ( { state : state , layout : stateinfo , graph : state_g } , state . id , sdfg ) ) ; } ) ; sdfg . edges . forEach ( ( edge , id ) => { g . setEdge ( edge . src , edge . dst , new Edge ( edge . attributes . data , id , sdfg ) ) ; } ) ; dagre . layout ( g ) ; sdfg . nodes . forEach ( function ( state ) { let gnode = g . node ( state . id ) ; state . attributes . layout = { } ; state . attributes . layout . x = gnode . x ; state . attributes . layout . y = gnode . y ; state . attributes . layout . width = gnode . width ; state . attributes . layout . height = gnode . height ; } ) ; sdfg . edges . forEach ( function ( edge ) { let gedge = g . edge ( edge . src , edge . dst ) ; let bb = calculateEdgeBoundingBox ( gedge ) ; bb . x += bb . width / 2.0 ; bb . y += bb . height / 2.0 ; gedge . x = bb . x ; gedge . y = bb . y ; gedge . width = bb . width ; gedge . height = bb . height ; edge . attributes . layout = { } ; edge . attributes . layout . width = bb . width ; edge . attributes . layout . height = bb . height ; edge . attributes . layout . x = bb . x ; edge . attributes . layout . y = bb . y ; edge . attributes . layout . points = gedge . points ; } ) ; sdfg . nodes . forEach ( ( s , sid ) => { if ( s . attributes . is_collapsed ) return ; let state = g . node ( sid ) ; let topleft = state . topleft ( ) ; offset_state ( s , state , { x : topleft . x + STATE_MARGIN , y : topleft . y + STATE_MARGIN } ) ; } ) ; return g ; }
Layout SDFG elements (states, nodes, scopes, nested SDFGs)
Layout SDFG elements ( states nodes scopes nested SDFGs )
// Layout the SDFG as a dagre graph // layout each state to get its size // Annotate the sdfg with its layout info // Convert from top-left to center // Offset node and edge locations to be in state margins