d3.js - 多个转换的单一事件

标签 d3.js

我正在修改 this example有多行并更新它以使用 v4。 The code I wrote有效,但我的更新函数递归的方式特别不优雅:

function repeat() {
  paths.each(d => d.push(random()));
  paths.attr("d", line)
      .attr("transform", null)
    .transition()
      .attr("transform", "translate(" + x(0) + ")")
      .duration(750)
      .ease(d3.easeLinear);
  paths.each(d => d.shift());
  d3.select({}).transition().duration(750).on('end', repeat);
}

请注意空选择的转换只是为了在调用之间创建 750 毫秒的超时。我想这样做:
function repeat() {
  paths.each(d => d.push(random()));
  paths.attr("d", line)
      .attr("transform", null)
    .transition()
      .attr("transform", "translate(" + x(0) + ")")
      .duration(750)
      .ease(d3.easeLinear)
      .on('end', repeat);
  paths.each(d => d.shift());
}

但是,这会导致对 repeat 的多个并发调用。 , 选择中的每个元素一个。

有没有办法可以简化我的代码以摆脱额外的转换?似乎必须有一种更清洁的方法。

最佳答案

D3 转换可能有点棘手,因为结束事件在每个元素转换结束时触发。没有transition.on("endAll", ... ,因此由于您不想在转换结束时触发重复函数两次,因此您使用空转换来延迟调用重复。

您可以使用计数器查看上次转换何时完成,但这也不太干净。最终,在管理具有单独作用于元素的转换的多个事件时,您将获得不太优雅的代码。

相反,由于 d3-transition 的每个元素的计时器和转换事件特定于该元素(即使您将它们设置为一个组,每个元素都有自己的计时器和事件),创建一个特定于每个元素的重复函数:

function scroll(d) {
   d.push(Math.random());

   // Transition
   d3.select(this).attr("transform",null)
     .attr("d",line)
     .transition()
      .attr("transform", "translate(" + x(0) + ")")
      .duration(750) 
      .ease(d3.easeLinear)  
      .on("end",scroll);  // repeat

   d.shift();
}

并调用 selection.each(scroll);现在我们正在使用一个函数管理每个转换(分别处理选择中的每个项目),该函数一次处理选择中的一个项目。

这允许您:
  • 删除空过渡,
  • 访问 d如果您使用 .each() 调用此函数,则直接(而不是在函数中使用 paths.each(... 两次),

  • 其他注意事项:
  • 您可以将此函数应用于您选择的任何路径组,而无需修改函数本身。
  • 被转换的元素是 this

  • 这是在工作:

    let n = 40;
    let random = d3.randomUniform(-1, 1);
    
    let data = [d3.range(n).map(random), d3.range(n).map(random)];
    
    let margin = {top: 6, right: 0, bottom: 6, left: 40};
    let width = 960 - margin.right;
    let height = 120 - margin.top - margin.bottom;
    
    let x = d3.scaleLinear()
        .domain([1, n - 2])
        .range([0, width]);
    
    let y = d3.scaleLinear()
        .domain([-1, 1])
        .range([height, 0]);
    
    let line = d3.line()
        .x(function(d, i) { return x(i); })
        .y(function(d, i) { return y(d); })
        .curve(d3.curveBasis);
    
    let svg = d3.select("body").append("p").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .style("margin-left", -margin.left + "px")
      .append("g")
      	.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    svg.append("defs").append("clipPath")
        .attr("id", "clip")
      .append("rect")
        .attr("width", width)
        .attr("height", height);
    
    svg.append("g")
        .attr("class", "y axis")
        .call(d3.axisLeft(y).ticks(5));
    
    let paths = svg.append('g')
        .attr('id', 'lines')
        .attr('clip-path', 'url(#clip)')
      .selectAll('path').data(data).enter()
      .append('path')
        .attr('class', 'line')
        .attr('stroke', (d, i) => d3.schemeCategory10[i])
        .attr('d', line)
    	.each(scroll);
    	
    	
    function scroll(d) {
       d.push(random());
              
       d3.select(this).attr("transform",null)
         .attr("d",line)
         .transition()
           .attr("transform", "translate(" + x(0) + ")")
           .duration(750)
           .ease(d3.easeLinear)  
           .on("end",scroll);
    
      d.shift();
    }
    #lines {
        fill: none;
        stroke: black;
        stroke-width: 1.5px;
    }
    .y.axis path {
        stroke: black;
    }
    p {
        padding: 40px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

    关于d3.js - 多个转换的单一事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51087514/

    相关文章:

    javascript - 删除 d3.js 中以前的路径并过渡到新数据

    javascript - 具有序数 x 轴的多线图

    javascript - d3 更改 x 轴时间仅勾选整年和整月

    javascript - D3 : Retrieve data from SVG

    javascript - 在 d3 map 投影周围创建一个弯曲的边界

    javascript - 带有传单的 d3 中沿路径的不正确过渡

    javascript - TopoJSON - 将属性添加到 topoJSON 文件

    javascript - 具有可变填充的 D3 包布局

    javascript - 计时器在 d3.js 中运行时是否可以改变时间间隔?

    javascript - 关于 d3.js selectAll 的困惑