Question: Is it possible to make a single page web application that uses CSS to layout the page and still have your d3 charts know when to update their size/appearance?
If the visualization is running inside a web application created with something like Sencha ExtJS or Dojo, you can utilize the event mechanisms that these libraries provide in their widget infrastructures. For example, in Dojo you can layout the interface using a BorderContainer which holds multiple ContentPanes. You can then listen for the ContentPane’s resize event to know when to update the d3 chart it contains. In the example below, you see two resizable pie charts in a Dojo split container. Then you move the splitter, each pie chart hears the resize event fired by its parent ContentPane and it updates its own size accordingly:
Approach 2: Listen to window.resize or use jQuery to dispatch events
If you have CSS handling the layout of your DOM elements, you could update your d3 charts by listening for resize events from the browser window. You can find this approach suggested in a few posts as a standard way to make the chart “responsive”. This is not a bad solution if it suits your need, but I personally find it has some undesirable side effects. Ideally, your d3 chart would only resize when the parent DOM element does. If you are using dynamic components (i.e. accordion containers, etc) that resize without changing the size of the browser itself, the window’s resize event may not fire unless someone has gone through the trouble of triggering that event manually. Another problem with only listening for the browser resize event is that if you have several visualizations in your application, they could all be resizing in response to the window event whether it is truly necessary or not.
Take the following example. Using jQuery and a reusable d3 pie chart, we have a visualization set inside a resizable container. The pie chart listens to the window.resize event to know when it should update itself. Try resizing each container and you will notice that neither pie chart adjusts its size. Only when the window is resized do the charts perform an update: (click on the “Edit on CodePen” link in the right corner of the demo to launch it separately to see the pie charts resize when the browser window is adjusted. The embedded version in this post cannot see these events)
My point is that your d3 chart will not resize if you only listen to window events and the DOM resizes for some other reason. In this second example, I instead listen for the resize event on the container created by jQuery.
This is better but we still are not using a CSS-only approach to handle the layout of the DOM. The goal here is to use CSS for the layout and still have the d3 chart know when a resize is required.
Approach 3: CSS Layouts
I came across a project by Marc Schmidt that might offer a solution. Using the ResizeSensor I was able to setup a relatively lightweight listener that fires when the containing DIV is resized. This in turn notifies the d3 chart that it needs to update. The following demo shows 2 reusable treemaps displayed within a CSS flowbox container. For the sake of the demo I added a jQuery resizable container to allow you to see what happens when the flexbox layout adjusts the size of the containers holding the treemaps: (doesn’t work cleanly in IE yet)
Using a ResizeSensor, we respond to the parent DOM element being changed by the Bootstrap layout. jQuery’s resizable container is only used to let you trigger that Bootstrap layout update for the sake of the demo.
If anyone can add to this discussion or find oversights in my approaches, I would love to get your feedback. 🙂