<div id="root">
li {
  font-size: 18px;
  list-style: none;
}

path, line {
  stroke: #777;
}

/* Particles Styles */
.particlesRect {
  fill: none;
  pointer-events: all;
}

.particlesCircle {
  fill: none;
  stroke-width: 2.5px;
}

.stackedBarAxis line {

/* stacked to bars */

  .STB {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  margin: auto;
  position: relative;
  width: 960px;
}

/*Voronoia*/

circle {
  stroke: #EFEDF5;
  fill: #EFEDF5;
  pointer-events: none;
}
line {
  pointer-events: none;
  stroke: #EFEDF5;
  stroke-width: 2px;
  opacity: .05;
}
path{
  stroke: #EFEDF5;
  stroke-width: 4px;
}
var node = document.createElement('div');

var branches = [];
var seed = {i: 0, x: 420, y: 600, a: 0, l: 130, d:0}; // a = angle, l = length, d = depth
var da = 0.5; // Angle delta
var dl = 0.8; // Length delta (factor)
var ar = 0.65; // Randomness
var maxDepth = 8;


// Tree creation functions
function branch(b) {
  var end = endPt(b), daR, newB;

  branches.push(b);

  if (b.d === maxDepth)
    return;

  // Left branch
  daR = ar * Math.random() - ar * 0.5;
  newB = {
    i: branches.length,
    x: end.x,
    y: end.y,
    a: b.a - da + daR,
    l: b.l * dl,
    d: b.d + 1,
    parent: b.i
  };
  branch(newB);

  // Right branch
  daR = ar * Math.random() - ar * 0.5;
  newB = {
    i: branches.length,
    x: end.x, 
    y: end.y, 
    a: b.a + da + daR, 
    l: b.l * dl, 
    d: b.d + 1,
    parent: b.i
  };
  branch(newB);
}

function regenerate(initialise) {
  branches = [];
  branch(seed);
  initialise ? create() : update();
}

function endPt(b) {
  // Return endpoint of branch
  var x = b.x + b.l * Math.sin( b.a );
  var y = b.y - b.l * Math.cos( b.a );
  return {x: x, y: y};
}


// D3 functions
function x1(d) {return d.x;}
function y1(d) {return d.y;}
function x2(d) {return endPt(d).x;}
function y2(d) {return endPt(d).y;}
function highlightParents(d) {
  var colour = d3.event.type === 'mouseover' ? 'green' : '#777';
  var depth = d.d;
  for(var i = 0; i <= depth; i++) {
    d3.select('#id-'+parseInt(d.i)).style('stroke', colour);
    d = branches[d.parent];
  } 
}

function create() {
  d3.select(node).append('svg')
    .attr('height', 650)
    .attr('width', 960)
    .selectAll('line')
    .data(branches)
    .enter()
    .append('line')
    .attr('x1', x1)
    .attr('y1', y1)
    .attr('x2', x2)
    .attr('y2', y2)
    .style('stroke-width', function(d) {return parseInt(maxDepth + 1 - d.d) + 'px';})
    .attr('id', function(d) {return 'id-'+d.i;})
    .on('mouseover', highlightParents)
    .on('mouseout', highlightParents);
}

function update() {
  d3.select('svg')
    .selectAll('line')
    .data(branches)
    .transition()
    .attr('x1', x1)
    .attr('y1', y1)
    .attr('x2', x2)
    .attr('y2', y2);
}

regenerate(true);

d3.select(node).select('svg')
  .on('click', regenerate);

function createVoronoi() {
var voronoi = document.createElement('div');
  
var w = 960,
    h = 500;

var svg = d3.select(voronoi)
        .append("svg")
        .attr("width", w)
        .attr("height", h)
        .on('mount', function(){

          var w = 960,
              h = 500,
              radius = 5.25,
              links = [],
              simulate = true,
              zoomToAdd = true,
              // https://github.com/mbostock/d3/blob/master/lib/colorbrewer/colorbrewer.js#L105
              color = d3.scale.quantize().domain([10000, 7250]).range(["#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"])
          
          var numVertices = (w*h) / 3000;

          var vertices = d3.range(numVertices).map(function(i) {
              var angle = radius * (i+10);
              return {x: angle*Math.cos(angle)+(w/2), y: angle*Math.sin(angle)+(h/2)};
          });

          var d3_geom_voronoi = d3.geom.voronoi().x(function(d) { return d.x; }).y(function(d) { return d.y; })

          var prevEventScale = 1;

          var zoom = d3.behavior.zoom().on("zoom", function(d,i) {
              if (zoomToAdd){
                if (d3.event.scale > prevEventScale) {
                    var angle = radius * vertices.length;
                    vertices.push({x: angle*Math.cos(angle)+(w/2), y: angle*Math.sin(angle)+(h/2)})
                } else if (vertices.length > 2 && d3.event.scale != prevEventScale) {
                    vertices.pop();
                }
                force.nodes(vertices).start()
              } else {
                if (d3.event.scale > prevEventScale) {
                  radius+= .01
                } else {
                  radius -= .01
                }
                vertices.forEach(function(d, i) {
                  var angle = radius * (i+10);
                  vertices[i] = {x: angle*Math.cos(angle)+(w/2), y: angle*Math.sin(angle)+(h/2)};
                });
                force.nodes(vertices).start()
              }
              prevEventScale = d3.event.scale;
          });

          var svg = d3.select('svg')
            .call(zoom)      

          var force = d3.layout.force()
                  .charge(-300)
                  .size([w, h])
                  .on("tick", update);

          force.nodes(vertices).start();

          var circle = svg.selectAll("circle");
          var path = svg.selectAll("path");
          var link = svg.selectAll("line");

          function update(e) {
            console.lo
              path = path.data(d3_geom_voronoi(vertices))
              path.enter().append("path")
                  // drag node by dragging cell
                  .call(d3.behavior.drag()
                    .on("drag", function(d, i) {
                        vertices[i] = {x: vertices[i].x + d3.event.dx, y: vertices[i].y + d3.event.dy}
                    })
                  )
                  .style("fill", function(d, i) { return color(0) })
              path.attr("d", function(d) { return "M" + d.join("L") + "Z"; })
                  .transition().duration(150).style("fill", function(d, i) { return color(d3.geom.polygon(d).area()) })
              path.exit().remove();
              circle = circle.data(vertices)
              circle.enter().append("circle")
                    .attr("r", 0)
                    .transition().duration(1000).attr("r", 5);
              circle.attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; });
              circle.exit().transition().attr("r", 0).remove();
              link = link.data(d3_geom_voronoi.links(vertices))
              link.enter().append("line")
              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; })
              link.exit().remove()
              if(!simulate) force.stop()
          }
        })

  return voronoi;
}

function createStreamGraph() {
  var streamGraph = document.createElement('div');

  var n = 20, // number of layers
      m = 200, // number of samples per layer
      stack = d3.layout.stack().offset("wiggle"),
      layers0 = stack(d3.range(n).map(function() { return bumpLayer(m); })),
      layers1 = stack(d3.range(n).map(function() { return bumpLayer(m); }));

  var width = 960,
      height = 500;

  var x = d3.scale.linear()
      .domain([0, m - 1])
      .range([0, width]);

  var y = d3.scale.linear()
      .domain([0, d3.max(layers0.concat(layers1), function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); })])
      .range([height, 0]);

  var color = d3.scale.linear()
      .range(["#aad", "#556"]);

  var area = d3.svg.area()
      .x(function(d) { return x(d.x); })
      .y0(function(d) { return y(d.y0); })
      .y1(function(d) { return y(d.y0 + d.y); });

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

  svg.selectAll("path")
      .data(layers0)
    .enter().append("path")
      .attr("d", area)
      .style("fill", function() { return color(Math.random()); });

  // On load function that will trigger the transitions
  svg.on('mount', function() {
    transition();
  });

  // This function will be triggered on load
  function transition() {

    d3.selectAll("path")
        .data(function() {
          var d = layers1;
          layers1 = layers0;
          return layers0 = d;
        })
      .transition()
        .duration(2500)
        .attr("d", area);

  }

  function bumpLayer(n) {

    function bump(a) {
      var x = 1 / (.1 + Math.random()),
          y = 2 * Math.random() - .5,
          z = 10 / (.1 + Math.random());
      for (var i = 0; i < n; i++) {
        var w = (i / n - y) * z;
        a[i] += x * Math.exp(-w * w);
      }
    }

    var a = [], i;
    for (i = 0; i < n; ++i) a[i] = 0;
    for (i = 0; i < 5; ++i) bump(a);
    return a.map(function(d, i) { return {x: i, y: Math.max(0, d)}; });
  }

 return streamGraph;
}

var { Router, Route, IndexRoute, Link, browserHistory } = ReactRouter

var MainLayout = React.createClass({
  render: function() {
    return (
      <div className="app">
        <header className="primary-header"></header>
        <aside className="primary-aside">
          <ul>
            <li><Link to="/">BinaryTree</Link></li>
            <li><Link to="/voronoi">Voronoi</Link></li>
            <li><Link to="/streamgraph">Stream Graph</Link></li>
          </ul>
        </aside>
        <main>
          {this.props.children}
        </main>
      </div>
      )
  }
})

var BinaryTree = React.createClass({
  getInitialState: function() {
    return {d3: ''}
  },

  componentDidMount: function() {
    this.setState({d3: node});
  },

  render: function() {
    var RD3Component = rd3.Component;
    return (
      <div>
        <RD3Component data={this.state.d3} />
      </div>
    )
  }
})

var Voronoi = React.createClass({
  getInitialState: function() {
    return {d3: ''}
  },

  componentDidMount: function() {
    this.setState({d3: createVoronoi()});
  },

  render: function() {
    var RD3Component = rd3.Component;
    return (
      <div>
        <RD3Component data={this.state.d3} />
      </div>
    )
  }
})

var StreamGraph = React.createClass({
  getInitialState: function() {
    return {d3: ''}
  },

  componentDidMount: function() {
    this.setState({d3: createStreamGraph()});
  },

  render: function() {
    var RD3Component = rd3.Component;
    return (
      <div>
        <RD3Component data={this.state.d3} />
      </div>
    )
  }
})

// Note that with how CodePen works, I wasn't able to get the browserHistory to work
// as the article suggests. The demo works without it, but you'll want to be sure to 
// use it in a real application
ReactDOM.render((
  <Router>
    <Route path="/" component={MainLayout}>
      <IndexRoute component={BinaryTree} />
      <Route path="voronoi" component={Voronoi} />
      <Route path="streamgraph" component={StreamGraph} />
    </Route>
  </Router>
), document.getElementById('root'))


View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://npmcdn.com/react-d3-library@1.1.2/dist/react-d3-library.js
  2. https://fb.me/react-15.1.0.min.js
  3. https://fb.me/react-dom-15.1.0.min.js
  4. https://cdnjs.cloudflare.com/ajax/libs/react-router/2.0.0/ReactRouter.min.js
  5. https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js