Here’s a quick example, where the layout of a chart is defined using SVG and flexbox via the
And here’s a chart that makes use of the above layout:
If you’ve ever wanted to plot a chart or create a visualisation, you will no doubt have come across D3. The power and versatility of this framework has resulted in it becoming one of the most popular repositories on GitHub.
D3 excels at transforming data into SVG or HTML elements, allowing charts to be constructed with very little code. However, D3 does little to help with the more mundane task of layout; the positioning of axes, labels, the legend etc …
Mike Bostock (D3’s creator) has published a simple Margin Convention which he uses in his own examples. As you can see from the code below the simple task of applying a margin around the chart requires some fiddly maths:
Once you start adding axes, titles or a legend things really start to get out of hand …
To be fair, this isn’t really a fault of D3, the problem of layout simply isn’t within the remit of this library.
With SVG elements are positioned using a simple coordinate system, which also doesn’t help us much when trying to construct a suitable layout.
Whilst battling with this problem, my colleague Chris Price came up with a great idea, why not apply the flexbox layout algorithm to SVG? HTML and CSS have a number of different techniques for constructing layouts - if one of these could be applied to SVG it would make it possible to construct a chart without all of the manual computation seen above.
Applying Flexbox to SVG
The interface for Facebook’s
css-layout couldn’t be simpler, given a tree of nodes with associated CSS attributes, you invoke
The resultant layout is computed after which each node is given a
layout property that describes its width, height and location with respect to the parent node:
Applying this technique to SVG is as simple as associating a style with each SVG element. This can be done by adding a custom attribute,
The following code constructs a suitable node-tree from the above SVG:
I have omitted the
parseStyle function which parses the
Once the node tree has been constructed and the layout computed, all that remains is to apply this layout to the SVG. The
left layout properties are applied as a transform, whereas the
width are written to
layout-width attributes respectively. The reason for this is that SVG group elements (
g) have an origin but do not have a width or height. In order for a child element to occupy the rectangle defined by the layout mechanism, they need some way to obtain the computed bounds.
The following puts it all together as a function that can be called on a D3 selection
Applying flexbox layout to a selection is now as simple as the following:
With the simple SVG example above, the layout mechanism writes the required transforms, widths and heights as follows:
Creating a chart layout
Here’s a more complex example that shows how this technique can be applied to construct a suitable layout for a chart with a title, axes and legend:
The following code applies the flexbox layout algorithm, then adds a rectangle to each of the containers that have been constructed in order to help visualise the results:
This results in the following layout:
Computing the above armed with nothing more than the ‘margin convention’ would be quite a painful process!
It was a great coincidence that the ReactJS Native development resulted in the open-sourcing of exactly the component I needed for applying flexbox to SVG. If you are interested in using this code, you can find it within the D3FC repository. This is a project with a wider goal of making it easier to construct complex financial charts using D3. Our aim is to construct components that enhance D3 rather than wrap it (which would take most of its power away).
Anyhow, more on D3FC later …
Regards, Colin E.