Reputation: 3752
I created a graph using D3 v4 that allows x-axis panning and zooming. I'm updating the graph differently when panning and zooming in order to decrease the amount of times we regenerate the graph.
As For Panning
When the user pans left or right i simply update the transform
attribute as such:
path.attr("transform", d3.event.transform)
.
It works well.
As For Zooming
I rescale the domain and re-generate the graph when the user zooms in order to achieve the desired behavior as such:
t = d3.event.transform;
xScale.domain(t.rescaleX(x2).domain()); //update xScale domain
xAxis =d3.axisBottom(xScale)...
focus.select(".axis--x").call(xAxis);
usageAreaPath.attr("d", area); //area being a reference to the generator
usageLinePath.attr('d',line); //line being the name of the generator
The problem is, performing a pan after zoom or zoom after pan results in the graph jumping to different zoom levels. I'm not sure what I'm doing wrong, or how to rebind the scale after zooming/panning to update the proper scale, but I have attached a JSBIN below:
http://jsbin.com/webowajola/edit?js,output
Upvotes: 2
Views: 1482
Reputation: 900
There are two separate problems with your code:
1. Translate
You used .attr("transform", "translate( 0, 80)")
the wrong way. Remove all the .attr("transform", "translate(0," + 80 + ")")
from your <path>
, <circle>
, axes and area and set the offset like this:
// Usage x-axis
var gX = focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + (height + margin.top) + ")")
.call(xAxis);
// Focus Viewpoint
var focus = svg.append("g")
.attr("class", "focus")
.attr('transform', "translate("
+ margin.left + "," + (margin.top + 80)
+ ")"
);
Doing this way, the whole chart is shifted downwards together in the <g>
.
2. panRight()
You are moving the circles and the lines twice: First with the new scale, second with the .attr("transform", d3.event.transform)
. So just remove following three lines
usageAreaPath.attr("transform", d3.event.transform);
usageLinePath.attr("transform", d3.event.transform);
circles.attr("transform", d3.event.transform);
Edit
I just realized, that the zoomed function is not working at all. The redraw function is called all the time during panning (also in my solution). Therefore the panning is executed twice. If the "if statement" in the zoomed function would work, the panRight() function would be necessary. So focus on this if/else statement. One option could be to distinguish between mouse wheel and drag event, e.g.
if(d3.event.sourceEvent.toString() === "[object MouseEvent]")
. So the redraw function will not be called during panning, but some scaling issues remain. Maybe this could help.
Upvotes: 1
Reputation: 958
i dont know whats is you aim for, i thing the answer above me it settle your thing, maybe you just didnt stop the event use d3.event.defaultPrevented()
if you want stop the event
function panRight(){
d3.event.defaultPrevented()//use it so it will reset the event
console.log('panRight',d3.event.transform);
var new_xScale = d3.event.transform.rescaleX(x2)
gX.call(xAxis.scale(new_xScale));
usageAreaPath.attr("transform", d3.event.transform);
usageLinePath.attr("transform", d3.event.transform);
circles.attr("transform", d3.event.transform);
}
//the result is normal ordinary chart
but if you playing with unremarking the d3.event.defaultPrevented()
on redraw() the result is one weird chart
function redraw(){
//d3.event.defaultPrevented()
var domain,
minBuffer,
maxBuffer,
panDelta1,
panDelta2,
t;
t = d3.event.transform;
console.log('redraw',d3.event.transform);
// console.log(t.rescaleX(x2).domain());
// console.log(xScale.domain());
//d3.event.defaultPrevented()
xScale.domain(t.rescaleX(x2).domain());
xAxis = d3.axisBottom(xScale).tickSize(0).tickFormat(d3.timeFormat('%b'));
focus.select(".axis--x").call(xAxis);
usageAreaPath.attr("d", area);
usageLinePath.attr('d',line);
//d3.event.defaultPrevented()
focus.selectAll('.circle')
.attr('cx', function(d) { return xScale(getDate(d)); })
.attr('cy', function(d) { return yScale(d.kWh); })
.attr("transform", "translate(0," + 80 + ")");
}
Upvotes: -1
Reputation: 1304
If you are updating the graph differently when panning and zooming in order to decrease the amount of times we regenerate the graph just add the check in the zoomed function as below,
function zoomed(){
if(d3.event.transform.x !== 0 && d3.event.transform.y !== 0){
redraw();
}
}
Here is the link to the updated working jsbin.
I hope it will solve your graph regeneration problem.
Upvotes: 1