This examples demonstrates how to use D3’s brush component to implement focus + context zooming. Click and drag in the small chart below to pan or zoom.
forked from mbostock‘s block: Focus+Context via Brushing
forked from renecnielsen‘s block: Focus+Context via Brushing
forked from renecnielsen‘s block: Focus+Context via Brushing
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.area {
fill: rgb(233, 233, 233);
clip-path: url(#clip);
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.brush .extent {
stroke: #fff;
fill-opacity: .125;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 20, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%b %Y").parse;
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.price); });
var area2 = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.price); });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.csv("sp500.csv", type, function(error, data) {
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([0, d3.max(data.map(function(d) { return d.price; }))]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
});
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.date = parseDate(d.date);
d.price = +d.price;
return d;
}
</script>
date,price
May 2012,1270.09
Jun 2012,1270.2
Jul 2012,1276.66
Aug 2012,1303.82
Sep 2012,1335.85
Oct 2012,1377.94
Nov 2012,1400.63
Dec 2012,1418.3
Jan 2013,1438.24
Feb 2013,1406.82
Mar 2013,1420.86
Apr 2013,1482.37
May 2013,1530.62
Jun 2013,1503.35
Jul 2013,1455.27
Aug 2013,1473.99
Sep 2013,1526.75
Oct 2013,1549.38
Nov 2013,1481.14
Dec 2013,1468.36
Jan 2014,1378.55
Feb 2014,1330.63
Mar 2014,1322.7
Apr 2014,1385.59
May 2014,1400.38
Jun 2014,1280
Jul 2014,1267.38
Aug 2014,1282.83
Sep 2014,1166.36
Oct 2014,968.75
Nov 2014,896.24
Dec 2014,903.25
Jan 2015,825.88
Feb 2015,735.09
Mar 2015,797.87
Apr 2015,872.81
May 2015,919.14
Jun 2015,919.32
Jul 2015,987.48