Reputation: 904
I'm currently working off of Mike Bostock's Brush & Zoom example although instead of having an overlayed rect object over the svg, I have it attached to my chart so that I can still use mouseover events and whatnot.
I'm having great difficulty combining both brush and zoom functionalities. Both work fine but do not "remember" their current state. For instance, if I'm to pan/resize the brush, all is fine with zoom but if I was to then use mouse/touchpad events to zoom, it would jump along the brush and completely lose where I was in the chart.
How would I get the zoom to "remember" where it was in the brush viewport, and to work fluidly?
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return;
var selection = d3.event.selection;
x.domain(selection.map(x2.invert, x2));
focus.selectAll(".point")
.attr("cx", function(d){
var time = timeParser(d.timestamp);
return x(time);
})
.attr("cy", function(d){
return y(d.value);
});
focus.selectAll(".trendline")
.attr("d", function(d){
return line(d);
});
focus.selectAll(".area")
.attr("d", function(d){
return area(d);
});
focus.select(".axis.x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (selection[1] - selection[0]))
.translate(-selection[0], 0));
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return;
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.selectAll(".point")
.attr("cx", function(d){
var time = timeParser(d.timestamp);
return x(time);
})
.attr("cy", function(d){
return y(d.value);
});
focus.selectAll(".trendline")
.attr("d", function(d){
return line(d);
});
focus.selectAll(".area")
.attr("d", function(d){
return area(d);
});
focus.select(".axis.x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
And here's how the chart looks to give a sort of rough idea:
Upvotes: 4
Views: 2660
Reputation: 38181
You've taken away the rectangle which was used to zoom the chart in your example, but you haven't replaced all of its functionality.
While you call zoom
on some other element (presumably your area graph), you don't update that zoom when brushing here:
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (selection[1] - selection[0]))
.translate(-selection[0], 0));
You need to assign the zoom class to your chart, otherwise this is an empty selection (or a selection of an irrelevant element). Without doing this, the brush changes don't modify the zoom's scale and translate, which means brushing and then zooming will result in a "jump along the brush", losing where you were.
With that change you should be able to get this working: example.
Upvotes: 3