I'm struggling to take a stacked area chart in D3 and add brushing features. I've managed to generate both the large (focus) and small (context) axes, and the plot looks fine to start. My problems is that the brushing features don't work at all. I've been banging my head on this for some time, to no avail, and can't figure out where the problem is. Any help would be much appreciated!
Click here to see the current state of the plot. Here's the code:
<!-- language: lang-js -->
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.tag text {
text-anchor: end;
}
</style>
<body onLoad="updateData()">
<div id="option" style="font-size:14px;">
<form>
Number of tags:<input value="5" id="nTags_select"></input>
<input name="updateButton"
type="button"
value="Update"
onclick="updateData()" />
</form>
</div>
<script src="http://d3js.org/d3.v3.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("%Y-%m-%d").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 color = d3.scale.category20();
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("basis")
.x(function(d) { return x(d.date); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
var area2 = d3.svg.area()
.interpolate("basis")
.x(function(d) { return x2(d.date); })
.y0(function(d) { return y2(d.y0); })
.y1(function(d) { return y2(d.y0 + d.y); });
var stack = d3.layout.stack()
.values(function(d) { return d.values; });
var oRequest = new XMLHttpRequest();
var sURL = "data100.tsv";
oRequest.open("GET",sURL,false);
oRequest.setRequestHeader("User-Agent",navigator.userAgent);
oRequest.send(null)
var data = oRequest.responseText;
var data = d3.tsv.parse(data);
data.forEach(function(d) {
d.date = parseDate(d.date);
});
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
var allTags = stack(color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, y: +d[name]};
})
};
}));
function updateData(){
var nTags = document.getElementById('nTags_select').value;
tags=allTags.slice(0,nTags);
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0,d3.max(tags, function(d) { return d3.max(d.values, function (d) { return d.y + d.y0; }); })]);
x2.domain(x.domain());
y2.domain(y.domain());
d3.select("svg").remove();
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("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
focus.selectAll('path')
.data(tags)
.enter()
.append('path')
.attr('clip-path','url(#clip)')
.attr("d", function(d) { return area(d.values); })
.attr('class','focus')
.style("fill", function(d) { return color(d.name); });
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
context.selectAll('path')
.data(tags)
.enter()
.append('path')
.attr('class','context')
.attr("d", function(d) { return area2(d.values); })
.style("fill", function(d) { return color(d.name); });
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);
focus.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.y0 + d.value.y / 2) + ")"; })
.attr("x", -6)
.attr("dy", "-.35em")
.text(function(d) { return d.name; });
};
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.selectAll("path.focus").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
</script>