0
votes

I was working against a financial library that requires me to provide realtime updates to a line chart in canvas. To optimize the process of updating the chart, I thought of just updated the latest data-point rather than clearing and re-drawing the entire canvas.

When re-rendering only the latest datapoint frequently, I'm noticing that the line is not clear(there's a spot in the image).

Here's how the line looks initially(no redraw)

Inital

And after a few updates of calling "partial_rerender", this is how the line looks: Redraw

Notice the "joining" of the 2 lines is visible with a darker shade.

Is there a way to achieve partial re-drawing of lines only for the latest data point & not drawing the entire line completely?

Reference code

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.lineWidth = 2;
ctx.lineJoin = "miter";
ctx.moveTo(20, 50);
ctx.lineTo(100, 50);
ctx.save();
ctx.lineTo(150, 60);
ctx.stroke();

/*Call this every second to re-draw only the latest data point*/
function partial_rerender(){
ctx.clearRect(100,50, 400,400);
ctx.restore();
ctx.lineTo(150, 60);
ctx.stroke();
}
2
On top of clearRect (which is a good idea) you should also use clip. After that line endings will not "leak". - tevemadar
You are not calling beginPath in partial_rerender... ctx.save saves all the properties of your context, but not the current state of your path declaration. (i.e it's an heavy call for nothing here). For such a case, simply redraw everything ; for really complicated and heavy to draw shapes, store it in an offscreen canvas, and at every frame clear all, draw the offscreen canvas, beginPath(), moveTo(theLastPoint), partial_rerender(). But by all means, remove these save and restore... - Kaiido

2 Answers

1
votes

You need to create a new path each time you render or you end up re- rendering the same content over and over.

ctx.save() and ctx.restore() push and pop from a stack, for every restore you need to have a matching save. ctx.save(), ctx.restore(), ctx.restore()the second restore does nothing as there is no matching save.

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.lineWidth = 2;
ctx.lineJoin = "miter";
ctx.moveTo(20, 50);
ctx.lineTo(100, 50);
ctx.save();
ctx.lineTo(150, 60);
ctx.stroke();

// Your function should look more like this
function partial_rerender(){
   ctx.lineWidth = 2;
   ctx.lineJoin = "miter";
   ctx.save();  // needed to remove clip
   ctx.beginPath(); // removes old path ready to create a new one
   ctx.rect(100,50, 400,400); // create a clip area
   ctx.clip(); // activate the clip area
   ctx.clearRect(100,50, 400,400);
   ctx.beginPath(); // needed to draw the new path 
   ctx.moveTo(100,50)
   ctx.lineTo(150, 60);
   ctx.stroke();
   ctx.restore(); // remove the clip area
}
0
votes

When you draw onto the canvas you do override the necessary pixels. But the rest stays the same. What you are trying to achieve is not possible. You have to clear the canvas (canvas.clear()) and then redraw all elements to remove these artifacts from previous draw calls and to achieve your desired result.