Reacting™ & D3® Charting

First of all, please let me say this, React is designed for us native developer!(because of the similar API, lifecycle things…).

Long long ago, when Facebook tries to use HTML5 technology to build the mobile version of Facebook, it turns out to be a failure, at that time, there are not so many choices of front-end modularization framework to choose from.

But no pains, no gains.

I guess Facebook learns from it, and I guess they actually learn a lot from the process. Since then Facebook spend a lot of energy on iOS.(like building the very famous Paper™ APP)

So my point is, if there’s gonna be one technology to rule the mobile & web platform, that’s gonna be build by Facebook XD.

Flux

1
2
3
4
5
6
7
8
// some fancy usage in dispatcher, this looks awesome...
case 'BUY_SHOES':
AppDispatcher.waitFor([
ShoeStore.dispatcherIndex
], function() {
CheckoutStore.purchaseShoes(ShoeStore.getSelectedShoes());
});
break;

D3 Overview & concept

lower lever API, but more control

Behaviors - reusable interaction behaviors

Core - selections, transitions, data, localization, colors, etc.

Geography - project spherical coordinates, latitude & longitude math

Geometry - utilities for 2D geometry, such as Voronoi diagrams and quadtrees

Layouts - derive secondary data for positioning elements

Scales - convert between data and visual encodings

SVG - utilities for creating Scalable Vector Graphics

Time - parse or format times, compute calendar intervals, etc.

g

The g element is a container used to group objects. Transformations applied to the g element are performed on all of its child elements. Attributes applied are inherited by child elements. In addition, it can be used to define complex objects that can later be referenced with the element.

d3.select(selector)

Selects the first element that matches the specified selector string, returning a single-element selection. If no elements in the current document match the specified selector, returns the empty selection. If multiple elements match the selector, only the first matching element (in document traversal order) will be selected.

D3 + React

https://github.com/codesuki/react-d3-components

Let React have complete control over the DOM even when using D3. This way we can benefit from Reacts Virtual DOM.

https://github.com/esbullington/react-d3

With this approach, React itself is responsible for generating the SVG markup. d3.js is used for its tremendous collection of utility functions, such as those that calculate the path value for various chart types.

d3 example

From http://bl.ocks.org/mbostock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
max-width: 640px;
margin: 40px auto;
}
input {
width: 100%;
}
</style>
<input type="range" min="0" max="1000" step="1" value="0">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
d3.select("input").transition()
.duration(7500)
.tween("value", function() {
var i = d3.interpolate(this.value, this.max);
return function(t) { this.value = i(t); };
});
</script>

<!DOCTYPE html>

http://bl.ocks.org/mbostock/c501f6cae402ab5e90c9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var data = [1, 1, 2, 3, 5, 8, 13, 21];
var width = 960,
height = 500,
radius = height / 2 - 10;
var arc = d3.svg.arc()
.innerRadius(radius - 40)
.outerRadius(radius)
.cornerRadius(20);
var pie = d3.layout.pie()
.padAngle(.02);
var color = d3.scale.category10();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
svg.selectAll("path")
.data(pie(data))
.enter().append("path")
.style("fill", function(d, i) { return color(i); })
.attr("d", arc);
</script>

<!DOCTYPE html>










1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
form {
position: absolute;
top: 1em;
left: 1em;
}
path {
fill-rule: evenodd;
stroke: #333;
stroke-width: 2px;
}
.sun path {
fill: #6baed6;
}
.planet path {
fill: #9ecae1;
}
.annulus path {
fill: #c6dbef;
}
</style>
<form>
<input type="radio" name="reference" id="ref-annulus">
<label for="ref-annulus">Annulus</label><br>
<input type="radio" name="reference" id="ref-planet" checked>
<label for="ref-planet">Planets</label><br>
<input type="radio" name="reference" id="ref-sun">
<label for="ref-sun">Sun</label>
</form>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
radius = 80,
x = Math.sin(2 * Math.PI / 3),
y = Math.cos(2 * Math.PI / 3);
var offset = 0,
speed = 4,
start = Date.now();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(.55)")
.append("g");
var frame = svg.append("g")
.datum({radius: Infinity});
frame.append("g")
.attr("class", "annulus")
.datum({teeth: 80, radius: -radius * 5, annulus: true})
.append("path")
.attr("d", gear);
frame.append("g")
.attr("class", "sun")
.datum({teeth: 16, radius: radius})
.append("path")
.attr("d", gear);
frame.append("g")
.attr("class", "planet")
.attr("transform", "translate(0,-" + radius * 3 + ")")
.datum({teeth: 32, radius: -radius * 2})
.append("path")
.attr("d", gear);
frame.append("g")
.attr("class", "planet")
.attr("transform", "translate(" + -radius * 3 * x + "," + -radius * 3 * y + ")")
.datum({teeth: 32, radius: -radius * 2})
.append("path")
.attr("d", gear);
frame.append("g")
.attr("class", "planet")
.attr("transform", "translate(" + radius * 3 * x + "," + -radius * 3 * y + ")")
.datum({teeth: 32, radius: -radius * 2})
.append("path")
.attr("d", gear);
d3.selectAll("input[name=reference]")
.data([radius * 5, Infinity, -radius])
.on("change", function(radius1) {
var radius0 = frame.datum().radius, angle = (Date.now() - start) * speed;
frame.datum({radius: radius1});
svg.attr("transform", "rotate(" + (offset += angle / radius0 - angle / radius1) + ")");
});
d3.selectAll("input[name=speed]")
.on("change", function() { speed = +this.value; });
function gear(d) {
var n = d.teeth,
r2 = Math.abs(d.radius),
r0 = r2 - 8,
r1 = r2 + 8,
r3 = d.annulus ? (r3 = r0, r0 = r1, r1 = r3, r2 + 20) : 20,
da = Math.PI / n,
a0 = -Math.PI / 2 + (d.annulus ? Math.PI / n : 0),
i = -1,
path = ["M", r0 * Math.cos(a0), ",", r0 * Math.sin(a0)];
while (++i < n) path.push(
"A", r0, ",", r0, " 0 0,1 ", r0 * Math.cos(a0 += da), ",", r0 * Math.sin(a0),
"L", r2 * Math.cos(a0), ",", r2 * Math.sin(a0),
"L", r1 * Math.cos(a0 += da / 3), ",", r1 * Math.sin(a0),
"A", r1, ",", r1, " 0 0,1 ", r1 * Math.cos(a0 += da / 3), ",", r1 * Math.sin(a0),
"L", r2 * Math.cos(a0 += da / 3), ",", r2 * Math.sin(a0),
"L", r0 * Math.cos(a0), ",", r0 * Math.sin(a0));
path.push("M0,", -r3, "A", r3, ",", r3, " 0 0,0 0,", r3, "A", r3, ",", r3, " 0 0,0 0,", -r3, "Z");
return path.join("");
}
d3.timer(function() {
var angle = (Date.now() - start) * speed,
transform = function(d) { return "rotate(" + angle / d.radius + ")"; };
frame.selectAll("path").attr("transform", transform);
frame.attr("transform", transform); // frame of reference
});
</script>
1
2
3
4
5
6
7
8
9
10
11
//var data = [{x: 5, y: 10}, {x: 20, y: 5}]
var circles = svg.selectAll('circle')
.data(data)
circles.enter().append('circle')
.attr('cx', function(d) { return d.x })
.attr('cy', function(d) { return d.y })
.attr('r', 0)
.transition().duration(500)
.attr('r', 5)

First we make a selection object of all the svg circles in the visualisation (initially there will be none). Then we bind some data to the selection (our data array).

D3 keeps track of which data point is bound to which circle in the diagram. So initially we have two datapoints, but no circles; we can then use the .enter() method to get the datapoints which have “entered”. For those points, we say we would like a circle added to the diagram, centered on the x and y values of the datapoint, with an initial radius of 0 but transitioned over half a second to a radius of 5.

1
2
3
4
5
6
7
#import "PNChart.h"
//For BarC hart
PNBarChart * barChart = [[PNBarChart alloc] initWithFrame:CGRectMake(0, 135.0, SCREEN_WIDTH, 200.0)];
[barChart setXLabels:@[@"SEP 1",@"SEP 2",@"SEP 3",@"SEP 4",@"SEP 5"]];
[barChart setYValues:@[@1, @10, @2, @6, @3]];
[barChart strokeChart];

super cool example
http://codepen.io/xna2/pen/Dmqso

TIP

  • There’s a confusing idiom “scale”.

“Scales are functions that map from an input domain to an output range.”

http://stackoverflow.com/questions/17562119/how-to-interpret-the-d3-statement-var-r-d3-scale-linear-domain0-1-range

  • React files can actually be named like “*.react.js”. Then you can require it like this:
1
var FluxCartApp = require('./components/FluxCartApp.react');

Hmmm… definitely cooler, not sure if it’s useful

  • Paperclip™ is a great way for you to play around with d3, you just copy those html into the editor and see how things are going on. I don’t know how to explain it better, but you just fucking do it.

https://github.com/wbkd/awesome-d3

Let’s Make a Bar Chart http://bost.ocks.org/mike/bar/

D3 and React - the future of charting components?
http://10consulting.com/2014/02/19/d3-plus-reactjs-for-charting/

Play with D3:

http://jsfiddle.net/enigmarm/3HL4a/13/

http://bl.ocks.org/mbostock

One repo to rule them all

Awesome-react

http://latentflip.com/imperative-vs-declarative/

D3 Tutorials

Book

https://leanpub.com/D3-Tips-and-Tricks

https://leanpub.com/reactd3js

http://chimera.labs.oreilly.com/books/1230000000345/

Get them for free… Holy High(好厉害).

Course

This one’s not for free… so if there are team coverage? XD
https://www.udemy.com/mastering-d3-js/

Reference

https://github.com/mbostock/d3/wiki/%E9%80%89%E6%8B%A9%E9%9B%86#d3_select
https://scotch.io/tutorials/getting-to-know-flux-the-react-js-architecture
https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g

Tools Built with D3

When you want to use D3 without actually writing any D3 code, you can choose one of the many tools built on top of D3!

Crossfilter
A library for working with large, multivariate datasets, written primarily by Mike Bostock. This is useful for trying to squeeze your “big data” into a relatively small web browser.

Cubism
A D3 plug-in for visualizing time series data, also written by Mike Bostock. (One of my favorite demos.)

Dashku
An online tool for data dashboards and widgets updated in real time, by Paul Jensen.

dc.js
The “dc” is short for dimensional charting, as this library is optimized for exploring large, multidimensional datasets.

NVD3
Reusable charts with D3. NVD3 offers lots of beautiful examples, with room for visual customizations without requiring as much code as D3 alone.

Polychart.js
More reusable charts, with a range of chart types available. Polychart.js is free only for noncommercial use.

Rickshaw
A toolkit for displaying time series data that is also very customizable.

Tributary
A great tool for experimenting with live coding using D3, by Ian Johnson.