简体   繁体   English

D3.js将变量传递给函数

[英]D3.js pass variable into function

I am trying to modify code that updates a line graph every second. 我正在尝试修改每秒更新一次折线图的代码。

The function takes a variable named path and uses it to make an animation on screen as though the line graph is moving. 该函数采用名为path的变量,并使用它在屏幕上制作动画,就像折线图正在移动一样。

Here is a code snippet. 这是一个代码片段。 (The entire code, working example, and citation is linked at the end of this question.) (整个代码,工作示例和引用在此问题的末尾链接。)

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

}

What I am trying to do is change the function so that it takes the path variable as an argument, so that I can use the same function (tick) for modifying various different paths. 我正在尝试做的是更改函数,使其将path变量作为参数,以便我可以使用相同的函数(刻度)来修改各种不同的路径。

However, when I change the above code to something like this: 但是,当我将上面的代码更改为这样的内容时:

   tick(path);

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

I get the TypeError path.attr is not a function. 我得到TypeError path.attr不是一个函数。

And, if instead, I try to do something like this: 而且,如果相反,我会尝试执行以下操作:

   tick(d3.select(path));

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

I get the error: cannot read property 'length' of undefined. 我收到错误消息:无法读取未定义的属性“ length”。

Can someone help me out? 有人可以帮我吗?

Working example: Scroll down to second graph: http://bost.ocks.org/mike/path/ 工作示例:向下滚动到第二张图: http : //bost.ocks.org/mike/path/

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

Citation for code, example: mbostock on Github 引用代码,例如:Github上的mbostock

The error is not caused by the first call to tick(path) but by subsequent calls when tick() gets called as a callback you registered by .each("end", tick); 该错误不是由第一次调用tick(path)引起的,而是由tick()作为您通过.each("end", tick);注册的回调调用时的后续调用引起的.each("end", tick); . These calls will not pass the required parameter path to your function. 这些调用不会将所需的参数path传递给函数。 And, looking at D3's source I don't see a way of passing this parameter to the callback. 而且,查看D3的源代码,我看不到将此参数传递给回调的方法。

You can circumvent these issues by parameterising your callback function with the path you want it to act on: 您可以通过使用希望其作用的路径参数化回调函数来规避这些问题:

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

This one uses a closure to save the reference to the path for future calls. 这使用闭包保存对路径的引用,以供将来调用。 The function tick(path) defines an inner function paramTick() which is basically the function you used previously. 函数tick(path)定义了一个内部函数paramTick() ,它基本上是您先前使用的函数。 It does, however, save the reference to the parameter path by means of a closure. 但是,它确实通过闭包保存了对参数path的引用。 Notice, that it passes the reference to itself as the callback parameter for the end event instead of tick() . 注意,它将引用传递给自身作为end事件的回调参数,而不是tick() This way you'll end up with a callback which gets parameterised by the call 这样,您最终将获得一个由调用参数化的回调

tick(path)();

The call to tick(path) returns the parameterised version of your rendering logic which is immediately executed by the second set of parentheses. 调用tick(path)返回渲染逻辑的参数化版本,该参数版本将由第二组括号立即执行。

I set up a working JSFiddle moving two paths to demonstrate this. 我建立了一个工作的JSFiddle,并通过两条路径进行了演示。


Although this does answer your question, it doesn't seem to be a perfect solution for the problem. 尽管这确实回答了您的问题,但它似乎并不是解决该问题的理想解决方案。 Looking at the example moving two paths you will notice that they will get slightly out of sync every now and then. 在移动两个路径的示例中,您会发现它们有时会不同步。 This is caused by utilizing different transitions for each path, which will not get perfectly synchronized. 这是由于对每个路径使用不同的过渡而导致的,这些过渡不会得到完全同步。

In my opinion the better approch would be to group multiple paths into one g and apply the transition to this group. 在我看来,更好的方法是将多个路径分组为一个g并将转换应用于该组。 With only slight modifications to your original code ( JSFiddle v2 ) this will give a smooth, synchronized movement of all paths. 只需对原始代码( 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();});
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM