D3.js将变量传递给函数

时间:2015-07-20 19:31:59

标签: javascript function debugging variables d3.js

我正在尝试修改每秒更新一次折线图的代码。

该函数采用一个名为path的变量,并使用它在屏幕上制作动画,就像线图正在移动一样。

这是一段代码段。 (整个代码,工作示例和引文在本问题的最后部分进行了链接。)

var path = svg.append("g")
    .attr("clip-path", "url(#clip)")
  .append("path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line);

tick();

function tick() {

  // push a new data point onto the back
  data.push(random());

  // redraw the line, and slide it to the left
  path
      .attr("d", line)
      .attr("transform", null)
    .transition()
      .duration(500)
      .ease("linear")
      .attr("transform", "translate(" + x(-1) + ",0)")
      .each("end", tick);

  // pop the old data point off the front
  data.shift();

}

我要做的是更改函数,使其将路径变量作为参数,以便我可以使用相同的函数(tick)来修改各种不同的路径。

但是,当我将上面的代码改为这样的代码时:

   tick(path);

   function tick(path) { /*same as before*/ }

我得到TypeError path.attr不是函数。

而且,如果相反,我会尝试这样做:

   tick(d3.select(path));

   function tick(path) { /*same as before*/ }

我收到错误:无法读取属性'长度'未定义的。

有人能帮助我吗?

工作示例:向下滚动到第二个图表:http://bost.ocks.org/mike/path/

工作代码:https://gist.githubusercontent.com/mbostock/1642874/raw/692ec5980f12f4b0cb38c43b41045fe2fe8e3b9e/index.html

引用代码,例如:Github上的mbostock

1 个答案:

答案 0 :(得分:2)

错误不是由第一次调用tick(path)引起的,而是由tick()作为.each("end", tick);注册的回调调用后续调用引起的。这些调用不会将所需的参数path传递给您的函数。而且,看看D3的源代码,我没有看到将此参数传递给回调的方法。

您可以通过使用您希望其操作的路径参数化回调函数来规避这些问题:

tick(path)();

function tick(path) {
    var paramTick = function() {
      // push a new data point onto the back
      path.datum().push(random());

      // redraw the line, and slide it to the left
      path
          .attr("d", line)
          .attr("transform", null)
        .transition()
          .duration(500)
          .ease("linear")
          .attr("transform", "translate(" + x(-1) + ",0)")
          .each("end", paramTick);

      // pop the old data point off the front
      path.datum().shift();
    };
    return paramTick;
}

这个使用闭包来保存对未来调用的路径的引用。函数tick(path)定义了一个内部函数paramTick(),它基本上是您之前使用的函数。但是,它通过闭包保存对参数path的引用。请注意,它将引用传递给自身作为end事件的回调参数而不是tick()。通过这种方式,您最终会得到一个回调,该回调通过调用

进行参数化
tick(path)();

tick(path)的调用返回渲染逻辑的参数化版本,该版本由第二组括号立即执行。

我设置了一个工作JSFiddle移动两条路径来证明这一点。

虽然这确实回答了你的问题,但似乎并不是解决问题的完美解决方案。看一下移动两条路径的示例,您会发现它们会偶尔会略微不同步。这是由于每个路径使用不同的转换而导致的,这些转换不会完全同步。

在我看来,更好的方法是将多个路径组合成一个g并将过渡应用于该组。只需稍微修改原始代码(JSFiddle v2),即可实现所有路径的平滑同步移动。

var data = [
        d3.range(n).map(random),
        d3.range(n).map(random)
];

var paths = group.selectAll("path")
        .data(data)
        .enter()
          .append("path")
            .attr("class", function(d,i) {
                return "line" + i;
            })
            .attr("d", line);

tick();

function tick() {
      // push a new data point onto the back
    paths.each(function(d) {d.push(random());});

    // redraw the line
    paths
        .attr("d", line);

    // Apply the transition to the group
    group
        .attr("transform", null)
      .transition()
        .duration(500)
        .ease("linear")
        .attr("transform", "translate(" + x(-1) + ",0)")
        .each("end", tick);

    // pop the old data point off the front
    paths.each(function(d) {d.shift();});
}