D3Kit Horizontal Bar Chart with React

by ramnathv

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/mithril/0.2.3/mithril.min.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//cdn.rawgit.com/twitter/d3kit/master/dist/d3kit.min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.6/paper/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/d3-tip/0.6.7/d3-tip.min.js"></script>
<div class="container" id="main">
  <div class="row">
    <div class="col-xs-12 col-md-6">
      <div id="app"></div>
    </div>
  </div>
</div>

CSS

#main{margin-top: 20px;}
.x-axis-layer path,
.x-axis-layer line{
  fill: none;
}
.x-axis-layer line{
  stroke: lightgray;
}
.x-axis-layer text{
  font-size: 11px;
}

.y-axis-layer path,
.y-axis-layer line{
  fill: none;
}

/* Tooltip */
.d3-tip {
   line-height: 1;
   font-weight: bold;
   padding: 8px;
   background: steelblue;
   border-color: white;
   color: #fff;
   border-radius: 2px;
 }


/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
  box-sizing: border-box;
  display: inline;
  font-size: 10px;
  width: 100%;
  line-height: 1;
  color: steelblue;
  content: "\25BC";
  position: absolute;
  text-align: center;
}

/* Style northward tooltips differently */
.d3-tip.n:after {
  margin: -3px 0 0 0;
  top: 100%;
  left: 0;
}

Babel + JSX

/** @jsx m */
const defaults = {
  margin: {left: 20, right: 20, bottom: 20, top: 20},
  initialWidth: "auto",
  initialHeight: 250
}

const chartConstructor = (skeleton) => {
  // setup 
  const S = {x: d3.scale.ordinal(), y: d3.scale.linear()}
  const A = {x: d => d[0], y: d => d[1]}
  
  const L = skeleton.getLayerOrganizer()
  L.create(['x-axis', 'y-axis', 'bars'])
  const visualize = d3Kit.helper.debounce(() => {
    // get data, width and height
    const data = skeleton.data()
    const W = skeleton.getInnerWidth()
    const H = skeleton.getInnerHeight()
    
    // update scales
    S.x.rangeRoundBands([0, H], 0.15).domain(data.map(A.x))
    S.y.range([0, W]).domain([0, d3.max(data, A.y)])
   
    // render bars
    const bars = L.get('bars').selectAll('.bar').data(data)
    bars.enter().append('rect')
      .attr({
        class: 'bar', 
        x: 0,
        width: 0
      })
    bars.attr({
      y: d => S.x(A.x(d)),
      height: S.x.rangeBand(),
      fill: "steelblue"
    })
    bars.transition().attr({
      width: d => S.y(A.y(d)),
    })
    
    
    // render x-axis
    const xAxis = d3.svg.axis()
      .scale(S.y)
      .orient('bottom')
      .tickSize(-H)
      .ticks(5)
    L.get('x-axis')
      .attr("transform", `translate(0, ${H})`)
      .call(xAxis)
      
      
     // render x-axis
    const yAxis = d3.svg.axis()
      .scale(S.x)
      .orient('left')
    L.get('y-axis')
      .call(yAxis)
    
    // add tooltips
    const tip = d3.tip()
      .attr('class', 'd3-tip')
      .offset([-12, 0])
      .html(d => d[1].toFixed(2))
    L.get("bars").call(tip)
    bars
      .on("mouseover", tip.show)
      .on("mouseout", tip.hide)    
  }, 10)
  skeleton
    .resizeToFitContainer("width")
    .autoResize(true)
    .on("data", visualize)
    .on("resize", visualize)
}

const makeData = () =>
  d3.range(8).map((d, i) => [i, Math.random()])


const Chart = d3Kit.factory.createChart(
  defaults, [], chartConstructor
)

const ChartWrapper =...