This brush snaps to day boundaries. On release, the brush fires an end event, allowing a listener to modify the brush selection. Using brush.move to initiate a transition, the brush smoothly interpolates from the original selection to the rounded selection. Compare this approach to using immediate snapping while brushing.
forked from mbostock's block: Brush Snapping
forked from ericsoco's block: Brush Snapping
xxxxxxxxxx
<meta charset="utf-8">
<style>
.axis--grid .domain {
fill: #ddd;
stroke: none;
}
.axis--x .domain,
.axis--grid .tick line {
stroke: #fff;
}
.axis--grid .tick--minor line {
stroke-opacity: .5;
}
</style>
<body>
<script src="//d3js.org/d3.v4.0.0-alpha.49.min.js"></script>
<script>
var margin = {top: 200, right: 40, bottom: 200, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scaleTime()
.domain([new Date(2013, 7, 1), new Date(2013, 7, 15) - 1])
.rangeRound([0, width]);
var brush = d3.brushX()
.extent([[0, 0], [width, height]])
.on("end", brushended);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "axis axis--grid")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.ticks(d3.timeHour, 12)
.tickSize(-height)
.tickFormat(function() { return null; }))
.selectAll(".tick")
.classed("tick--minor", function(d) { return d.getHours(); });
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.ticks(d3.timeDay)
.tickPadding(0))
.attr("text-anchor", null)
.selectAll("text")
.attr("x", 6);
svg.append("g")
.attr("class", "brush")
.call(brush);
function brushended() {
if (!d3.event.sourceEvent) return; // Only transition after input.
if (!d3.event.selection) return; // Ignore empty selections.
var domain0 = d3.event.selection.map(x.invert),
domain1 = domain0.map(d3.timeDay.round);
// If empty when rounded, use floor & ceil instead.
if (domain1[0] >= domain1[1]) {
domain1[0] = d3.timeDay.floor(domain0[0]);
domain1[1] = d3.timeDay.ceil(domain0[1]);
}
d3.select(this)
.transition()
.call(brush.move, domain1.map(x));
}
</script>
https://d3js.org/d3.v4.0.0-alpha.49.min.js