使用d3.js绘制来自动态生成数据的波上的数据点

时间:2017-09-03 22:16:06

标签: javascript d3.js svg

我根据d3.js中随机生成的数据绘制了动态波。我使用“dot”(svg.selectAll(“dot”))元素来表示波浪上的数据点(x和y轴)。基于setinterval方法,我的数据每200ms更新一次,我将数据从右向左转换。但是我添加到波浪中的数据点(点)不随波浪一起移动,它们是固定的(不移动),只有波浪移动。

这是代码: https://jsfiddle.net/rajatmehta/tm5166e1/4/

function updateData() {

    var newData = GenData(N,lastUpdateTime);
    lastUpdateTime = newData[newData.length-1].timestamp;

    var newData2 = GenData2(N,lastUpdateTimeNew);
    lastUpdateTimeNew = newData2[newData2.length-1].timestamp;

    for (var i=0; i<newData.length; i++){
    console.log(globalData.length);
        if(globalData.length>99){
        globalData.shift();
        }
        globalData.push(newData[i]);
    }
    for (var i=0; i<newData2.length; i++){
    console.log(globalDataNew.length);
        if(globalDataNew.length>99){
        globalDataNew.shift();
        }
        globalDataNew.push(newData2[i]);
    }

        //code for transition start
        x1 = newData[0].timestamp;
        x2 = newData[newData.length - 1].timestamp;
        dx = dx + (x(x1) - x(x2)); // dx needs to be cummulative

        x1New = newData2[0].timestamp;
        x2New = newData2[newData2.length - 1].timestamp;
        dxNew = dxNew + (x(x1New) - x(x2New)); // dx needs to be cummulative


        d3.select("path#path1")
            .datum(globalData)
            .attr("class", "line")
            .attr("d", valueline(globalData))
            .transition()
            .ease("linear")
            .attr("transform", "translate(" + String(dx) + ")");




        d3.select("path#path2")
            .datum(globalDataNew)
            .attr("class", "line")
            .attr("d", valueline2(globalDataNew))
            .transition()
            .ease("linear")
            .attr("transform", "translate(" + String(dxNew) + ")");



    svg.select(".x.axis").call(xAxis);
}

我是d3.js的新手,所以对此并不太了解。

1 个答案:

答案 0 :(得分:1)

两个问题:

  1. 您没有正确添加圈子:无法<circle>元素附加到<path>元素。您必须使用“输入”选项,将它们附加到SVG(或组元素):

    chartBody.selectAll(null)
        .data(globalData)
        .enter()
        .append("circle")
        .attr("class", "dot1")
        .attr("r", 3)
        .attr("cx", function(d) {
            console.log(d)
            return x(d.timestamp);
        })
        .attr("cy", function(d) {
            return y(d.value);
        });
    
  2. 在更新功能中,按

    选择这些圈子
    d3.selectAll(".dot1")
        .data(globalData)
        .transition()
        .ease("linear")
        .attr("transform", "translate(" + String(dx) + ")");
    
  3. 以下是包含这些更改的代码:

    var lastUpdateTime = +new Date();
    var lastUpdateTimeNew = +new Date();
    
    var GenData = function(N, lastTime) {
      var output = [];
      for (var i = 0; i < N; i++) {
        output.push({
          value: Math.random() * 10,
          timestamp: lastTime
        });
        lastTime = lastTime + 1000;
      }
    
      return output;
    
    }
    var GenData2 = function(N, lastTime) {
      var output = [];
      for (var i = 0; i < N; i++) {
        output.push({
          value: Math.random() * 20,
          timestamp: lastTime
        });
        lastTime = lastTime + 1000;
      }
    
      return output;
    
    }
    var globalData;
    var globalDataNew;
    
    // plot the original data by retrieving everything from time 0
    data = GenData(50, lastUpdateTime);
    dataNew = GenData2(50, lastUpdateTimeNew);
    
    lastUpdateTime = data[data.length - 1].timestamp;
    lastUpdateTimeNew = dataNew[dataNew.length - 1].timestamp;
    
    globalData = data;
    globalDataNew = dataNew;
    
    // Define the div for the tooltip
    var div = d3.select("body").append("div")
      .attr("class", "tooltip")
      .style("opacity", 0);
    
    var margin = {
        top: 30,
        right: 20,
        bottom: 30,
        left: 50
      },
      width = 800 - margin.left - margin.right,
      height = 350 - margin.top - margin.bottom;
    
    var x = d3.time.scale()
      .range([0, width]);
    
    var y = d3.scale.linear()
      .range([height, 0]);
    
    
    x.domain(d3.extent(globalDataNew, function(d) {
      return d.timestamp;
    }));
    y.domain(d3.extent(globalDataNew, function(d) {
      return d.value;
    }));
    
    
    var xAxis = d3.svg.axis().scale(x)
      .orient("bottom")
      .ticks(d3.time.seconds, 20)
      .tickFormat(d3.time.format('%X'))
      .tickSize(5)
      .tickPadding(8);
    
    var xAxisTop = d3.svg.axis().scale(x)
      .orient("bottom").tickFormat("").tickSize(0);
    
    var yAxis = d3.svg.axis().scale(y)
      .orient("left").ticks(5);
    
    var yAxisRight = d3.svg.axis().scale(y)
      .orient("right").tickFormat("").tickSize(0);
    
    var valueline = d3.svg.line()
      .x(function(d) {
        return x(d.timestamp);
      })
      .y(function(d) {
        return y(d.value);
      });
    
    var valueline2 = d3.svg.line()
      .x(function(d) {
        return x(d.timestamp);
      })
      .y(function(d) {
        return y(d.value);
      });
    
    var svg = d3.select("body")
      .append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    
    svg.append("rect")
      .attr("width", width)
      .attr("height", height)
      .attr("class", "plot");
    
    var clip = svg.append("clipPath")
      .attr("id", "clip")
      .append("rect")
      .attr("x", 0)
      .attr("y", 0)
      .attr("width", width)
      .attr("height", height);
    
    var chartBody = svg.append("g")
      .attr("clip-path", "url(#clip)");
    
    
    
    /* .on("mouseover", function(d) {		
                div.transition()		
                    .duration(200)		
                    .style("opacity", .9);		
                div	.html(formatTime(d.timestamp) + "<br/>"  + d.close)	
                    .style("left", (d3.event.pageX) + "px")		
                    .style("top", (d3.event.pageY - 28) + "px");	
                })					
            .on("mouseout", function(d) {		
                div.transition()		
                    .duration(500)		
                    .style("opacity", 0);	
            })*/
    
    
    chartBody.append("path") // Add the valueline path
      .datum(globalData)
      .attr("id", "path1")
      .attr("class", "line")
      .attr("d", valueline);
    
    chartBody.selectAll(null)
      .data(globalData)
      .enter()
      .append("circle")
      .attr("class", "dot1")
      .attr("r", 3)
      .attr("cx", function(d) {
        return x(d.timestamp);
      })
      .attr("cy", function(d) {
        return y(d.value);
      });
    
    chartBody.selectAll(null)
      .data(globalDataNew)
      .enter()
      .append("circle")
      .attr("class", "dot2")
      .attr("r", 3)
      .attr("cx", function(d) {
        return x(d.timestamp);
      })
      .attr("cy", function(d) {
        return y(d.value);
      });
    
    
    
    
    
    chartBody.append("path") // Add the valueline path
      .datum(globalDataNew)
      .attr("id", "path2")
      .attr("class", "line")
      .attr("d", valueline2);
    
    
    svg.append("g") // Add the X Axis
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
    
    svg.append("g") // Add the Y Axis
      .attr("class", "y axis")
      .call(yAxis);
    
    svg.append("g")
      .attr("class", "y axis")
      .attr("transform", "translate(" + width + ",0)")
      .call(yAxisRight);
    
    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + String(0) + ")")
      .call(xAxisTop);
    
    svg.append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 0 - margin.left)
      .attr("x", (0 - (height / 2)))
      .attr("dy", "1em")
      .style("text-anchor", "middle")
      .style("font-weight", "bold")
      .text("Return (%)");
    
    
    var inter = setInterval(function() {
      updateData();
    }, 1000);
    
    
    
    
    
    //////////////////////////////////////////////////////////////
    
    var N = 3;
    var dx = 0;
    var dxNew = 0;
    
    function updateData() {
    
      var newData = GenData(N, lastUpdateTime);
      lastUpdateTime = newData[newData.length - 1].timestamp;
    
      var newData2 = GenData2(N, lastUpdateTimeNew);
      lastUpdateTimeNew = newData2[newData2.length - 1].timestamp;
    
      for (var i = 0; i < newData.length; i++) {
        if (globalData.length > 99) {
          globalData.shift();
        }
        globalData.push(newData[i]);
      }
      for (var i = 0; i < newData2.length; i++) {
        if (globalDataNew.length > 99) {
          globalDataNew.shift();
        }
        globalDataNew.push(newData2[i]);
      }
    
      //code for transition start
      x1 = newData[0].timestamp;
      x2 = newData[newData.length - 1].timestamp;
      dx = dx + (x(x1) - x(x2)); // dx needs to be cummulative
    
      x1New = newData2[0].timestamp;
      x2New = newData2[newData2.length - 1].timestamp;
      dxNew = dxNew + (x(x1New) - x(x2New)); // dx needs to be cummulative
    
    
      d3.select("path#path1")
        .datum(globalData)
        .attr("class", "line")
        .attr("d", valueline(globalData))
        .transition()
        .ease("linear")
        .attr("transform", "translate(" + String(dx) + ")");
    
      d3.select("path#path2")
        .datum(globalDataNew)
        .attr("class", "line")
        .attr("d", valueline2(globalDataNew))
        .transition()
        .ease("linear")
        .attr("transform", "translate(" + String(dxNew) + ")");
    
      d3.selectAll(".dot1")
        .data(globalData)
        .transition()
        .ease("linear")
        .attr("transform", "translate(" + String(dx) + ")");
    
      d3.selectAll(".dot2")
        .data(globalDataNew)
        .transition()
        .ease("linear")
        .attr("transform", "translate(" + String(dx) + ")");
    
      svg.select(".x.axis").call(xAxis);
    }
    body {
       font: 12px Arial;
     }
     
     path {
       stroke: black;
       stroke-width: 1;
       fill: none;
     }
     
     .axis path,
     .axis line {
       fill: none;
       stroke: black;
       stroke-width: 2;
       shape-rendering: crispEdges;
     }
     
     text {
       fill: black;
     }
     
     rect {
       fill: #add8e6;
     }
    <script src="https://d3js.org/d3.v3.min.js"></script>

    PS:当线条向左移动时,你必须添加新的圆圈。但是,这是另一个问题。