Froked from mbostock's block: Brush Handles (now in d3v4).
See issue #14 and crossfilter.
license: gpl-3.0 |
Froked from mbostock's block: Brush Handles (now in d3v4).
See issue #14 and crossfilter.
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
circle { | |
fill-opacity: 0.2; | |
transition: fill-opacity 250ms linear; | |
} | |
circle.active { | |
stroke: #f00; | |
} | |
</style> | |
<svg width="960" height="500"></svg> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script> | |
var data = d3.range(800).map(Math.random); | |
var svg = d3.select("svg"), | |
margin = {top: 194, right: 50, bottom: 214, left: 50}, | |
width = +svg.attr("width") - margin.left - margin.right, | |
height = +svg.attr("height") - margin.top - margin.bottom, | |
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var x = d3.scaleLinear().range([0, width]), | |
y = d3.randomNormal(height / 2, height / 8); | |
var brush = d3.brushX() | |
.extent([[0, 0], [width, height]]) | |
.on("start brush end", brushmoved); | |
g.append("g") | |
.attr("class", "axis axis--x") | |
.attr("transform", "translate(0," + height + ")") | |
.call(d3.axisBottom(x)); | |
var circle = g.append("g") | |
.attr("class", "circle") | |
.selectAll("circle") | |
.data(data) | |
.enter().append("circle") | |
.attr("transform", function(d) { return "translate(" + x(d) + "," + y() + ")"; }) | |
.attr("r", 3.5); | |
var gBrush = g.append("g") | |
.attr("class", "brush") | |
.call(brush); | |
// style brush resize handle | |
// https://github.com/crossfilter/crossfilter/blob/gh-pages/index.html#L466 | |
var brushResizePath = function(d) { | |
var e = +(d.type == "e"), | |
x = e ? 1 : -1, | |
y = height / 2; | |
return "M" + (.5 * x) + "," + y + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6) + "V" + (2 * y - 6) + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y) + "Z" + "M" + (2.5 * x) + "," + (y + 8) + "V" + (2 * y - 8) + "M" + (4.5 * x) + "," + (y + 8) + "V" + (2 * y - 8); | |
} | |
var handle = gBrush.selectAll(".handle--custom") | |
.data([{type: "w"}, {type: "e"}]) | |
.enter().append("path") | |
.attr("class", "handle--custom") | |
.attr("stroke", "#000") | |
.attr("cursor", "ew-resize") | |
.attr("d", brushResizePath); | |
gBrush.call(brush.move, [0.3, 0.5].map(x)); | |
function brushmoved() { | |
var s = d3.event.selection; | |
if (s == null) { | |
handle.attr("display", "none"); | |
circle.classed("active", false); | |
} else { | |
var sx = s.map(x.invert); | |
circle.classed("active", function(d) { return sx[0] <= d && d <= sx[1]; }); | |
handle.attr("display", null).attr("transform", function(d, i) { return "translate(" + [ s[i], - height / 4] + ")"; }); | |
} | |
} | |
</script> |