D3Kit Histogram with Mithril
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;}
.y-axis-layer path,
.y-axis-layer line{
fill: none;
}
.y-axis-layer line{
stroke: lightgray;
}
.y-axis-layer text{
font-size: 11px;
}
.x-axis-layer line,
.x-axis-layer path{
fill: none;
}
.x-axis-layer text{
font-size: 11px;
}
/* Tooltip */
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 8px;
background: darkgreen;
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: darkgreen;
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -3px 0 0 0;
top: 100%;
left: 0;
}
.panel-heading{
padding-bottom: 0px;
}
.panel-body{
padding-top: 0px;
}
Babel + JSX
/** @jsx m */
const chartDefaults = {
margin: {left: 30, right: 20, bottom: 20, top: 20},
initialWidth: "auto",
initialHeight: 200
}
const chartConstructor = (skeleton) => {
// setup
const S = {x: d3.scale.linear(), y: d3.scale.linear()}
const A = {x: d => d.x, y: d => d.y}
const L = skeleton.getLayerOrganizer()
L.create(['y-axis', 'x-axis', 'bars'])
const visualize = d3Kit.helper.debounce(() => {
// get data, width and height
const data = skeleton.data()
const W = skeleton.getInnerWidth()
const H = skeleton.getInnerHeight()
const opts = skeleton.options()
const numBins = x =>
Math.ceil(Math.log(x.length)/Math.log(2) + 1)
S.x.range([0, W]).domain(d3.extent(data))
const histData = d3.layout.histogram()
.bins(S.x.ticks(numBins(data)))
(data)
S.y.range([H, 0]).domain([0, d3.max(histData, A.y)])
// render bars
const bars = L.get('bars').selectAll(".bar").data(histData)
bars.enter().append("rect").classed("bar", true)
bars.exit().remove()
bars.attr({
transform: d =>
`translate(${S.x(A.x(d))}, ${S.y(A.y(d))})`,
height: d => H - S.y(A.y(d)),
width: S.x(A.x(histData[1])) - S.x(A.x(histData[0])) - 1,
x: 1,
fill: opts.fill || "steelblue"
})
// tooltip
const tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(d => `${d.y} values in (${d.x}, ${d.x + d.dx}]`)
skeleton.getRootG().call(tip)
L.get("bars").selectAll(".bar")
.on("mouseover", tip.show)
.on("mouseout", tip.hide)
// render y-axis
const yAxis = d3.svg.axis()
.scale(S.y)
.ticks(5)
.tickSize(-W)
.orient('left')
L.get("y-axis").call(yAxis)
// render x-axis
const xAxis = d3.svg.axis()
.scale(S.x)
.orient('bottom')
L.get("x-axis")
.attr("transform", `translate(0, ${H})`)
.call(xAxis)
}, 10)
skeleton
...