viewof focus = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, focusHeight])
.style("display", "block");
const brush = d3.brushX()
.extent([[margin.left, 0.5], [width - margin.right, focusHeight - 10]])
.on("brush", brushed)
.on("end", brushended);
const initialBrushMax = 10;
const stackedBarGroup = svg.append("g")
.call(g => stackedBars(g, x, y.copy().range([focusHeight - marginFocus.bottom, 4]), data))
const dx = (x.bandwidth() * x.paddingInner())/2;
const defaultSelection = [x.range()[0] + dx, x.range()[0] + x.bandwidth() * initialBrushMax + dx]
const gb = svg.append("g")
.call(brush)
.call(brush.move, defaultSelection);
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]);
stackedBarGroup.selectAll("g").selectAll("rect").attr("filter", (d, i) => (i0 <= i) && (i < i1) ? "invert(100%)" : "none");
svg.property("value", x.domain().slice(i0, i1))
.dispatch("input");
} else {
stackedBarGroup.selectAselectAll("rect")
.attr("filter", "none");
svg.property("value", []).dispatch("input");
}
}
function brushended({selection, sourceEvent}) {
if (!sourceEvent) {
return
};
if (!selection) {
d3.select(this).transition().call(brush.move, defaultSelection);
}
const range = x.domain().map(x);
const x0 = range[d3.bisectRight(range, selection[0])] - dx;
const x1 = range[d3.bisectRight(range, selection[1]) -1 ] + x.bandwidth() + dx;
if (x0 === x1) {
d3.select(this).transition().call(brush.move, defaultSelection);
}
d3.select(this)
.transition()
.call(brush.move, x1 > x0 ? [x0, x1] : null);
}
return svg.node();
}