Author Archive

So, you started building charts with D3 and quickly realized there are certain behaviors you want all of your charts to have. Being the excellent developer you are, you decided to wrap the basics up in a nicely packaged, reusable bit of code that will help you build charts faster in the future.

For our team, this meant creating a simple Backbone view to encapsulate all of our charts’ must-haves. Why Backbone? Because we like it, though you can certainly accomplish all of what you’ll see here with a jQuery plugin or your own homebrew JavaScript lib.

Here’s how you can use it.

Simple bar chart

Just an example of a simple bar chart. If you’re not familiar with the code below, you’ll want to check out Michael Bostock’s Let’s make a bar chart.

At this point you’ve created a single, crappy little bar chart and you can hardly contain your joy. You can’t deny your desire to plaster these things all over your site. You WILL make this code reusable. Soon you will have loads of these things EVERYWHERE.

Before you do, however, consider a few things that might make your crappy little bar chart a little less crappy. You need:

Responsiviosity, responsiveness, responsivity — whatever you call it, it’s a way to redraw the chart when the window resizes

A simple way to extend and modify your chart to create different versions

A way to vary the appearance of the chart at certain viewport breakpoints

A fallback mechanism for browsers that don’t support D3

Enter ChartView.js — a simple Backbone view put together by my teammate David Eads to address these very needs.

First thing we do is define `BarChartView` by extending `ChartView`. The only function we must override is the `draw` member function of `ChartView`. The code within our `draw` function looks a lot like the code we wrote to render our simple chart, but it takes advantage of some of the values that `ChartView` calculates and tracks for us. For example, instead of defining a `width` variable, we use `this.dimensions.width,` which is calculated based on the chart’s parent element.

The next thing we do is create a new instance (or two, or three, etc — remember charts EVERYWHERE) of our `BarChartView`. The minimum you need to get started is an options object with `el` and `data` or `collection` defined (note: you can only use one of `data` or `collection` with views that extend `ChartView` — not both).

If you resize your browser, you’ll see these charts are now responsive. At viewport breakpoints of 420 and 728 pixels wide, the height of the charts’ containers will be adjusted to 0.7 and 0.9 of the base_height option we passed when creating them. These breakpoints are, of course, customizable:

I know what you’re thinking. The examples are awesome, but yo, you don’t even use SVG for these charts. How about showing some real code?

You’re right. To show how to use this in a real life scenario, I thought I’d refactor some of the code we wrote for our Broken Bonds series. Trust me when I tell you you don’t want to see the original code. You can, however, see the refactored code by clicking here. Look at this code in action below.

The `y_key` is used to determine which key to pluck from each item in our dataset to draw the chart’s bars. The `y_scale_max` option is used to adjust the maximum value that can be plotted on the chart — in this case, $7,000.

Also, notice we’re specifying a `collection`. When this option is present, `ChartView` will bind to the collection’s “sync” event, triggering a re-rendering of the chart any time the collection data changes. A big yay for events!

I won’t go through ObligationDebtChartView.js line-by-line. What’s important here is that the process is the same regardless of how complex your chart’s D3 render code is.

We have our draw function, which calls a handful of other functions that do the heavy D3 lifting. Our chart is responsive — the bars squish as the viewport is constrained and axis labels change to be legible on smaller screens.

Fallback for older browsers

One last thing to cover — `ChartView` checks whether the browser supports D3 and will display a message if it does not.

If you love WordPress and like what you’re reading here, you should work with us.

The past four months have been one big, nasty, non-stop, face-melting, brain-bending WordPress sprint for Ryan Mark and myself. We’ve been working on the migration and relaunch of ChicagoNow and finally kicked the site out the door on June 30. Please, have a look: www.chicagonow.com.

Along the way (read: from the very start), there were things about WordPress that we desperately wanted to be different.

Specifically, we hated writing WordPress themes.

As you may know, WordPress places no constraints on where you to put your business code. You can do complex stuff anywhere in your templates, right alongside presentation code. This makes templates really hard to read and prone to bugs. Maintainability of the code (and your quality of life) suffers.

Being the anti-freedom, inflexible, stubborn jerks that we are, we hijacked WP’s built-in template stuff along with all of its baked-in rewrite rules. In their place went Twig and a 30-line URL resolver. In order to make it easier for our Backbone.js app to interact with the WP database, we wrote a simple, consistent wrapper for WordPress patterned after Backbone.js’s models.

What we ended up with is a simple Django and Backbone inspired framework for building heavily-customized WordPress sites.

Over time, we compiled a list of all the WordPress functions we needed to get things done. Nothing more, nothing less. And any time we try using a function that is template-prohibited, a fatal PHP error serves as a reminder of what we wanted to accomplish with MTV.

About our models

Here’s an example view using our PostCollection model to get recent posts:

Our PostCollection is passed to our template and we use a Twig for loop to display the title and content of each Post model in the collection.

Note that the $args array passed to PostCollection::filter() is exactly the same array you would pass to WP_Query() to get recent posts. The difference is that returned objects are more robust (for example, all post meta/custom fields are included as attributes of returned posts) and have methods consistent with those found in Backbone.js models (for example, get(), fetch(), set(), save()).

Also note that these Backbone-like methods do exactly what you think they do. You don’t have to remember the 101 different WordPress functions related to post objects and the variety of possible return values.

Fetch a post, get an attribute, set an attribute, save the post. Done.

One more thing to note: these models include two special methods for shuttling data back and forth between the client and server: $model->to_json() — used to send jsonified model data out to the frontend, and $model->from_json() — used to create a new model from json data sent to the backend.

I’ll leave the details of how we used these models with Backbone for a later post, but hopefully that gives an idea of how awesome these things are.

While we don’t have code ready to be open sourced just yet, we plan on doing so in the future, so stay tuned. In the meantime, we’d love to hear questions and feedback.