Reputation: 31
I am trying ti implement a zoom and brush chart with D3.js with an initial zoom. The initial zoom covers only about 10% of the brushable extent - this works correctly. When I zoom on the chart the first time, the zoom does not take into account the initial state.
Here's the graph initially:
And after the first zoom:
Here's a plunkr, and the relevant code:
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
//To set initial zoom level in graph
var d0 = data[0].date,
d1 = data[data.length-1].date;
svg.call(zoom).transition()
.duration(1500)
.call(zoom.transform, d3.zoomIdentity
.scale(width / (x(d1) - x(d0)))
.translate(-x(d0), 0));
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
Why are zoom events not relative to the initial zoom state?
Upvotes: 3
Views: 347
Reputation: 38151
Your code works fine if, you don't zoom over the chart plot area: you can zoom on the axes or margins for example. This is a hint as to what is happening:
The zoom is applied to two elements:
svg.append("rect")
...
.call(zoom);
And:
svg.call(zoom)
This means we are keeping track of two zoom states - but you only apply an initial state to one:
svg.call(zoom).transition()
.duration(1500)
.call(zoom.transform, d3.zoomIdentity
.scale(width / (x(d1) - x(d0)))
.translate(-x(d0), 0));
This is why you can zoom in the margins and the chart works as intended, but doesn't work if you zoom over the rect that covers the plot area. Let's just apply the zoom once on one element:
var rect = svg.append("rect")
...
.call(zoom);
rect.transition()
.duration(1500)
.call(zoom.transform, d3.zoomIdentity
.scale(width / (x(d1) - x(d0)))
.translate(-x(d0), 0));
Here's an updated plunkr
I've removed the script.js file as it duplicated script in the index.html file.
I had issues with your original plunkr in Firefox, I have not addressed those, I used Chrome to view
Upvotes: 2