I use <canvas> to draw all notes and glyphs in my music education web apps:
http://www.musictheory.net/exercises/keysig/bc98yy
A Firefox 15.0.1 user has reported that sometimes the exercise goes on to the next question, but the canvas still shows the previous question. I have seen this occur in testing one time (out of ~500 questions).
When it occurs, the canvas has been cleared via both canvas.width = canvas.width and a call to .clearRect on the context and glyphs have been drawn in JavaScript via .beginPath, .quadraticCurveTo, .closePath, etc. However, it seems like the canvas's backing buffer never gets flushed/drawn into the window.
I have seen bug reports in the past regarding similar issues:
https://bugzilla.mozilla.org/show_bug.cgi?id=787623
https://bugzilla.mozilla.org/show_bug.cgi?id=794337
http://code.google.com/p/chromium/issues/detail?id=55339
I can force a redraw by doing a DOM hack such as inserting a text node as a child of the canvas, and then removing it on the next run loop cycle, or modifying the background-color or padding of the canvas. This seems heavy-handed, however, and I keep having the nagging feeling that I'm missing something obvious.
My drawing code is simple enough:
canvas.width = width;
ctx.clearRect(0, 0, width, height);
ctx.save();
// Lots of drawing code here
ctx.restore()
ctx.clearRect(0, 0, 1, 1); // Helped force a repaint on some older WebKit browsers?
I have ensured that the number of .save and .restore calls are balanced.
1) I am calling this code directly in response to an onclick event handler. Should I instead be using requestAnimationFrame or setTimeout to perform the drawing on a future run loop cycle?
2) I'm not missing something obvious, like a canvas.pleaseRepaintNow() API, right?
3) Have other people encountered similar issues and resorted to DOM modification to force redraws?
Add context.stroke(); to the last line of your onLoad function, it fixes a bug in Firefox. Otherwise changes to the canvas don't render until the window is redrawn.
It worked in my case at least.
window.onload = function() {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
//Code here...
context.stroke();
}
I tried to get the bug to happen but after madly clicking in Firefox for awhile, I never saw it. This is how I clear the canvas which seems to work, but take it with a grain of salt since I can't get the bug to occur I also can't check to see if this fixes anything...
// Store the current transformation matrix
ctx.save();
// Use the identity matrix while clearing the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Restore the transform
ctx.restore();
Related
I have a background that scrolls up, down, left and right based on position, and was wondering if there is any significant performance difference into using drawImage() every time the position changes vs just drawing the entire background once and moving the canvas around using canvas.style
Using canvas.drawImage()
//cut piece and draw image to fill canvas every time position changes
canvas.drawImage(backgroundImg, 0 + positionX, 0 + positionY, c.width, c.height, 0, 0, c.width, c.height);
VS
Using canvas.style
canvas.width = widthofbackgroundImg;
canvas.height = heightofbackgroundImg;
//draw entire background only once
canvas.drawImage(backgroundImg, 0, 0, widthofbackgroundImg, heightofbackgroundImg);
..then
//move the entire canvas on every position change
canvas.style.left = positionX;
canvas.style.up = positionY;
Those are two different approaches which are depending on the browser processing (different browsers might set different priorities in rendering).
For sure, it does not make sense to move the canvas image by drawImage, if nothing else changes and there is just an initial draw.
Instead of going with canvas.style.left and canvas.style.right I would suggest you to use transform = translate3d(x, y, 0) and test the performance improvement with your dev tools. This will be rendered via the GPU and may increase speed. It will prevent reflow which is time consuming in general.
Also the reading from and writing to the DOM in alternation might slow down performance. It will help to first make all reading (get positions, scroll position or the like), save it in variables and then write everything.
I am trying to create a 'hangman' display for my hangman game with the HTML canvas element. I got the hangman to display one step at a time but I can't seem to clear the canvas (was expecting it to be the easier step...). When I add the clearRect call it causes my whole page to fault out. Can't start the game etc - even when I call it only at the end of a game...
Any advice would be appreciated - new to the web world so assuming I'm doing something silly :)
See the following code pen for the source files and a display of the issue:
https://codepen.io/enewmanMN/pen/LYPWpQq
Tried moving the clearRect call around to avoid calling it right away to see if I could even get the game started with it in the code path but not having any luck.
https://codepen.io/enewmanMN/pen/LYPWpQq
function clearCanvas () {
myStickman = document.getElementById("stickman");
context = myStickman.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height); //CAUSING FAULTS
context.beginPath();
context.strokeStyle = "#fff";
context.lineWidth = 2;
}
Was expecting it to clear the canvas element 'stickman' but instead loose functionality to the page.
When I ran your code with the clearRect uncommented, I got an error saying canvas is not defined. You gave the canvas the name myStickman. This fixed it
context.clearRect(0, 0, myStickman.width, myStickman.height);
I'm new to using canvas and am having a weird issue. My canvas lines are successfully being drawn using:
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
where canvas is the id of a canvas. I then draw using the methods:
context.strokeStyle = "red";
context.beingPath();
context.moveTo(x, y);
context.lineTo(x, y);
context.stroke();
with lineTo being called in a loop updating its position. I use these methods in a function and can draw multiple lines. The issue is (is it an issue?) when I use google's inspect elements I can't find these lines under the canvas that was created. I am used to seeing a path element of some sort.
I can see the script that created these lines, however.
EDIT: just checked another website using canvas and this seems to be normal behavior. Would like confirmation though.
Thanks
Yes It's normal behaviour.
In 2012 the chrome have some experimental plugin with help inspect canvas. But I not sure if it still avaiable (I found information here http://www.html5rocks.com/en/tutorials/canvas/inspection/)
I'm trying to accomplish an effect similar to what you might see on the cartoon Chowder (example link) , where shapes serve as masking layers for a texture underneath that stays static. I've begun playing around with this idea by creating a render loop that clears the canvas, saves it's state, then draws a rectangular clipping region, followed by drawing the background texture that occupies the entire width and height of the canvas.
Here's the draw function:
function draw()
{
context.clearRect(0,0, 640, 480);
context.save();
x += velocityX;
y += velocityY;
context.rect(x, y, 40, 40);
context.clip();
context.drawImage(image, 0,0, 640, 480);
context.restore();
}
Basically it just runs at 60 frames per second, updating the position of the rectangle and clipping a background image inside the clipping region. (I know the code isn't structured perfectly, but I was just experimenting to see if this effect was even possible on the canvas).
http://jsfiddle.net/JERje/86/
The problem I seem to be having is that the clipping area from the previous iteration of the loop hangs around creating the weird effect that you see in the fiddle above. I've tried reordering everything in the draw() step of the loop, but the only thing that seems to work is the canvas.width = canvas.width trick for clearing the screen. I'd like to avoid this method of clearing the screen, since it doesn't seem to work in IE, and it also destroys the canvas state. clearRect() should work to clear the screen. What am I doing wrong?
You're using the same HTML5 Canvas paperback I am aren't you.
If you set up an adhoc canvas as I did on your jsfiddle like so:
var newCanvas = document.createElement('canvas');
newCanvas.getContext("2d").drawImage(image,0,0);
A function such as this would be able to hack a section out of that canvas:
context.putImageData(newCanvas.getContext("2d").getImageData(x,y,40,40),x,y);
Thus giving you the chowder effect. Good show man, good luck. Pst me if it doesn't work
EDIT: However this solution will ignore some context scaling transformations. Just be smart about how you handle scale on your own (and you really should be anyways if you want the true "chowder" effect)
So, feel pretty dumb about this, but apparently when you call rect() you also have to make sure to call closePath afterwards in order to close the clipping area. Glad I figured it out finally, now on to adding multiple layers!
Here's the working fiddle: http://jsfiddle.net/JERje/129/
Is there a way to avoid redrawing all the elements on the canvas (so I don't have to keep track of everything), while still having a smooth drawing experience with the currently drawn line?
This is a very good question, but its worded vaguely. Please be more careful wording questions in the future.
Typically when drawing smooth lines you need to redraw the line from the beginning.
You do not need to redraw everything from the beginning though, because you should be following these operations:
Save the current canvas to an in-memory canvas
Begin drawing a new line
As you're drawing, you are constantly:
Clearing the canvas
Drawing from in-memory canvas onto main canvas
Drawing the line-so-far
When the line finishes, you save the new canvas to the in-memory canvas and repeat this process
The only line you need to keep track of (in terms of points) is the "current" one. All the old lines are saved into the bitmap via the in-memory canvas.
Here's an example I made a long time ago, dealing with smooth lines specifically. The code organization is weird because I started with someone elses code, but it should give you the basic idea:
http://jsfiddle.net/NWBV4/10/
The drawing part described above is seen in the mousemove:
this.mousemove = function(ev) {
if (tool.started) {
context.clearRect(0, 0, 300, 300);
// put back the saved content
context.drawImage(memCanvas, 0, 0);
tool.points.push({
x: ev._x,
y: ev._y
});
drawPoints(context, tool.points);
}
};