ogobrecht.github.io

D3.js - Data Driven Documents

Ottmar Gobrecht
DOAG APEX connect 2015, Düsseldorf


Aufwärmrunde


Force Directed Graph


Bubble Chart


Sunburst Chart


Treemap Chart


Collapsible Tree Chart


Zum selber schauen:

d3js.org github.com/mbostock/d3/wiki/Gallery


d3js.org


github.com/mbostock/d3/wiki/Gallery


github.com/mbostock/d3/wiki/Gallery


github.com/mbostock/d3/wiki/Gallery


github.com/mbostock/d3/wiki/Gallery


github.com/mbostock/d3/wiki/Gallery


github.com/mbostock/d3/wiki/Gallery


github.com/mbostock/d3/wiki/Gallery


github.com/mbostock/d3/wiki/Gallery


github.com/mbostock/d3/wiki/Gallery


Das könnte immer so weiter gehen …


Der Versuch einer Definition


D3.js - Was ist das?


Die Basis - SVG


Scalable Vector Graphics


SVG Zeichnungselemente


Ein erstes Beispiel

Live im Browser…


<!DOCTYPE html><html><head><title>SVG Beispiel</title></head><body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<svg id="Beispiel_1" style="width:490; height:140;">
  <rect x="10" y="10" height="120" width="160" fill="#ff6600"/>
  <ellipse cx="270" cy="70" rx="120" ry="40" fill="green"/>
  <line x1="40" y1="40" x2="480" y2="120" stroke="blue"/>
</svg>

JavaScript: Bitte in Konsole ausführen

  d3.select('svg#Beispiel_1').append('circle')
    .attr('cx','420')
    .attr('cy','70')
    .attr('r','60')
    .style('stroke','red')
    .style('fill','lightsteelblue')
    .style('fill-opacity',0.5);

Anmerkung:


JavaScript


Selectors versus Selections


Selectors versus Selections

Schleife über alle Elemente: JavaScript

var p = document.getElementsByTagName('p');
for (var i = 0; i < p.length; i++) {
  var pi = p.item(i);
  pi.style.setProperty('color','red', null);
}

Schleife über alle Elemente: D3

d3.selectAll('p').style('color','red');

bost.ocks.org/mike/selection/

Anmerkung:


Ohne Daten nichts los


Die D3 Mengenlehre

Wie man Daten an das DOM bindet


Der D3 Data Join - [bost.ocks.org/mike/join/][6]


Eine Data Join Live Übertragung direkt aus … … dem Browser:

Ein bereits existierendes Element

<div id="Beispiel_2">
  <p style="color:green;">Ein bereits existierendes Element</p>
</div>

Bitte Code in der Browser-Konsole ausführen:

  var div = d3.select('div#Beispiel_2');
  var p = div.selectAll('p').data([1,2,3])
    .style('color', 'red');
  p.enter().append('p')
    .text( function(d){return 'Neues Element aus Daten ' + d;} )
    .style('color', 'green');
  p.exit().remove();

bost.ocks.org/mike/circles/


Anmerkungen


Die Key Function


Key Function Beispiel:

<svg id="Beispiel_3" width="200" height="30"></svg>
var data = [ {"id":1, "r":14, "x":80,  "y":15, "color":"red"},
             {"id":2, "r":14, "x":100, "y":15, "color":"green"},
             {"id":3, "r":14, "x":120, "y":15, "color":"blue"} ];
var svg = d3.select('svg#Beispiel_3');
var circle = svg.selectAll('circle')
  .data(data, function(d){ return d.id; });
circle.exit().remove();
circle.enter().append('circle');
circle
  .attr('r',    function(d) { return d.r; })
  .attr('cx',   function(d) { return d.x; })
  .attr('cy',   function(d) { return d.y; })
  .attr('fill', function(d) { return d.color; });
// Einfach mal mit diesen neuen Daten rumprobieren
data = [ {"id":1, "r":7,  "x":50,  "y":15, "color":"blue"},
         {"id":3, "r":14, "x":150, "y":15, "color":"red"} ];
circle = svg.selectAll('circle')
  .data(data, function(d){return d.id;}); // Was kommt danach? ;-)

Hilfsfunktionen


Layouts

Layouts sind Chart Algorithmen

github.com/mbostock/d3/wiki/Layouts


Beispiel Pack Layout

Beispiel Pack Layout

github.com/mbostock/d3/wiki/Pack-Layout


Beispiel Bundle Layout

Beispiel Bundle Layout

github.com/mbostock/d3/wiki/Bundle-Layout


Das Geheimnis der Geschwindigkeit

Anmerkung:


Force Layout Beispiel


Überblick Force Layout


Die Knoten: Mitarbeiter der EMP-Tabelle

  var nodes = [
    {"name":"King","dept":10},{"name":"Blake","dept":30},
    {"name":"Clark","dept":10},{"name":"Jones","dept":20},
    {"name":"Scott","dept":20},{"name":"Ford","dept":20},
    {"name":"Smith","dept":20},{"name":"Allen","dept":30},
    {"name":"Ward","dept":30},{"name":"Martin","dept":30},
    {"name":"Turner","dept":30},{"name":"Adams","dept":20},
    {"name":"James","dept":30},{"name":"Miller","dept":10}
  ];

Die Links: Mitarbeiter / Vorgesetzter

  var links = [
    {"source":1,"target":0},{"source":2,"target":0},
    {"source":3,"target":0},{"source":7,"target":1},
    {"source":8,"target":1},{"source":9,"target":1},
    {"source":10,"target":1},{"source":12,"target":1},
    {"source":13,"target":2},{"source":4,"target":3},
    {"source":5,"target":3},{"source":6,"target":5},
    {"source":11,"target":4}
  ];

Vorbereitung, Helper und Layout

var width = 600, height = 400;

var svg = d3.select("body").append("svg")
  .attr("width",width).attr("height", height);

var color = d3.scale.category10();

var force = d3.layout.force().size([width,height]);

Selections

var link = svg.selectAll("line").data(links)
  .enter().append("line").style('stroke','#999');

var node = svg.selectAll("circle").data(nodes)
  .enter().append("circle")
    .attr("r", 5)
    .style("fill", function(d){ return color(d.dept); })
    .call(force.drag);

Tick Event

force.on("tick", function(){

  link.attr("x1", function(d){ return d.source.x; })
      .attr("y1", function(d){ return d.source.y; })
      .attr("x2", function(d){ return d.target.x; })
      .attr("y2", function(d){ return d.target.y; });

  node.attr("cx", function(d){ return d.x; })
      .attr("cy", function(d){ return d.y; });
  });

Ausführung

force.nodes(nodes).links(links).start();

Das Ergebnis…

Knoten dürfen bewegt werden ;-)


…ein wenig aufgebrezelt

Mit Customize Wizard: Standalone, APEX Plugin


The End


Fragen?

ogobrecht.github.io


Anhang: Kapselung von Chart Code


Warum eigentlich?


Kleiner Exkurs

Anmerkung:


Beispiel Closure:

function my_chart() {
  var conf = { "width": 600, "height": 400 };
  function chart(){/*create chart with conf*/}
  chart.render = function(){
    chart();
    return chart;
  };
  chart.width = function(value) {
    if (!arguments.length) return conf.width;
    conf.width = value;
    return chart;
  };
  return chart;
}
//Einfach einzeln in der Konsole ausprobieren ;-)
var test = my_chart(); //Initialisierung
test.width();          //Breite auslesen
test.chart();          //Versuch, die Chart Funktion auszuführen
test.render();         //Chart Funktion über Render-Methode
test.width(300).render().width(); //Was passiert jetzt?

Anmerkungen


Nun aber wirklich: The End

Fragen?

ogobrecht.github.io