Experiments in Responsive D3

PROJECT INFO

Ongoing experiments in how to code responsive visualizations with D3 - basically, how to write better code. Tools include Rhino, Excel, Javascript, HTML/CSS.

OVERVIEW

I’ve been using D3 on and off for about 4 years, creating custom visualizations and tools for building performance analysis. The library is such a powerhouse. As a non-web developer though, I usually display these visualizations in a controlled environment–as part of a client presentation or as a graphical output from a desktop program like Rhino. I rarely have to worry about changing screen sizes, or even about optimizing the code for cross-browser support and speed. Recently I decided to give myself a challenge and design something that is more versatile. I decided to recreate one of my favorite tools, the psychrometric chart, as a responsive visualization with some added functionality like scrubbing, filtering, and file-drops.

BACKGROUND

Up until last year, I didn’t spend a lot time planning out my code. There were far too many global variables, and I kept everything in one massive JS file. For the most part this worked well for simple visualizations with limited interactivity. However, as I started creating more complex visualizations, I needed much more control. In 2014, I worked with MIT on a tool to forecast carbon emissions, which was largely based in Excel but contained a few outputs to D3 via VBA. The visualizations were pretty simple, but they contained a few elements that needed tighter variable scoping. This was the first time I had to rely on closures to get the job done.

Using closures was the only way to design the pie chart overlay. The chart inherits data from each rectangle element (actually the containing g element) but is otherwise a completely self-contained visualization.

Even though the visualization isn't responsive, this project got me to write better code. As a non-programmer I didn’t realize the importance of keeping things modular, and only had a syntactical sense for how to employ object oriented or functional programming.

CHALLENGE

I decided I needed a project that would force me to use D3 more strategically. There were a few things that I wanted to specifically accomplish: First, I wanted to make the visualization responsive and fully functional on all major web browsers. Second, I wanted to make the visualization truly reusable. In other words I wanted to be able to drag a new data file onto the browser window and have the visualization update. At the time, I had a critical need for a new psychrometric weather tool that could read EPW files, so that became the focus of this project.

A psychrometric chart is “A graph of the thermodynamic parameters of moist air at a constant pressure, often equated to an elevation relative to sea level.” The chart is an awesome design tool in and of itself, but also an interesting challenge to create using D3, since all of the lines and limits are calculated from air pressure, which changes by elevation. Therefore, I needed to rely on methods within the main chart function, the closure, to dynamically draw the lines when the chart resizes or when a user drops new data onto the chart. The setup for all of this is really straightforward:

/*
helper functions
chart function
psychrometric functions (from ASHRAE Fundamentals)
globe function
*/ 

$(document).ready(function() {
     var chart = new psychrometricChart();
     d3.text("data/EPW_file.epw", function(data) {             d3.select("#chart").datum(formatEpw(data)).call(chart);
     });
     $(window).resize(chart.resize);
     //could read breakpoints instead
});

At this point there isn't any error checking in the formatEPW() function. This allows for a little more flexibility if you want to use the chart for something other than purely viewing EPW files. However, the drag-and-drop functionality works better than I expected, even if the EPW files take a few seconds to load up. A simple fix from a UX point of view would be to add some text that let's users know that the file is loading.

The whole project is on github here. With 8760 data points, it gets little slow in Safari and Internet Explorer, but it works reasonably well in Chrome. Still, it’s a little janky. A friend suggested that I use Canvas to plot the hourly points. A better solution might be utilizing a queue or a quad tree to speed up the filtering process, or rendering the points in batches. I think this might do the trick. I’ll post an update when I find a good solution. Another fix for the lag (when resizing the screen) would be to strictly limit the chart.resize function to only those times when the containing element is resized. Currently, the resize function is triggered with each window resize, regardless of whether the containing element actually changes given the breakpoints on the site.