viewof selection = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
const brush = d3.brushX()
.on("start brush end", brushed)
.on("end.snap", brushended);
const bar = svg.append("g")
.attr("fill", "#fafafa")
.selectAll("rect")
.data(x.domain())
.join("rect")
.attr("x", d => x(d) - x.step() / 2)
.attr("height", height)
.attr("width", x.step());
svg.append("g")
.attr("font-family", "var(--sans-serif)")
.attr("text-anchor", "middle")
.attr("transform", `translate(${x.bandwidth() / 2},${height / 2})`)
.selectAll("text")
.data(x.domain())
.join("text")
.attr("x", d => x(d))
.attr("dy", "0.35em")
.text(d => d);
svg.append("g")
.call(brush);
function brushed({selection}) {
if (selection) {
const range = x.domain().map(x);
const i0 = d3.bisectRight(range, selection[0]);
const i1 = d3.bisectRight(range, selection[1]);
bar.attr("fill", (d, i) => i0 <= i && i < i1 ? "orange" : null);
svg.property("value", x.domain().slice(i0, i1)).dispatch("input");
} else {
bar.attr("fill", null);
svg.property("value", []).dispatch("input");
}
}
function brushended({selection, sourceEvent}) {
if (!sourceEvent || !selection) return;
const range = x.domain().map(x), dx = x.step() / 2;
const x0 = range[d3.bisectRight(range, selection[0])] - dx;
const x1 = range[d3.bisectRight(range, selection[1]) - 1] + dx;
d3.select(this).transition().call(brush.move, x1 > x0 ? [x0, x1] : null);
}
return svg.property("value", []).node();
}