D3.js

Much more like a library like jQuery, than a framework like angular.js

Focused od data Visualisation

D3.js uses "document traversal" aka. DOM traversal

you can chain all the methods toogether

to use it in node.js (where lacking DOM) you can require some DOM implementations

like JSDOM

r

var d3 = require("d3"), jsdom = require("jsdom");var document = jsdom.jsdom(), svg =d3.select(document.body).append("svg");

npm install d3

<script src="http://d3js.org/d3.v3.min.js"; charset="utf-8"></script>

SVG

scalable vector graphics

xml format

positioning

(positiveX, positiveY)

(negative X, negative Y)

figures

circle

attributes

r

cx

cy

line

x1, y1

x2, y2

stroke

color

stroke-width

g element

Is a contianer used to group objects

Transformations applied to the g element are performed on all of its child elements.

you can use it to attach style or events to multiple elements (children of g element)

ex.

r

<svg width="100%" height="100%" viewBox="0 0 95 50" xmlns="http://www.w3.org/2000/svg"> <g stroke="green" fill="white" stroke-width="5"> <circle cx="25" cy="25" r="15" /> <circle cx="40" cy="25" r="15" /> <circle cx="55" cy="25" r="15" /> <circle cx="70" cy="25" r="15" /> </g></svg>

geometry

is changed by .attr

aestetic

is changed by .style

text element

do not support margins and paddings

dy

is used to center it verticaly

JSON

Data Format of a modern web browser :)

JavaScript Object Notation

Objects

Array of values

Keys:Values

Primitive Ojbects/Nested Objects

selecting

dot notation

objectName.nestedObjectName.keyName

from array (0 based notation)

test.phones[0]

braces

objectName['keyName']

to check array lenght

arrayName.lenght

steps

Load

Select & Bind

Enter and Append

Transform & Translate

Transistion

Exit

charts functions

d3.layout.pie()

selections

adding functions

.each(function)

The .each() method calls the function argument for each element inside the
Selection

ex.

r

d3.selectAll('p').each(function(d, i){var self = d3.select(this);// Output the text of every elementconsole.log(self.text());});</script>

selection.call(function[, arguments…])

you can call function that you have declared with arguments

ex.

r

<p>I like fruits.</p><p>Apple, Banana and Orange</p><script type="text/javascript">function set_custom_attr(selection, attr, value) {selection.attr(attr, value);}d3.selectAll('p').call(set_custom_attr, 'align', 'center');</script>and the result is:<p align="center">I like fruits.</p><p align="center">Apple, Banana and Orange</p>

methods

.classed()

return true of false depending on class attached to element

d3.select('#tree').classed('house')

it return false, becouse element (#tree) don't have class ('hosue')

d3.select('div').classed('house')

return false becouse non all div has calss ('.hosue')

we can also give and deleted class of selected documents by this method

d3.selectAll('div').classed('house',true)

all divs will have calss="house"

it will return a selection

d3.selectAll('div').classed('hosue', false)

none of the divs will have class="house"

request()

asynchronius of course

non-blocking

D3 Data Formats

data binding

methods of binding data to selected element

core of D3

ghost selection | empty selection

you can select element that not exist yet

also...after selecting DOM element you have access to the data that is bind to selected element

.data(values[, key])

r

<script type="text/javascript">// Create a data arrayvar data = [10, 20, 30, 40];// Bind data array to the Selectionvar circles = d3.selectAll('circle').data(data);console.log(circles.data());// [10, 20, 30, 40]</script>

for binding data from file to choosen element

it returns the number of elements = number of data records

key is additional parameter

you can call a function there, that interacts with every data item

enter()

ex.

r

var viz = d3.select("#viz-wrapper") .append('svg') .attr('id', 'viz'); d3.csv('../../app/climate_data.csv', function(data) { dots = viz.selectAll('circle') //ghost selection dots.data(data) //return 516 objects dots.enter() // still return 516 objects dots.append('circle'); //adding 516 circle elements to HTML//binding data (absolute value from max temp/ 100 to make it C deg) to r of a circledots.attr('r', function(d) {return Math.abs(d.TMAX) / 100}); });

Using dynamic properties in Selections

circles.attr('r', function(d, i) { return d; });

you can also access data from the array of objects

circles.attr('r', function(d, i) { return d.r; });

r

var data = [{cx:50, cy:50, r: 10, color: '#ff0000'},{cx:150, cy:50, r: 20, color: '#ff0066'},{cx:250, cy:50, r: 30, color: '#ff00aa'},{cx:350, cy:50, r: 40, color: '#ff00ff'}];

.attr('fill', function(d, i) { return d.color; })

Set the fill color
depending of the bound object

we can also set the properties depending on index i value

circles.style('stroke-width', function(d, i) { return i*2; }) ;

.append()

it will append svg element to the current selections

.append returns a new selection

svg

.append('svg').attr('width', 200px).attr('height', 200px)

figure

.append('circle')

.attr('attribute', 'value')

gives HTML attribute to the selected svg element

for example takes one piece of data, and bind it to "r" attr of a circle

ex.

r

dots.attr('r', function(d) {return d.TMAX});

value is offten a function

it can takes 2 parameters

d - data or datum

i - index value of the data

optional

math

Math.abs()

return a absolute value (when you dealing with nagative numbers)

Math.max(0, 10)

gives you maximum value from equation

=== 10

ex.

r

{return Math.max(0 + padding, Math.random() * width - padding)} //give us some random number based on width minus padding left and right

text()

debbuger in chrome dev tools

to explore what data is bind to where

by accessing d in the console

Sources tab are really helpful with debbuging

You can open any files, and set break points to run your code to a specyfic line

and later access the variable or function in the given time

you can write "debugger" into your code, and app will stop there

styling

Events

Converting visualisation into angular app

Creating directive with chart code

make an app

link to angular libarary of course

var app = angular.module("myApp", []);

connect app into html <body>

<body ng-app= "myApp" ng-controller="chartNameController">

make an chart element inside html <chart-name data="chart" ng-reapat="chart in charts"></chart-name>

Subtopic

make an derective (inside an app) where code for a chart goes

app = directive('chartName', function() { })

function link (scope, el) { //d3 code inside, el is an element }

you can pull the data out the chart function

var data = scope.data;

it reference to the <chart-name data=[21,5,9]></chart-name> in html

it should return an link

return { link:link, restrict: 'E', scope: {data: '=' } };

write css on the element not a class of the element

creating controller for the chart

<body ng-app="myApp" ng-controller="chartNameController">

app.controller("ChartNameController", function($scope) { //code inside })

$scope.charts = d3.range(10).map(function() { return d3.range(10).map(Math.random) })

random data with 10 values for 10 charts

making visualisation responsive

inside chart element ng-style="{width: 100 / charts.length + '%' }"

with: 100%;

height: 100%;

inside chart code

scope.$watch(function() { return el.clientWidth * el.clientHeight}, function() { width = el.clientWidth height = el.clientHeight })

all the variables that depends on with and height goes inside secon function

inside controller we have to tell angular to watch the widow changes

angular.element($window).on('resize', function(){ $scope.$apply() })

how to design it

every visualisation element should be write as a custom derective

r

<html><head><script>...app.directive('d3Map', function(){ ... });app.directive('d3LineChart', function(){ ... });app.directive('d3ScatterPlot', function(){ ... });app.directive('d3ChordDiagram', function(){ ... });</script></head><body><d3-map></d3-map><d3-line-chart data="data"></d3-line-chart><d3-scatter-plot data="data"></d3-scatter-plot><d3-chord-diagram data="data"></d3-chord-diagram></body></html>

ex.

app.directive('d3ChordDiagram', function(){ ... });

<d3-chord-diagram data="data"></d3-chord-diagram>

in HTML

we can alter the visualisation by writing a custom filters

ex.

app.filter('startDate', function(){ ... });

<d3-line-chart data="timeData | startDate:'01.01.2015'"></d3-
line-chart>

in HTML