HTML5 Canvas slows down with each stroke and clear
The <canvas>
element keeps track of a current path (i.e., set of points, lines, and curves). canvas.moveTo
, canvas.lineTo
, and canvas.stroke
all operate on the current path. Every time you call canvas.moveTo
or canvas.lineTo
you are adding to the current path. As the path gets more and more complex, drawing gets slower and slower.
You can clear the path by calling canvas.beginPath()
. Doing this at the start of your draw function should get rid of the slowdown.
Redrawing HTML5 canvas incredibly slow
Here's the code made much better.
http://jsfiddle.net/zHpgV/3/
Here's a breakdown of the things that you should take into consideration that I changed:
- Continuous adding to a path instead of stopping and creating a new path with
beginPath
. This is by far the biggest performance killer here. You're ending up with a path with thousands and thousands of line segements that never gets cleared. - Continuously making the same path over and over when it only needs to be made once, on initialization. That is, the only thing you need to call inside of
render
isstroke
. You do not need to calllineTo/moveTo
ever again, and certainly not continuously. See note 1. - Stroking twice for one path
- Stroking inside a for loop
- Redrawing a background instead of setting CSS background
- Setting the line cap over and over
Note 1: If you plan to have more than one path in your application then you should probably cache paths like this one since they never change. I have a a tutorial on how to do that here.
Of course, if you are doing all of this to just make a background, it should be saved as a png and you should be using a CSS background-image.
Like so: http://jsfiddle.net/zHpgV/4/
Then suddenly your render routine is rather small:
function render() {
c.clearRect(0, 0, scale, scale);
c.fillText('{0}, {1}'.format(mouseX, mouseY), 0.5, 1.5);
}
HTML5 Canvas performance very poor using rect()
LIVE DEMO
Try add the beginPath
method, like the following code:
canvasContext.beginPath();
canvasContext.rect(2, 1, 210, 30);
canvasContext.rect(2, 1, 80, 30);
canvasContext.rect(80, 1, 70, 30);
canvasContext.strokeStyle = "#FCEB77";
canvasContext.stroke();
canvasContext.closePath();
When drawing using a path, you are using a virtual "pen" or "pointer". Without the path, will cause direct changes on canvas state machine which make things slow.
closePath
is not really necessary in this case, but is there to illustrate the usage.
Try demo with and without the (begin/close)Path and compare the performance. I provided a rough fps counter but it is sufficient to see the decrease in performance.
You might need to check this on other browsers, including mobiles, so I set this JSPerf test.
HTML5 Canvas and JS Framerate slowly drops to 0
The reason is, you are not clearing your paths. Use
context.beginPath();
at the begin of draw()
.
This question was asked before here
canvas animation slows down
Try this change (beginPath())
if (patterns.length > 0) {
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
context.beginPath();
draw();
Link http://jsbin.com/aleqef/4/edit#preview
Html canvas drawing slows with too many canvas elements
To answer your question: Yes, It takes longer to redraw as you increase the total canvas size. You are dramatically increasing the total canvas size by adding full sized canvases even if those canvases are scaled down to be "slide size". BTW, .stroke
is not your problem -- it renders very quickly.
Each of your slide canvases has the same resolution as your main canvas. The DOM must remember the original size so total canvas size increases dramatically with each new slide.
A fix is to make the each slide canvases smaller (== the display size), rather than keeping the same resolution as the main canvas. If the user wants to redraw a slide then dynamically create a full-sized canvas from points
for that slide. Less total canvas size == better performance.
Canvas has a scaling command that lets you easily take your full-sized canvas content and scale it to smaller display size:
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
c.width=smallSlideWidth;
c.height=smallSlideHeight;
var scale=Math.min((slideWidth/mainCanvasWidth),(slideHeight/mainCanvasHeight));
cctx.scale(scale,scale);
... now draw your slide using the same coordinates as your main canvas
We don't have more of your code, but if you're redrawing every slide canvas all the time -- don't do that!
How to clear the canvas for redrawing
Given that canvas
is a canvas element or an OffscreenCanvas
object, use clearRect
:
const context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
setInterval is slowing down over time
First of all the screen only refreshes at a rate of 16 milliseconds (assuming 60 frames per second). So calling the two function at 10 milliseconds is a bit overkill. But in the modern browser, we now have a native support to do anything when the screen refreshes. Its called request animation frame: requestAnimationFrame(animationrDrawCallback).
You can read more about it here: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame. Now back to your code, it can be refactored like this:
const r = [];
const ctx;
function init() {
ctx = document.getElementById("canvas").getContext("2d");
for(let i = 0; i < 20; i++) {
const x = Math.floor(Math.random() * (ctx.canvas.width - 20)) + 10;
const y = Math.floor(Math.random() * (ctx.canvas.height - 20)) + 10;
r.push(new Rect(x,y, 10, 10, ctx));
}
// start our animation
window.requestAnimationFrame(render);
}
function render() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
r.forEach((item) => {
item.trick();
item.draw();
})
ctx.beginPath();
ctx.lineWidth = 5;
ctx.rect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.stroke();
// this will be called at next screen refresh
window.requestAnimationFrame(render);
}
The BIGGEST BONUS of using requestAnimationFrame is that it will stop executing when the tab is no longer in focus. Big boost for smartphones. Hope this helps.
Related Topics
Div with Horizontal Scrolling Only
Are Nested HTML Comments Possible
What Is The Correct Readonly Attribute Syntax for Input Text Elements
Force <A Download /> to Download Image Instead of Opening Url Link to Image
Inline Form Nested Within Horizontal Form in Bootstrap 3
Fixed Header, Footer, and Sidebars with Scrolling Content Area in Center
Is It Bad Design to Use Table Tags When Displaying Forms in HTML
Table Overflowing Outside of Div
Can Outlook 2010 Use a Web Font in an HTML Email
How to Display a Range Input Slider Vertically
How to Always Show Up/Down Arrows for Input "Number"
How to Overlap Two Images Using CSS Style
Select First Occurring Element After Another Element
Change The Color of Glyphicons to Blue in Some- But Not at All Places Using Bootstrap 2
Writing HTML Form Data to a Txt File Without The Use of a Webserver