Hackpads are smart collaborative documents. .

Nate Strauser

514 days ago
Unfiled. Edited by Nate Strauser 514 days ago
Nate S Meteor Cookbook: Reactive D3 Visualizations
Cyntia C Live Demo - Demo Source
Nate S
  • 0. Introduction to D3
  • D3.js is a JavaScript library for manipulating documents based on data. D3 helps you bring data to life using HTML, SVG and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a Interactive Data Visualization for the Web data-driven approach to DOM manipulation.
As D3 is a well established library, we won't go very deep into D3 specifics in this article, but rather focus on how to properly utilize D3 in Meteor applications with full reactivity.
The good news is that D3 integrates very well with Meteor applications to create collection driven visualizations. Only minor changes are needed to adapt most D3 examples to be fully reactive to any data changes. Since D3 directly manipulates the DOM to create the data visualization, the Meteor rendering engine (Blaze) is not very involved in the actual rendering as D3 handles the creation and manipulation of SVG elements which make up the visualization. Meteor covers everything but the rendering as it manages the backing data, orchestrates the reactive updates, and binds events to the visualization elements.
D3 Resources
The web version of Interactive Data Visusource of the alternative version of the scatter plotalization for the Web is an excellent and in depth resource covering the most common use cases of D3. (Several of the example graphs were adapted from this source)
Since D3 can be used to produce wide array of data visualizations, a good way to start on building your own is to look over the many high quality examples and find one that is close to what you are looking for. A multitude of excellent example graphs can be found in the following galleries: https://github.com/mbostock/d3/wiki/Gallery, http://bl.ocks.org/mbostock
The D3 API Reference can be a useful resource when working with D3.
Nate S
  • 1. Common Chart Types
In the demo application for this article we have provided example code for most basic chart types common in web applications. Each of these charts is fully reactive to data changes in documents, adding or removing documents, and sorting.
Andrew M
  • The approach in this document seems to only work with documents that are bound directly to DOM elements. It doesn't work when data is post-processed with `d3.nest` followed by a `d3.layout`, for example - which are often required for more advanced aggregate visualizations. However, doing the aggregate operations continuously may be doable if the underlying data array is updated efficiently; see comment below.
Nate S Pie Chart - Source
Scatter Plot - Source
Line Chart with Time Data - Source
  • 2. Base D3 Integration Pattern
We will use the bar chart example to talk about the basic pattern used to integrate D3 into a Meteor application. This same basic pattern was used for all common chart examples and should be extendable to any D3 visualization within a Meteor application.
We start by defining an empty SVG element in template markup
  • <svg id="barChart"></svg>
Not much here at all, this is really just a placeholder for D3 to do its work.
All D3 code goes in the rendered callback for the template. Some code has been omitted using ... for brevity and to more clearly illustrate the pattern.
  • Template.barChart.onRendered( function(){
Meridian W
  •     //I thought .rendered is deprecated? Correct. Updated.
Nate S
  •     //define constants, height/width
  •     ...
  •     //define scales and axes
  •     ...
  •     //define key function to bind elements to documents
  •     ...
  •     //define the SVG element by selecting the SVG via its id attribute
  •         ...
  •     //declare a Deps.autorun block
  •     Deps.autorun(function(){
  •         //perform a reactive query on the collection to get an array
  •         var dataset = Bars.find(...).fetch();
  •         //update scale domains and axises
  •         ...
  •         //select elements that correspond to documents
  •         var bars = svg.selectAll("rect")
  •             .data(dataset, key); //bind dataset to objects using key function
  •         //handle new documents via enter()
  •         bars.enter()
  •             .append("rect")
  •             ...    
  •         //handle updates to documents via transition()
  •         bars.transition()
  •             ...
  •         //handle removed documents via exit()
  •         bars.exit()
  •             ...
  •             .remove();
  •     });
  • });
Following this basic pattern allows for relatively straightforward refactoring of most D3 examples to be driven via Meteor collections. The key part is separating the D3 code into what gets run once to initiate the visual (before the Deps.autorun block) and what gets run on each collection query result change (inside the Deps.autorun block).
Andrew M
  • This seems like it will only work with very small datasets. `cursor.fetch()` deep copies all documents when it is called, so this will be extremely slow. It seems like the best approach is to create a single reactive array that is updated using `cursor.observe`, specifically using the `addedAt` and `removedAt` callbacks, which can then be repeatedly joined with `selection.data` in D3. This basically accomplishes the same effect as repeatedly calling `fetch()` without the huge CPU and memory usage of a large collection, and could be easily implemented as part of a d3 helpers package.
Nate S It is also possible to use observe instead of Deps.autorun, see alternative opalternative optionstions.
Driving Updates with Document Changes
We want our visualization to update reactively whenever there is a change in the results of the collection query, contained in the variable dataset.
  • var dataset = Bars.find(...).fetch();
946 days ago
Unfiled. Edited by deep yadav 946 days ago
Once we have documents inserted with Date properties, we can use other Date objects as Mongo semeteor.hackpad.comlectors in a collection query.

Contact Support

Please check out our How-to Guide and FAQ first to see if your question is already answered! :)

If you have a feature request, please add it to this pad. Thanks!

Log in