Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing multiple real time lines

I want to draw multiple real time lines using JSON files. I am basically retrieving the JSON file from a website, getting the time data (duration in seconds), converting them into minutes and pushing them into the data array. This code checks the JSON file for every second.

I want to add as many line as possible. For example, I want to add the average of the elements in data array (average duration) and plot it on the same plane. I tried to add another "line" and "path" variable, however I wasn't able to plot it at the same time.

The data array is an empty array with 44 elements in the beginning, and everytime the code checks the JSON file it replaces those zeroes with the retrieved duration data.

Here is my code to draw only one line.

  function graph() {

  var n = 43,
      duration = 1000,
      now = new Date(Date.now() - duration),
      count = 0,
      data = d3.range(n).map(function() { return 0; });

  var margin = {top: 10, right: 20, bottom: 30, left: 60},
      width = 1200 - margin.left-margin.right,
      height = 460 - margin.top - margin.bottom;

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

  var y = d3.scale.linear()
      .range([height, 0]);

  var line = d3.svg.line()
      .interpolate("basis")
      .x(function(d, i) { return x(now - (n - 1 - i) * duration); })
      .y(function(d, i) { return y(d); });

  var line2 = d3.svg.line()
      .interpolate("basis")
      .x(function(d, i) { return x(now - (n - 1 - i) * duration); })
      .y(function(d, i) { return y(d); });

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

  var axis = svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate( "+margin.left+"," + height + ")")
      .call(x.axis = d3.svg.axis().scale(x).orient("bottom"));


  var yaxis = svg.append("g")
      .attr("class", "y axis")
      .attr("transform", "translate(" + margin.left + ",0)")
      .call(y.axis = d3.svg.axis().scale(y).orient("left"));


  d3.select(".y.axis")
      .append("text")
      .text("Travel Time (min)")
      .attr("text-anchor", "middle")
      .attr("transform","rotate( -90, 200, 0)")
      .attr("y",-250);

  var path = svg.append("g")
      .attr("clip-path", "url(#clip)")
      .attr("transform", "translate(" + margin.left + ",0)")
      .append("path")
      .data([data])
      .attr("class", "line");

  tick();

  function tick() {

    d3.json("route.json",function(barzo){
      var tempdata = barzo.route;
      var len = tempdata.realTime;
      var lastdata = parseInt(len)/60; //this is the time variable I use.

    // update the domains
    now = new Date();
    x.domain([now - (n - 2) * duration, now - duration]);
    y.domain([0, d3.max(data)+5]);

   // push the time into the data
    data.push(count);
    count = lastdata;

    // redraw the line
    svg.select(".line")
        .attr("d", line)
        .attr("transform", null);

    // slide the x-axis left
    axis.transition()
        .duration(duration)
        .ease("linear")
        .call(x.axis);

    yaxis.transition()
        .duration(duration/10)
        .ease("linear")
        .call(y.axis);

    // slide the line left
    path.transition()
        .duration(duration)
        .ease("linear")
        .attr("transform", "translate(" + x(now - (n - 1) * duration) + ")")
        .each("end", tick);


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

  });
  }
  };
like image 919
gradLife Avatar asked Dec 25 '13 05:12

gradLife


1 Answers

First, I included another another data array (data2) to push the new data points for the new path:

 var n = 43,
      duration = 1000,
      now = new Date(Date.now() - duration),
      count = 0,
      data = d3.range(n).map(function() { return 0; });
      data2 = d3.range(n).map(function() { return 0; });

Then, I defined another path for the line that uses the points of data2 array.

var path2 = svg.append("g")
    .attr("clip-path", "url(#clip)")
    .attr("transform", "translate(" + margin.left + ",0)")  
    .append("path")
    .data([data2])
    .attr("class", "line2")

In the tick function, I needed to select both of those lines to update them (You can write a function to do the same thing for these steps instead of repeating the same code twice).

  // redraw the line
  svg.select(".line")
      .attr("d", line)
      .attr("transform", null);

  svg.select(".line2")
      .attr("d", line2)
      .attr("transform", null);

The same thing for transition and data shift as well

  // slide the line left
  path.transition()
      .duration(duration)
      .ease("linear")
      .attr("transform", "translate(" + x(now - (n - 1) * duration) + ")");

  path2.transition()
      .duration(duration)
      .ease("linear")
      .attr("transform", "translate(" + x(now - (n - 1) * duration) + ")")
      .each("end", tick);   

// pop the old data point off the front
  data.shift();
  data2.shift();
like image 108
gradLife Avatar answered Oct 21 '22 00:10

gradLife