tomshanley / d3-sankey-circular

A fork of the d3-sankey library to allow circular links.
MIT License
89 stars 41 forks source link

graph not using full height if only one circular link is present #9

Closed tomshanley closed 6 years ago

tomshanley commented 6 years ago

Updated the breadth function to start positioning nodes from the top, if there are

Else, if there's both top and bottom, position in the vertical centre

tomshanley commented 6 years ago

Also need to update the relax function, which has the effect of condensing the nodes together, and downwards, if there no ciruclar links at the top.

tomshanley commented 6 years ago

Proposed solution is to

emeeks commented 6 years ago

I wanted to clean up semiotic so it only relied on d3-sankey-circular and not d3-sankey, too, so I added the following function, which seems to handle cases where there are no circular links or only links on the bottom (which come back with half-height sankeys). I'm posting the code here not so that you'll integrate it, because it's a hack, but because it might point you to where the problem might be.

Basically, I run the sankey once just to see if there are circular links and if there are no circular links at all, I double the y extent of the layout, and if there are only bottom links, I double the extent minus the width of those bottom links. That produces good results.

//Temporary fix for when sankey-circular sets the size incorrectly
        const initialSettings = actualSankey()
          .extent(frameExtent)
          .links(projectedEdges)
          .nodes(projectedNodes)
          .nodeAlign(sankeyOrient)
          .nodeId(nodeIDAccessor)
          .nodePadding(nodePadding)
          .nodeWidth(nodeWidth)
          .iterations(1)

        initialSettings()

        const circularEdges = projectedEdges.filter(d => d.circular === true)

        if (circularEdges.length === 0) {
          frameExtent = [
            [0, -frameExtent[1][1]],
            [frameExtent[1][0], frameExtent[1][1]]
          ]
        } else if (!circularEdges.find(d => d.circularLinkType === "top")) {
          const bottomEdges = circularEdges.filter(
            d => d.circularLinkType === "bottom"
          )

          const offset = bottomEdges
            .map(d => d.circularPathData.leftLargeArcRadius)
            .reduce((p, c) => p + c)
          frameExtent = [
            [0, -frameExtent[1][1]],
            [frameExtent[1][0], frameExtent[1][1] - offset]
          ]
        }
        //End temporary

        const frameSankey = actualSankey()
          .extent(frameExtent)
          .links(projectedEdges)
          .nodes(projectedNodes)
          .nodeAlign(sankeyOrient)
          .nodeId(nodeIDAccessor)
          .nodePadding(nodePadding)
          .nodeWidth(nodeWidth)
          .iterations(iterations)

        frameSankey()
tomshanley commented 6 years ago

Thanks - I'll need to make this a lot better

tomshanley commented 6 years ago

Fixed - after the layout functions complete, a check is performed on the distribution of nodes y0 y1 and stretches them out to fill the available height