React with D3Kit

by ramnathv

HTML

<script src="//fb.me/react-with-addons-0.14.0.js"></script>
<script src="//fb.me/react-dom-0.14.0.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//rawgit.com/kristw/75b61f9beeab9b530612/raw/389e984e4041117a9185cf6edad9f6b85a38097a/d3kit.min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/react-bootstrap/0.28.1/react-bootstrap.min.js"></script>
<div class="container-fluid" id='main'>
    <div class="row">
        <div class="col-xs-12 col-md-6">
            <h4>React with D3Kit</h4>
            <div id="chart"></div>
            <div class="well" style="text-align:justify;">
              This is an example of hooking up React with a D3Kit chart that automatically handles resize events. If you open the developer console, you will notice that resizing the chart will not initiate a rerendering by React, as it is being handled directly by the chart code.
            </div>
        </div>
        
    </div>
</div>

CSS

#main{margin-top: 20px;}
.x-axis-layer line, .y-axis-layer line,
.x-axis-layer path, .y-axis-layer path {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

Babel + JSX

// Define bubble chart
var BubbleChart = d3Kit.factory.createChart(
  // First argument is the default options for this chart
  {
    margin: {top: 60, right: 60, bottom: 60, left: 60},
    initialWidth: 800,
    initialHeight: 400
  },
  // The second argument is an Array that contains
  // names of custom events from this chart.
  // In this example chart,
  // it will dispatch event "bubbleClick" when users click on a bubble.
  ['bubbleClick'],
  // The third argument is an internal constructor.
  // This is where you would implement a bubble chart
  // inside the passed skeleton.
  function(skeleton){
    var layers = skeleton.getLayerOrganizer();
    var dispatch = skeleton.getDispatcher();
    var color = d3.scale.category10();

    layers.create(['content', 'x-axis', 'y-axis']);

    var x = d3.scale.linear()
      .range([0, skeleton.getInnerWidth()]);

    var y = d3.scale.linear()
      .range([0, skeleton.getInnerHeight()]);

    
    var xAxis = d3.svg.axis()
      .scale(x)
      .orient('bottom')

    var yAxis = d3.svg.axis()
      .scale(y)
      .orient('left');

    var visualize = d3Kit.helper.debounce(function(){
      if(!skeleton.hasData()){
        d3Kit.helper.removeAllChildren(layers.get('content'));
        return;
      }
      var data = skeleton.data();
      // set number of ticks based on width
      xAxis.ticks(Math.round(skeleton.getInnerWidth()/40))

      x.domain(d3.extent(data, function(d){return d.x;}))
        .range([0, skeleton.getInnerWidth()]);
      y.domain(d3.extent(data, function(d){return d.y;}))
        .range([skeleton.getInnerHeight(), 0]);

      layers.get('x-axis')
        .attr('transform', 'translate(0,' + skeleton.getInnerHeight() + ')')
        .call(xAxis);

      layers.get('y-axis')
        .call(yAxis);

      var selection = layers.get('content').selectAll('circle')
        .data(data);

      selection.exit().remove();

      selection.enter().append('circle')
        .attr('cx', function(d){return...