I suspect that the problem is simply that IE9 does not support the requestAnimationFrame()
method. D3 uses requestAnimationFrame if available to synchronize transitions.
That makes a difference because the requestAnimationFrame method bundles a series of consecutive calls into a single "frame" -- and passes them all the same timestamp value. Without the requestAnimationFrame method, each transition will get a different timestamp, delayed by however long it took the browser to complete the previous task.
Unfortunately, there's no easy solution for how to fix it for someone who insists on using an out-of-date browser.
What you can do is try to make your code as efficient as possible. For example, currently you are creating separate transitions to shift each of your paths by the same transform amount. If instead you created a <g>
element and drew all the paths within it, then you would only need one transform, and one transition.
var graph = g.append("svg")
.attr("width", width)
.attr("height", height + margin.top + margin.bottom);
var plot = graph.append("g").attr("class", "plot");
var path1 = plot.append("g").append("path")
/* etc for the other paths */
And then in your tick()
function:
don't set any transforms on the path elements when you redraw the lines, instead clear the plot transform with
plot.attr("transform", null);
replace all the path transitions with
plot.transition()
.duration(duration)
.ease("linear")
.attr("transform", "translate(" + x(t - n + 1) + ")");
http://jsfiddle.net/QBDGB/155/
(Let me know if that's a noticeable improvement in IE9 -- the IE11 emulation tools weren't really showing the problem, so I can't test effectively.)
By the way, you could also shorten your code a lot by using a selection & datajoin to draw your different lines. Check out the tutorials for more on selections and joins in d3.
Edit
Thanks for the feedback, and sorry it's still not making an improvement. The following approach is more complicated, and might be hard to follow if you're new to d3, but it should force the synchronization. Be warned that the animation will still probably be jumpy, but the line and axis should jump at the same time!
The idea is to only use one transition, and then at every tick of the transition update both the plot translation and the axis. That is done using a custom "tween" function. It assumes you've already made the changes above.
In particular, instead of allowing the default axis function to create separate transitions for each sub-component, I use the same approach as the lines: draw the axis without a transition, and then use a transform to shift it sideways. Both transforms are applied within the same tween function.
plot.attr("transform", null);
// redraw the axis, without transition
axis.call(xAxis).attr("transform", null);
// slide the line left
plot.transition()
.duration(duration)
.ease("linear")
.attrTween("transform",
function(){
//this function is run for every element
//in the selection (which only has one element).
//create an interpolator function
var inter = d3.interpolateString("translate(0,0)",
"translate(" + x(t - n + 1) + ")");
return function(t) {
//this function is called at every "tick"
//of the transition
//transition the axis
axis.attr("transform", inter(t) );
//return the value to transition the plot
return inter(t);
};
})
.each("end", tick); //loop
There was just one extra complication: The x-axis <g>
element already had a transform attribute, shifting it down to the bottom of the graph. I could have repeated that transform, each time, so that the transitioned attribute would look like axis.attr("transform", "translate(0," + height + ")" + inter(t) );
. However, I decided to keep it simple by using nested <g>
elements for the axis: the vertical transform is applied on an outer group, and the horizontal transforms on the inner group:
var xAxis = d3.svg.axis().scale(x)
.orient("bottom")
.outerTickSize(0);
var axis = graph.append("g") //outer group handles the vertical transform
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.append("g")
//this nested <g> will be stored in the `axis` variable!
//and therefore will get the horizontal transform attribute
.call(x.axis = xAxis);
Notice that I also added .outerTickSize(0)
to the axis definition. That prevents the axis from drawing an extra tick mark at the start and end of the domain -- the outer tick was appearing as a strange flickering line at the base of Y axis, appearing every time the axis was redrawn and then immediately disappearing as the axis shifted.
http://jsfiddle.net/QBDGB/160/
P.S. If your client is still disappointed, calmly & politely remind him or her that IE9 is an out-of-date browser that doesn't have the capabilities of the latest browsers for generating smooth animation. If someone wants the latest & greatest websites, they need to use the latest & greatest browsers.