d3 Wrapping Flow Tree Layout

By | October 11, 2013

One d3 visualization I’ve been refining for a while now uses a flowing tree layout. I wanted to have a structure similar to the standard d3 tree layout which would position consistently-sized leaf nodes (children) in a recursively flowing (wrapping) arrangement. I also wanted to take a stab at building this layout as a library that followed the examples set forth in discussions of the ‘Reusable Charts’ pattern that has been such a hot topic lately. There are many great libraries out there that have attacked this problem in various fashions and it will take me a while to determine which one makes the most sense for my purposes. In the meantime, I wanted to share what I’ve come up with for a flowing tree chart:

Resizable Flow Tree (Expand/Collapse nodes & resize using space between chart and scrollbar)

Features:

Flow Layout
I’ve taken the logic from the d3 tree layout and adapted it to recursively size and space out the children of each container given the available width. What you end up with is a flowing version of the Indented Tree example.

Resizable Visualizations
The chart will update its layout when it is resized (Try it by putting the mouse cursor just the left of the scrollbar and resize the container and watch the layout do its thing). Most d3 examples that I have come across do not address resizing issues at all, something that is not surprising given the complexity involved. I’ve seen many developers asking about ways to create resizable charts in d3 and in most cases the replies suggest that they scale the SVG contents to fit the available space within the viewport. Personally, I do not find this very useful. Instead, I want to keep the size of the visualization constant (i.e. legible) and reapply the layout to make use of the available space and adjust the scrolling size as necessary.

Expanding and Collapsing Groups
The layout includes a variation of the expand/collapse logic found in the Indented Tree example. It also adjusts the container’s scroll size based on the updated chart height once expand/collapse actions have changed the size of the chart.

Recursive Layout
I’ve come across a few examples that feature wrapping style layouts, but what they did not address is recursive containment. They would not measure and layout containers within containers. This flow layout walks the hierarchy, sizing and positioning groups within groups as well as their children.

Possible Enhancements
There were a couple of ideas that I did not get time to implement yet. It might be nice to allow the children to vary in size. I may also look into justifying the children contained with each row rather than leaving the unused space tacked onto the right edge.

Related Links:
Stand alone demo of the visualization shown above
Gist showing the flow tree that resizes with the containing div. (same as shown in this blog post)
Flow Tree that resizes with the browser window
Gist showing the flow tree that resizes with the window

15 thoughts on “d3 Wrapping Flow Tree Layout

  1. Hayden Livingston

    This is _almost_ exactly what I need – I don’t want these groupings — maybe have a config option to disable them. As well as the fact that I want all children of the tree to have the same width as the parent, i.e. all nodes have the same effective size (obviously the deeper you go the less width there is for each node).

    How tough would that be?

    Reply
    1. Bill Post author

      I’m a little confused about what you’re trying to do. What did you mean when you said “I don’t want these groupings”? Since this is a tree, it inherently has recursive groups so I’m not sure what you’re trying to change. The second part about all nodes having the same effective size sounds like you are trying to achieve something like the indented tree example where each child has the width of the parent (less the indentation affordance). Can you elaborate a little more on what you’re trying to do?

      Reply
      1. Hayden Livingston

        Ok. I want the leaf nodes (ones without children) to be treated the same way as their parents do. That is they get put on their own line.

        Secondly, You artificially reduce the width of the children elements and put a border around them. I’d like to not do that.

        Thirdly, I’d like them to be in their own rows, and the background of the parent to not encompass the children.

        Lastly, I want to add columns to this beautiful thing!

        Reply
        1. Bill Post author

          Ok. I want the leaf nodes (ones without children) to be treated the same way as their parents do. That is they get put on their own line.

          I kind of get where you are going, but this particular demo is designed to demonstrate a flow layout which, by definition, has multiple children on each line which flow to the next line based on the available space. I’m wondering if you want something closer to this demo which is based on the d3 indented tree demo I mentioned earlier.

          Secondly, You artificially reduce the width of the children elements and put a border around them. I’d like to not do that.

          You can remove the spacing by adjusting the padding variable in the code.

          Thirdly, I’d like them to be in their own rows, and the background of the parent to not encompass the children.

          You can remove the code that sets the fill color style on the nodes to remove the backgrounds and then remove the stroke styling in the CSS to get rid of the borders and give it the appearance that there is no containment.

          Lastly, I want to add columns to this beautiful thing!

          That feature would depend upon what you want the columns to be based on. It almost sounds like you are trying to recreate a spreadsheet of some sort. Not sure how to modify this demo to get there since this is designed to demonstrate a flowing layout.

          Reply
          1. Hayden Livingston

            Yes, it is very much like a “tree” spreadsheet! Will look over to find more examples on the net.

  2. Gene

    I really like your tree implementation and it fits what I need in my application, but I am trying to include it inside an svg and not a div. How can I modify your code to do it?
    Thanks,
    Gene

    Reply
    1. Bill Post author

      Not really sure what you mean by “trying to include it inside an svg and not a div”. Can you describe that in a little more detail?

      Reply
      1. Gene

        Bill,
        I have an app with two trees on the left and the right side of the screen. I need to drag a mouse and connect tree elements from two opposite sides. Currently I have three segments like this and it works great, but I can only draw a link in the middle side and can not span the link across three different ‘divs’:

        What I need is ability to draw a line and create links between two trees on the opposite side. And for that I need to put both tables (trees) on one SVG canvas so I can draw a line between any nodes in the tree. So I see the page content looking like this:

        So I can draw a link on the “main” svg.
        When I try to implement it using the tree code I get an error that has to do with the width.. Hope this is clear..
        Do you have any suggestions?
        Thank you,
        Gene

        Reply
        1. Bill Post author

          I understand that you’re wanting to not have the layout create the SVG for you but instead just put the flow layout inside the container. I’ve created a gist that shows how you might modify the flow layout code to do this. 🙂

          Reply
          1. Gene

            Hi Bill,
            Thanks again for the single canvas implementation of this tree. It works just like I want it, but when I tried it of firefox (I have been using chrome all this time) the image displayed is cut and only a portion of the trees is visible. Is there anything I can do so it works on firefox as well?
            Best regards,
            Gene

          2. Bill Post author

            Gene,

            Are you referring to the code from this Gist? If so, I think the issue was that I needed to set a width/height style on the svg container. I updated the Gist accordingly so let me know if that fixes your issue. 🙂

            Bill

          3. Gene

            Bill,
            I just downloaded your code from this Gist and it ran fine on FF and Chrome.
            Thanks again,
            Gene

  3. Gene

    Bill,
    I just downloaded your code from this Gist and it ran fine on FF and Chrome.
    Thanks again,
    Gene

    Reply
    1. Bill Post author

      I would think the approach would involve using the d3 hierarchy layout to generate links and then overlay the connecting lines accordingly. This demo shows the links and you would just append them over the top of the diagram (https://bl.ocks.org/mbostock/4063570); that is just a thought off the top fo my head…..

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *