javascript – How to put the same animation on two canvas at the same time?

Question:

I have an animation in "html5 Canvas" (using Flot Real Time) and now I need it to be cloned in real time to a new canvas, that is, drawing the same thing on 2 canvas at the same time.

So I simply tried to copy the image, but of course it was slow, causing it to flicker:

var c   = document.getElementById('placeholder');
var ctx = c.getContext('2d');
var imgData = ctx.getImageData(0, 0, 300, 500);

var imageNow = document.querySelector('#placeholder2');
var ctxImageNow = imageNow.getContext('2d');
ctxImageNow.putImageData(imgData, 0, 0); 

In my research I realized that using buffers, this is easy,
but I didn't understand the mechanics and I don't know how to apply it to my example.

canvas { border: 2px solid #000; position:absolute; top:0;left:0; 
visibility: hidden; }

Buffers[1-DrawingBuffer].style.visibility='hidden';
Buffers[DrawingBuffer].style.visibility='visible';

DrawingBuffer=1-DrawingBuffer;

var context = Buffers[DrawingBuffer].getContext('2d');

My example is very similar to the one provided by flot realtime I put it here:

$(function() {
  // info for graph2
  instant = 5;
  high = -45;
  factor = 0;
  frequency = 15;
  updateInterval = 70;
	var data1 = [], data2 = [], totalPoints = 300;

  function Easing( i ) {
      i *= 2;
      if (i<1) return 1/(2-i)-.5;
      return 1.5-1/i;
  }

	function getRandomData() {
    // original j-flot randon data, nao precisamos neste exemplo..
  }
  function getRandomData2() {
    // nosso grafico, DESTE nos  precisamos....
  
    // se adrenalina ON  sobre o grafico
    if(isRunning==true){
      if(factor<1) {
        factor=factor+.005;    
        frequency=frequency+.25;
      }
    } 
    // se adrenalina OFF  desce o grafico
	else {
      if(factor>0) {
        factor=factor-.005;    
        frequency=frequency-.25;
      }
    }
      
    if (data2.length > 0)
      data2 = data2.slice(1);
    while (data2.length < totalPoints) {
        instant = instant - frequency;
        calc = high - Easing(factor) * 35;
        if (instant < calc ) {
          instant = (calc * -1);
        }
        instantShow = instant;
        if (instantShow < 20) {
          instantShow = 20;
        }
        data2.push(instantShow);
    }
    var res = [];
    for (var i = 0; i < data2.length; ++i) {
      res.push([i, data2[i]])
    }
    //console.log(data2);
    return res;
  }
	//
  // Set up the control widget
  $("#updateInterval").val(updateInterval).change(function() {
    var v = $(this).val();
    if (v && !isNaN(+v)) {
      updateInterval = +v;
      if (updateInterval < 1) {
        updateInterval = 1;
      } else if (updateInterval > 2000) {
        updateInterval = 2000;
      }
      $(this).val("" + updateInterval);
    }
  });
  var plot = $.plot("#placeholder", [{
    data: getRandomData()
  }, {
    data: getRandomData2()
  }], {
    series: {
      shadowSize: 0
    },
    yaxis: {
      min: 0,
      max: 100
    },
    xaxis: {
      show: false
    }
  });
  function update() {
    plot.setData([{
      data: getRandomData()
    }, {
      data: getRandomData2()
    }]);
    plot.draw();
    setTimeout(update, updateInterval);
  }
  update();
});


//
// buttons
//

var isRunning = false;
document.getElementById('button').onclick = function()
{
    if (isRunning){
    	document.getElementById('button').innerHTML = "<font color=red>Sem Adrenalina</font>";
    }
    else{
    	document.getElementById('button').innerHTML = "<font color=green>Com Adrenalina</font>";
    }
    isRunning = !isRunning;
};
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.js"></script>

<div id="placeholder" style="height:300px; width:500px; border:solid 1px red; ">
</div>

<button id="button" onmousedown="buttonAdrenaline">
  <font color=red>
    Sem Adrenalina
   </font>
</button>

<hr>

<div id="placeholder2" style="height:300px; width:500px; border:solid 1px blue;">
</div>

Could someone teach me how to solve this? I need to put the same animation on two different canvas…

Answer:

Instead of doing all the copying work, for every animation update you'll have to copy again, this makes it as much work for you as the browser does, you can simply add the parameters of the $.plot to two variables:

var dataAnimation = [{
  data: getRandomData()
}, {
  data: getRandomData2()
}]

var optsAnimation = {
  series: {
    shadowSize: 0
  },
  yaxis: {
    min: 0,
    max: 100
  },
  xaxis: {
    show: false
  }
};

And create add the $.plot for each element:

var plot1 = $.plot("#placeholder", dataAnimation, optsAnimation);
var plot2 = $.plot("#placeholder2", dataAnimation, optsAnimation);

And in the update just add the setData for both objects:

function update() {
  var data = [{
    "data": getRandomData()
  }, {
    "data": getRandomData2()
  }];

  plot1.setData(data);
  plot2.setData(data);
  plot1.draw();
  plot2.draw();
  setTimeout(update, updateInterval);
}

full example

$(function() {
  // info for graph2
  instant = 5;
  high = -45;
  factor = 0;
  frequency = 15;
  updateInterval = 70;
    var data1 = [], data2 = [], totalPoints = 300;

  function Easing( i ) {
      i *= 2;
      if (i<1) return 1/(2-i)-.5;
      return 1.5-1/i;
  }

    function getRandomData() {
    // original j-flot randon data, nao precisamos neste exemplo..
  }
  function getRandomData2() {
    // nosso grafico, DESTE nos  precisamos....

    // se adrenalina ON  sobre o grafico
    if(isRunning==true){
      if(factor<1) {
        factor=factor+.005;
        frequency=frequency+.25;
      }
    }
    // se adrenalina OFF  desce o grafico
    else {
      if(factor>0) {
        factor=factor-.005;
        frequency=frequency-.25;
      }
    }

    if (data2.length > 0)
      data2 = data2.slice(1);
    while (data2.length < totalPoints) {
        instant = instant - frequency;
        calc = high - Easing(factor) * 35;
        if (instant < calc ) {
          instant = (calc * -1);
        }
        instantShow = instant;
        if (instantShow < 20) {
          instantShow = 20;
        }
        data2.push(instantShow);
    }
    var res = [];
    for (var i = 0; i < data2.length; ++i) {
      res.push([i, data2[i]])
    }
    //console.log(data2);
    return res;
  }
    //
  // Set up the control widget
  $("#updateInterval").val(updateInterval).change(function() {
    var v = $(this).val();
    if (v && !isNaN(+v)) {
      updateInterval = +v;
      if (updateInterval < 1) {
        updateInterval = 1;
      } else if (updateInterval > 2000) {
        updateInterval = 2000;
      }
      $(this).val("" + updateInterval);
    }
  });

  var dataAnimation = [{
    data: getRandomData()
  }, {
    data: getRandomData2()
  }];

  var optsAnimation = {
    series: {
      shadowSize: 0
    },
    yaxis: {
      min: 0,
      max: 100
    },
    xaxis: {
      show: false
    }
  };

  var plot1 = $.plot("#placeholder", dataAnimation, optsAnimation);
  var plot2 = $.plot("#placeholder2", dataAnimation, optsAnimation);

  function update() {
    var data = [{
      "data": getRandomData()
    }, {
      "data": getRandomData2()
    }];

    plot1.setData(data);
    plot2.setData(data);
    plot1.draw();
    plot2.draw();
    setTimeout(update, updateInterval);
  }
  update();
});

var isRunning = false;
document.getElementById('button').onclick = function()
{
    if (isRunning){
        document.getElementById('button').innerHTML = "<font color=red>Sem Adrenalina</font>";
    }
    else{
        document.getElementById('button').innerHTML = "<font color=green>Com Adrenalina</font>";
    }
    isRunning = !isRunning;
};
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.js"></script>

<div id="placeholder" style="height:300px; width:500px; border:solid 1px red; "></div>

<button id="button" onmousedown="buttonAdrenaline">
  <font color=red>
    Sem Adrenalina
   </font>
</button>

<hr>

<div id="placeholder2" style="height:300px; width:500px; border:solid 1px blue;"></div>
Scroll to Top