Marvelous Visualizations with D3.js

A talk by Igor Lukanin at FrontendFellows #4

Yekaterinburg · April 29, 2016

Data-Driven
Documents


<body>
    <div class="dot"></div>
</body>
    

const createDot = () =>
        ({ x: Math.random(), y: Math.random() });

const dot = createDot();

d3.select('body')
        .append('div')
        .attr('class', 'dot')
        .style('left', 100 * dot.x + '%')
        .style('top',  100 * dot.y + '%');
    

const dots = [
    createDot(),
    createDot()
];

dots.forEach(dot => {
    // Drawing with D3...
});
    

— Noooooooo!
Luke S.


d3.select('body')
        .selectAll('div') // Elements
        .data(dots)       // Data
        .enter()          // Selection
        .append('div')
        .attr('class', 'dot')
        .style('left', dot => 100 * dot.x + '%')
        .style('top',  dot => 100 * dot.y + '%');
    
Data Elements Enter Update Exit

One, two...
Oops!


const selection = d3.select('body')
        .selectAll('div') // Elements
        .data(dots);      // Data

selection.enter()         // For each new dot...
        .append('div')
        .attr('class', 'dot dot_entered')
        .style('left', dot => 100 * dot.x + '%')
        .style('top',  dot => 100 * dot.y + '%');
    

<body></body>

const dots = [
    { x: 0.5, y: 0.5 },
    createDot(),
    createDot()
];

// Drawing with D3...
    

Red or green?


const draw = dots => {
    // Drawing with D3...
};

draw(dots);

setInterval(() => {
    dots.push(createDot());
    draw(dots);
}, 1000);
    

var i = 1;
const createDot = () => ({ /* x, y... */  i: i++ }};
const dots =            [{ /* x, y... */  i: 0 }, /* ... */];

const draw = dots => { 
    // Data × Elements...

    selection.enter() // ...
            .text(dot => dot.i);
};
    

setInterval(() => {
    if (i <= 10) {
        dots.push(createDot());
    }
    else {
        const index = Math.floor(Math.random() * dots.length);
        dots.splice(index, 1);
    }

    draw(dots);
}, 1000);
    

const draw = dots => {
    // Data × Elements...
    // selection.enter()

    selection.exit()
            .remove();
};
    

setInterval(() => {
    if (i <= 10) {
        dots.push(createDot());
    }
    else {
        const index = Math.floor(Math.random() * dots.length);
        dots.splice(index, 1);
    }

    draw(dots);
}, 1000);
    

Random?


const draw = dots => {
    const selection = d3.select('body')
            .selectAll('div')
            .data(dots, dot => dot.i);

    // selection.enter()
    // selection.exit()
};
    

const draw = dots => {
    const selection = // Data × Elements...
            .attr('class', 'dot');

    selection.enter() // ...
            .attr('class', 'dot dot_entered');

    selection.exit()
            .attr('class', 'dot dot_exited');
};
    

Data × Elements
Enter, update, exit

Transitions
& Interpolations


selection.enter() // ...
        .style('left', dot => 100 * dot.x + '%')
        .style('top',  dot => -100)
        .transition().duration(3000)
        .style('top',  dot => 100 * dot.y + '%');

selection.exit() // ...
        .transition().duration(2000).ease('bounce')
        .style('top', '95%');
    

Moar!

Interpolations for Transitions

SVG
is XHTML too

Primitives

Path Data Generators

svg.append('path').attr('d', /* ... */ )
d3.svg.line().x(d => d.x).y(d => d.y).interpolate('basis')
d3.svg.area().x(d => d.x).y0(d => d.y).y1(d => d.y + 10)

D3.js is...

D3.js

  • Data × Elements
  • Transitions
  • SVG
  • scales
  • axes
  • geo
  • layouts
  • statistics
  • events
  • CSV, TSV

Marvelous
Visualizations

Links

One more thing...

Pace Craze

@igorlukanin
on Twitter & Github