为什么动画d3 svg线在IE9中不与轴移位同步,但在IE11和Chrome中同步



以下是两个jsfiddle:

调用JSFiddle 1中的tick的代码:

path.transition()
.duration(duration)
.ease("linear")
.attr("transform", "translate(" + x(now - (n - 1) * duration) + ")")
.each("end", tick);

调用JSFiddle 2中的tick的代码:

axis.transition()
.duration(duration)
.ease("linear")
.call(xAxis)
.each("end", tick);

做一个测试1:

  1. 使用IE 11Chrome浏览器打开JSFiddle 1和JSFiddle2。
  2. 观察动画svg行

做一个测试2:

  1. 使用IE9浏览器打开JSFiddle2和jsfiddle1。
  2. 观察动画svg行

在测试1中,我观察到动画svg线的起点随着轴的移动而移动,因此它在视觉上看起来是同步的。因此,您将看到一条平滑的动画线。

在测试2中,我观察到svg线的起点没有随着轴的移动而移动,因此从视觉上看它是不同步的。因此,您会看到一条有点奇怪的抖动线。

有没有人知道是什么原因导致这种情况发生?如何在IE9中解决这个问题?

我上传了一个视频来演示这个问题:视频1

编辑

根据Amelia的回答,我上传了custom tween function: video 2的改进版本

我对她的回答做了一些小的调整,并使用x(t - n + 2)而不是x(t - n + 1)。尽管这条线不光滑,但至少它现在与轴位移同步:

我怀疑问题仅仅是IE9不支持requestAnimationFrame()方法。D3使用requestAnimationFrame(如果可用)来同步转场。

这是有区别的,因为requestAnimationFrame方法将一系列连续的调用捆绑到一个"帧"中——并向它们传递相同的时间戳值。如果没有requestAnimationFrame方法,每个转换将获得一个不同的时间戳,延迟时间取决于浏览器完成前一个任务所花费的时间。

不幸的是,对于坚持使用过时浏览器的人来说,没有简单的解决方案可以解决这个问题。

可以做的是尽量使你的代码高效。例如,当前您正在创建单独的转换,以相同的转换量来移动每个路径。如果你创建了一个<g>元素并在其中绘制了所有的路径,那么你只需要一个变换和一个过渡。

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 */

然后在tick()函数中:

  • 当你重画线条时,不要在路径元素上设置任何变换,而是用

    清除plot变换
    plot.attr("transform", null);
    
  • 替换所有路径转换
     plot.transition()
         .duration(duration)
         .ease("linear")
         .attr("transform", "translate(" + x(t - n + 1) + ")");
    
http://jsfiddle.net/QBDGB/155/

(让我知道这在IE9中是否有明显的改进——IE11仿真工具并没有真正显示这个问题,所以我无法有效地测试。)

顺便说一下,你也可以通过使用选择&数据连接来绘制不同的线。在d3中查看更多关于选择和连接的教程。

编辑

感谢您的反馈,很抱歉它仍然没有做出改进。下面的方法更复杂,如果您是d3新手,可能很难理解,但它应该强制同步。需要注意的是,动画可能仍然是跳跃的,但是线和轴应该同时跳跃!

我们的想法是只使用一个转场,然后在转场的每个刻度更新情节转换和轴。这是使用自定义的"tween"函数完成的。它假设你已经做了上面的修改。

特别地,我不允许默认的轴函数为每个子组件创建单独的过渡,而是使用与线条相同的方法:绘制不带过渡的轴,然后使用转换将其侧向移动。这两个转换都在同一个渐变函数中应用。

 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

有一个额外的复杂性:x轴<g>元素已经有一个transform属性,将它移动到图形的底部。我每次都可以重复这个转换,这样转换后的属性看起来就像axis.attr("transform", "translate(0," + height + ")" + inter(t) );。然而,我决定通过使用嵌套的<g>元素作为轴来保持简单:垂直转换应用于外部组,水平转换应用于内部组:

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);

注意,我还将.outerTickSize(0)添加到轴定义中。这可以防止轴在域的开始和结束处绘制额外的标记-外部标记在Y轴的底部出现奇怪的闪烁线,每次重新绘制轴时出现,然后在轴移动时立即消失。

http://jsfiddle.net/QBDGB/160/

注:如果你的客户仍然感到失望,冷静下来。礼貌地提醒他或她IE9是一个过时的浏览器,没有最新浏览器生成流畅动画的能力。如果有人想要最新的&最伟大的网站,他们需要使用最新的&最大的浏览器。

相关内容

最新更新