design pattern

for creating data

visualizations

with D3 & Angular


Nicholas Ortenzio

twitter: @p_arithmetic

github: youbastard



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 data-driven approach to DOM manipulation



AngularJS is what HTML would have been, had it been designed for building web-apps. Declarative templates with data-binding, MVW, MVVM, MVC, dependency injection and great testability story all implemented with pure client-side JavaScript


Initial Approach To using

d3 in an angular app

Put your D3 stuff inside a controller and call it a day.

Unhappy with this approach because


  • It does not really take advantage of any Angular JS features
  • Angular models / inputs that can alter are chart are not managed by D3
  • No communication between frameworks
  • Creating XML nodes in JavaScript drives me crazy

reasons why Creating XML nodes

in JavaScript drives me crazy



  • Views and templates are a thing, its like the main reason for using Angular in the first place
  • Does not intuitively describe the result
  • Gets very messy and confusing

Alternative Approach




  • Use D3 for the mathy stuff (if you even need it)
  • Use Angular for the everything else

A simple bar chart



Notes




  • ng-repeat through data. this is the easiest way to create distinct objects like rectangles, lines, circles and groups
  • Use ng-attr-<attributename> or else the browser will complain
  • If the data updates, so will the graph.

First Issue


Axes are a problem

Creating an axis returns a function that gets called directly from a selection.



Solutions


1. My initial approach was to create and Angular directive


Solutions


1. Create an Angular directive



This works I guess but I think it's over complicating the issue

Solutions


2. Alternative approach to rendering axes - Cheat


  <g transform="translate(20,20)"> 
<g class="x axis" ng-attr-transform="translate(0, {{ height }})"></g>
<g class="y axis">
<text transform="rotate(-90)" y="6" dy=".71em" style="text-anchor:end;">Price</text>
</g>
</g>

  $scope.xAxis = d3.svg.axis().scale($scope.x).orient("bottom");
$scope.yAxis = d3.svg.axis().scale($scope.y).orient("left"); $scope.xAxis(d3.select('.x.axis'));
$scope.yAxis(d3.select('.y.axis'));

This works just as well

Next Issue


Okay so barcharts and scatter plots are easy, but what about

charts that arent a 1:1 representation of data?


  • Line charts
  • Area charts
  • Polygons
  • Topographic charts
  • Hexagonal Binning
  • Heat maps
  • etc...

Solution


Many chart types work by accepting data and returning a path


area

area = d3.svg.area()
    .x(function(d) { return $scope.x(d.date); })
    .y0($scope.height)
    .y1(function(d) { return $scope.y(d.close); });

$scope.areaPath = area($scope.data);
geo
path = d3.geo.path().projection(projection);   
$scope.ocean.path = path($scope.ocean.data); 

...which you can render
<path d="{{ path }}" />


Hexbin


   $scope.hexbin = d3.hexbin()
.size([width, height])
.radius(10);

<path ng-repeat="(i, hex) in hexs" 
   ng-attr-d="{{ hexbin.hexagon() }}" 
   ng-attr-transform="translate({{ hex.x }}, {{ hex.y}})" 
   ng-attr-style="fill: {{ color(hex.length) }}" 
   class="hexagon" />






Basically, having a deep understanding of how all

the D3 chart types work

is key to using them without D3

Further exploration




  • Brushes
  • SVG view box
  • Transitions with ng-animate
  • Deeper understanding of Joins (enter / update / exit)

Thank you



Slides

https://slides.com/nonononono/using-d3-with-angular-js/


Examples

http://downwith.us/semplica


Source

https://github.com/youbastard/semplica

Made with Slides.com