title: Continuously updating lines in a d3 chart based on SignalR input
body: <p>I have a d3 chart displaying three lines, where each line has its own y-axis. It also has a x-axis for displaying time. All axes has zoom / pan on them. 
  <img src="https://i.stack.imgur.com/5X4NE.png" alt="enter image description here">
  This works fine for displaying historic data, but I also need a button to start displaying real time data. </p>
  
  <p>I have a button triggering SignalR, which again gives me new data that I can push onto my data arrays. </p>
  
  <p>My question is how I can update these three lines and move them in a horizontal direction every time the arrays are updated with the new data values.
  I've tried following <a href="http://bost.ocks.org/mike/path/" rel="nofollow noreferrer">this</a> and <a href="http://bl.ocks.org/benjchristensen/1148374" rel="nofollow noreferrer">this</a> guide, but all I really end up doing is redrawing the entire line on top of the old one. (I'm only trying to update one of them at the moment)</p>
  
  <p>Before displaying my chart code, I should mention that my array is updated every second with new values (This happens in a separate js file, included in the same view):</p>
  
  <pre><code>speed.push(entry.Speed);
  redraw();
  
  &lt;script&gt;
      /* d3 vars */
      var graph;
      var m = [];
      var w;
      var h;
  
      /* d3 scales */
      var x;
      var y1;
      var y2;
      var y3;
  
      /* d3 axes */
      var xAxis;
      var yAxisLeft;
      var yAxisLeftLeft;
      var yAxisRight;
  
      /* d3 lines */
      var line1;
      var line2;
      var line3;
  
      /* d3 zoom */
      var zoom;
      var zoomLeftLeft;
      var zoomRight;
  
      /* Data */
      var speed = [];
      var depth = [];
      var weight = [];
      var timestamp = [];
  
      var url = '@Url.Action("DataBlob", "Trend", new {id = Model.Unit.UnitId, runId = Request.Params["runId"]})';
  
      var data = $.getJSON(url, null, function(data) {
          var list = JSON.parse(data);
          var format = d3.time.format("%Y-%m-%dT%H:%M:%S").parse;
          if ($("#IsLiveEnabled").val() != "true") {
              list.forEach(function(d) {
                  speed.push(d.Speed);
                  depth.push(d.Depth);
                  weight.push(d.Weight);
                  var date = format(d.Time);
                  d.Time = date;
                  timestamp.push(d.Time);
              });
          }
  
          $('#processing').hide();
  
          m = [20, 85, 30, 140]; // margins: top, right, bottom, left
          w = ($("#trendcontainer").width() - 35) - m[1] - m[3]; // width
          h = 600 - m[0] - m[2]; // height
  
          x = d3.time.scale().domain(d3.extent(timestamp, function(d) {
              return d;
          })).range([0, w]);
  
          y1 = d3.scale.linear().domain([0, d3.max(speed)]).range([h, 0]);
          y2 = d3.scale.linear().domain([0, d3.max(depth)]).range([h, 0]);
          y3 = d3.scale.linear().domain([0, d3.max(weight)]).range([h, 0]);
  
          line1 = d3.svg.line()
              .interpolate("basis")
              .x(function(d, i) {
                  return x(timestamp[i]);
              })
              .y(function(d) {
                  return y1(d);
              });
  
          line2 = d3.svg.line()
              .interpolate("basis")
              .x(function(d, i) {
                  return x(timestamp[i]);
              })
              .y(function(d) {
                  return y2(d);
              });
  
          line3 = d3.svg.line()
              .interpolate("basis")
              .x(function(d, i) {
                  return x(timestamp[i]);
              })
              .y(function(d) {
                  return y3(d);
              });
  
          zoom = d3.behavior.zoom()
              .x(x)
              .y(y1)
              .scaleExtent([1, 35])
              .on("zoom", zoomed);
  
          zoomLeftLeft = d3.behavior.zoom()
              .x(x)
              .y(y3)
              .scaleExtent([1, 35])
              .on("zoom", zoomed);
  
          zoomRight = d3.behavior.zoom()
              .x(x)
              .y(y2)
              .scaleExtent([1, 35])
              .on("zoom", zoomed);
  
          // Add an SVG element with the desired dimensions and margin.
          graph = d3.select(".panel-body").append("svg:svg")
              .attr("width", w + m[1] + m[3])
              .attr("height", h + m[0] + m[2])
              .call(zoom)
              .append("svg:g")
              .attr("transform", "translate(" + m[3] + "," + m[0] + ")");
  
          graph.append("defs").append("clipPath")
              .attr("id", "clip")
              .append("rect")
              .attr("width", w)
              .attr("height", h);
  
          // create xAxis
          xAxis = d3.svg.axis().scale(x).tickSize(-h).tickSubdivide(false);
          // Add the x-axis.
          graph.append("svg:g")
              .attr("class", "x axis")
              .attr("transform", "translate(0," + h + ")")
              .call(xAxis);
  
          // create left yAxis
          yAxisLeft = d3.svg.axis().scale(y1).ticks(10).orient("left");
          // Add the y-axis to the left
          graph.append("svg:g")
              .attr("class", "y axis axisLeft")
              .attr("transform", "translate(-25,0)")
              .call(yAxisLeft)
              .append("text")
              .attr("transform", "rotate(-90)")
              .attr("y", 5)
              .attr("dy", ".71em")
              .style("text-anchor", "end")
              .text("Speed (m/min)");
  
          // create leftleft yAxis
          yAxisLeftLeft = d3.svg.axis().scale(y3).ticks(10).orient("left");
          // Add the y-axis to the left
          graph.append("svg:g")
              .attr("class", "y axis axisLeftLeft")
              .attr("transform", "translate(-85,0)")
              .call(yAxisLeftLeft)
              .append("text")
              .attr("transform", "rotate(-90)")
              .attr("y", 5)
              .attr("dy", ".71em")
              .style("text-anchor", "end")
              .text("Weight (kg)");
  
          // create right yAxis
          yAxisRight = d3.svg.axis().scale(y2).ticks(10).orient("right");
          // Add the y-axis to the right
          graph.append("svg:g")
              .attr("class", "y axis axisRight")
              .attr("transform", "translate(" + (w + 25) + ",0)")
              .call(yAxisRight)
              .append("text")
              .attr("transform", "rotate(-90)")
              .attr("y", -15)
              .attr("dy", ".71em")
              .style("text-anchor", "end")
              .text("Depth (m)");
  
          graph.append("svg:path").attr("d", line1(speed)).attr("class", "y1").attr("clip-path", "url(#clip)");
          graph.append("svg:path").attr("d", line2(depth)).attr("class", "y2").attr("clip-path", "url(#clip)");
          graph.append("svg:path").attr("d", line3(weight)).attr("class", "y3").attr("clip-path", "url(#clip)");
      });
  
      function redraw() {
          graph.append("svg:path")
              .attr("d", line1(speed))
              .attr("class", "y1")
              .attr("clip-path", "url(#clip)");
      }
  
      function zoomed() {
          zoomRight.scale(zoom.scale()).translate(zoom.translate());
          zoomLeftLeft.scale(zoom.scale()).translate(zoom.translate());
  
          graph.select(".x.axis").call(xAxis);
          graph.select(".y.axisLeft").call(yAxisLeft);
          graph.select(".y.axisLeftLeft").call(yAxisLeftLeft);
          graph.select(".y.axisRight").call(yAxisRight);
          graph.select(".x.grid")
              .call(make_x_axis()
                  .tickFormat(""));
          graph.select(".y.axis")
              .call(make_y_axis()
                  .tickSize(5, 0, 0));
          graph.selectAll(".y1")
              .attr("d", line1(speed));
          graph.selectAll(".y2")
              .attr("d", line2(depth));
          graph.selectAll(".y3")
              .attr("d", line3(weight));
      };
  
      var make_x_axis = function() {
          return d3.svg.axis()
              .scale(x)
              .orient("bottom")
              .ticks(10);
      };
  
      var make_y_axis = function() {
          return d3.svg.axis()
              .scale(y1)
              .orient("left")
              .ticks(10);
      };
  
  &lt;/script&gt;
  </code></pre>
  
  <p>I do realise that it's not coming out right, but I can't seem to figure out how to append the new values to the end of the drawn line and move it.</p>