Javascript D3过渡线发生两次

Javascript D3过渡线发生两次,javascript,d3.js,Javascript,D3.js,我对D3非常陌生,我正试图根据这里的一个片段粗略地制作一个简单的实时图表: 我希望能够在移动的实时图表中添加许多行,并从web套接字更新这些行(我知道怎么做!!) 当我尝试添加第二行时,图表不会顺利更新,我认为转换被调用了两次。感谢您的帮助 代码如下,但这里有一把小提琴 var n=243; var random=d3.randomNormal(0.2); var持续时间=500; var now=新日期(Date.now()-持续时间); var svg=d3。选择(“svg”), 边距={顶

我对D3非常陌生,我正试图根据这里的一个片段粗略地制作一个简单的实时图表:

我希望能够在移动的实时图表中添加许多行,并从web套接字更新这些行(我知道怎么做!!)

当我尝试添加第二行时,图表不会顺利更新,我认为转换被调用了两次。感谢您的帮助

代码如下,但这里有一把小提琴

var n=243;
var random=d3.randomNormal(0.2);
var持续时间=500;
var now=新日期(Date.now()-持续时间);
var svg=d3。选择(“svg”),
边距={顶部:20,右侧:20,底部:20,左侧:40},
宽度=+svg.attr(“宽度”)-margin.left-margin.right,
高度=+svg.attr(“高度”)-margin.top-margin.bottom,
g=svg.append(“g”).attr(“transform”、“translate”(+margin.left+)、“+margin.top+”);
var x=d3.scaleTime()
.domain([现在-(n-2)*持续时间,现在-持续时间])
.范围([0,宽度]);
变量y=d3.scaleLinear()
.domain([-1,1])
.范围([高度,0]);
var lineNames=[];
变量行={};
变量数据={};
var line=d3.line()
.曲线(d3.曲线基)
.x(函数(d,i){返回x(现在-(n-1-i)*持续时间);})
.y(函数(d,i){返回y(d);});
g、 附加(“defs”)。附加(“clipPath”)
.attr(“id”、“剪辑”)
.append(“rect”)
.attr(“宽度”,宽度)
.attr(“高度”,高度);
var轴=g.append(“g”)
.attr(“类”、“轴--x”)
.attr(“变换”、“平移(0)、+y(0)+”)
.call(d3.axisBottom(x));
g、 附加(“g”)
.attr(“类”、“轴--y”)
.调用(d3.左(y));
创建线(“一”);
createLine(“两个”);
d3.选择全部(“.行”)
.transition()
.持续时间(持续时间)
.ease(d3.easeLinear)
。开启(“开始”,勾选);
函数createLine(名称){
lineNames.push(name);
数据[名称]=d3.range(n).map(随机);
行[名称]=d3.line()
.曲线(d3.曲线基)
.x(函数(d,i){返回x(现在-(n-1-i)*持续时间);})
.y(函数(d,i){返回y(d);});
g、 附加(“g”)
.attr(“剪辑路径”、“url(#剪辑)”)
.append(“路径”)
.数据(数据[名称])
.attr(“类”、“行”);
}
函数tick(){
var指数;
var i;
对于(i=0;i
问题似乎是当一行调用“tick”时更新所有行的数据。您会注意到,您的示例在1行中效果很好,而在3行中效果更差。这是因为函数tick中有for循环。D3中的数据绑定非常有用,但需要一些时间才能习惯使用
我所做的两个主要代码更改是将line()设为变量,并从tick函数中删除for循环。更新的fiddle(我试图注释掉原始代码,这样您就可以很容易地看到差异):


清理小提琴:

问题似乎是在一行调用“tick”时更新所有行的数据。您会注意到,您的示例在1行中效果很好,而在3行中效果更差。这是因为函数tick中有for循环。D3中的数据绑定非常有用,但需要一些时间才能习惯使用
我所做的两个主要代码更改是将line()设为变量,并从tick函数中删除for循环。更新的fiddle(我试图注释掉原始代码,这样您就可以很容易地看到差异):


清理小提琴:

我最初的倾向是,tick函数被调用的频率是它应该调用的两倍。我可能是错的,但看起来函数每行调用一次,但每次调用都会影响两行。我本以为每一行都会打勾,只影响那一行。我已经添加了一个提琴来显示问题。我最初的倾向是,tick函数被调用的频率是它应该调用的两倍。我可能是错的,但看起来函数每行调用一次,但每次调用都会影响两行。我本以为每一行都会打勾,只影响那一行。或者勾选被调用一次并影响两行。我添加了一个小提琴来显示问题。好的,我想我有一点理解。我想我把“line”函数和屏幕上表示线条的路径搞混了。你的提琴有点让人困惑,但我还是想弄明白了。我在这里整理了一下:对不起,小提琴太乱了。我试图在给出答案和展示答案之间取得平衡。在开发工具的tick函数中设置一个断点非常有用,然后看看“this”包含什么。该框架将为您跟踪许多事情。我清理了小提琴,把它添加到原来的帖子里。好吧,我想我有点理解了。我想我把“line”函数和屏幕上表示线条的路径搞混了。你的提琴有点让人困惑,但我还是想弄明白了。我在这里整理了一下:对不起,小提琴太乱了。我试图在给出答案和展示答案之间取得平衡。在开发工具的tick函数中设置一个断点非常有用,然后看看“this”包含什么。该框架将为您跟踪许多事情。我清理了小提琴,把它添加到原来的帖子里。
var n = 243;
var random = d3.randomNormal(0, .2);

var duration = 500;
var now = new Date(Date.now() - duration);

var svg = d3.select("svg"),
    margin = {top: 20, right: 20, bottom: 20, left: 40},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleTime()
    .domain([now - (n - 2) * duration, now - duration])
    .range([0, width]);

var y = d3.scaleLinear()
    .domain([-1, 1])
    .range([height, 0]);

var lineNames = [];
var lines = {};
var data = {};

var line = d3.line()
    .curve(d3.curveBasis)
    .x(function(d, i) { return x(now - (n - 1 - i) * duration); })
    .y(function(d, i) { return y(d); });

g.append("defs").append("clipPath")
    .attr("id", "clip")
  .append("rect")
    .attr("width", width)
    .attr("height", height);

var axis = g.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0," + y(0) + ")")
    .call(d3.axisBottom(x));

g.append("g")
    .attr("class", "axis axis--y")
    .call(d3.axisLeft(y));

createLine("one");
createLine("two");

d3.selectAll(".line")
    .transition()
        .duration(duration)
        .ease(d3.easeLinear)
        .on("start", tick);

function createLine(name) {
    lineNames.push(name);

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

    lines[name] = d3.line()
        .curve(d3.curveBasis)
        .x(function(d, i) { return x(now - (n - 1 - i) * duration); })
        .y(function(d, i) { return y(d); });

    g.append("g")
      .attr("clip-path", "url(#clip)")
        .append("path")
        .datum(data[name])
        .attr("class", "line");
}

function tick() {
    var index;
    var i;
    for (i = 0; i < lineNames.length; ++i) {
        index = lineNames[i];

        // Push a new data point onto the back.
        data[index].push(random());

        // Redraw the line.
        d3.select(this)
          .attr("d", lines[index])
          .attr("transform", null);

        // Pop the old data point off the front.
        data[index].shift();
    }

    now = new Date();
    x.domain([now - (n - 2) * duration, now - duration]);
    axis.transition()
        .duration(duration)
        .ease(d3.easeLinear)
        .call(d3.axisBottom(x));


    // Slide it to the left.
    d3.active(this)
      .attr("transform", "translate(" + x(now - (n - 1) * duration) + ")")
    .transition()
      .on("start", tick);
}
var line = d3.line()
   .curve(d3.curveBasis)
   .x(function(d, i) { return x(now - (n - 1 - i) * duration); })
   .y(function(d, i) { return y(d); });

function tick() {
    var index;
    var i;
   // Push a new data point onto the back.
   this.__data__.push(random());
   // Redraw the line.
   d3.select(this)
      .attr("d", line)
      .attr("transform", null);

   // Pop the old data point off the front.
      this.__data__.shift();

    now = new Date();
    x.domain([now - (n - 2) * duration, now - duration]);
    axis.transition()
        .duration(duration)
        .ease(d3.easeLinear)
        .call(d3.axisBottom(x));

    // Slide it to the left.
    d3.active(this)
      .attr("transform", "translate(" + x(now - (n - 1) * duration) + ")")
    .transition()
      .on("start", tick);
}