I made a simple canvas animation using a function which clears and redraws the canvas, and the calling requestAnimationFrame, It works awesome but when the window is blurred for long, say 10 secs, then the canvas clears itself and nothing's drawn. May anybody give an Idea why it's happening and how to solve it?
The structure of function is like :-
function drawFrame(time){
//clear and redraw to be understood as working functions in prototype ...
canvas.clear();
canvas.redraw();
requestAnimationFrame(drawFrame);
}
requestAnimationFrame(drawFrame);
Related
Long time lurker but never made an account. Just wanted to preface that I'm by no means a dev and just tinkering and experimenting for fun, so I apologise in advance if I seem really dumb.
I'm working on a dynamic overlay for Twitch streaming and was previously using AS3 but I've switched over to HTML5 now. I'm trying to load an image onto the canvas (which will eventually be a profile picture fetched using Twitch API... but one step at a time). I'm using Adobe Animate and I have the following so far applied in Actions on the first frame of the layer:
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
show_image();
function show_image() {
source_image = new Image();
source_image.src = 'https://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png';
source_image.onload = function () {
context.drawImage(source_image, 100, 100);
}
}
When I hit Ctrl+Enter and see it in Chrome, the image appears for the first frame then disappears. I'm not sure how I'm supposed to get it to stay indefinitely. I need to be able to animate it later, and it'll change depending on the latest follow/donation/sub, etc.
I tried extending the frame itself in the timeline, however, this just changed long how it took to loop and didn't make the image itself stay longer. I'm probably missing something really simple!
Any help would be appreciated. Thanks!
Your code is okay if your approach is using a canvas with HTML and JS, without any libraries involved. However, this is not the case, as you are using Animate, and the way to draw graphics with it is different than using default canvas methods like drawImage().
Animate includes the CreateJS suite, which includes the EaselJS library ,and this allows you to use another tools to draw to your canvas. Two or them are the Stage object, the visual container of your animate project, and the Bitmap object, who represents an image, canvas or video. For effects of this question, only both objects are required.
Note that the code below is only for the first frame:
/* It is not necessary to declare the canvas or stage element,
as both are already declared. At this point the stage is ready to be drawn */
show_image();
function show_image() {
var source_image = new Image();
source_image.src = 'https://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png';
source_image.onload = function(event) {
/* A new Bitmap object is created using your image element */
var bmp = new createjs.Bitmap(event.currentTarget);
/* The Bitmap is added to the stage */
stage.addChild(bmp);
}
}
This question already has answers here:
HTML5 Canvas: Get Event when drawing is finished
(5 answers)
Closed 1 year ago.
html:
<canvas id="cnv" width="786" height="1113">
js:
var img = new Image(),
cnv = document.getElementById('cnv');
var context = cnv.getContext('2d');
img.onload = function () {
context.drawImage(img, 0, 0, 786, 1113);
alert('finished drawing');
}
img.src = 'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png';
http://jsfiddle.net/FxrSa/14/
I want to show the alert after the canvas finished his rendering. But the alert show before the image is drawn.
How can I wait for the GUI thread to finish his rendering?
Canvas drawImage is synchronous. And even, really synchronous.
Your problem is that alert() is blocking, and even really blocking.
By this I mean it does not only block the js execution, it also blocks the page rendering. So the browser has painted your image on your canvas, but didn't display it yet when you called alert().
One should always avoid alert and replace it with normal DOM elements.
Ps: Here is a proof that your image is indeed already painted on the canvas.
Double buffered canvas
An on screen canvas has two pixel buffers. One is called the back buffer, all rendering is done directly to the back buffer. When you make a render call, ctx.drawImage(foo,0,0); the function will not return until it has drawn the back buffer pixels. Even if the GPU is doing the rendering and the CPU is doing nothing, Javascript will wait until the rendering is complete befor moving on to the next line.
When the canvas is on the screen, you will not see the results of any rendering until the current execution has finished.
function myRender(){
ctx.draw(foo,0,0); // draw stuff
... new pixel content is only in back buffer
return;
}
function myLoop(){
ctx.clearRect(,0,0,w,h);
myRender(); // draw stuff
.. new pixels not visible
}
myLoop();
// no more code
When the myLoop function has returned and javascript has nothing to do, the DOM will see that the canvas backbuffer has changed. It then moves the back buffer to the front buffer so that it can be seen by the hardware that creates the display signal.
This is called double buffering, and it stop artifacts like shearing and flickering caused when you draw to the screen and the screen displays part of the rendering before it is finished.
When the canvas is offscreen, there is no front buffer.
The same is true for all DOM content.
As a workaround you may try this:
//after the rendering
setTimeout(function(){
alert("Yay");
},100);
HTML5 Canvas: Get Event when drawing is finished
I have the following problem:
I create a Raphael canvas in a div. This happens as soon as the page is loaded and the initRadar() function is called:
var r;
var paper;
var c;
function initRadar(){
r = $( "#circ" );
paper = Raphael("circ", r.width(), r.height());
c = paper.circle(r.width()/2, r.height()/2, r.height()/2-2);
$(window).on("orientationchange",function(){
//redraw(); // <--- the way I wanted it
setTimeout(function(){ redraw(); }, 300); // <--- *yuck*
});
}
This functions perfectly so far. My problem starts when the orientation of the viewport changes. I thought I could add an event handle to the window, which fires, when the orientation changes and redraw the content. And it works... kind of. I wanted to call the second function:
function redraw(){
c.remove();
c = paper.circle(r.width()/2, r.height()/2, r.height()/2-2);
}
Whenever the orientation changes, this function redraws the content. And this also works... almost. The problem is, I have a race condition. Even though the orientation change event fired, the #circ div still has the old size and position. This leads to the strange effect, that when the viewport is in portrait mode, the landscape circle is drawn and vice versa.
My current solution is to use the timeout function (yuck), to wait a few ms so that the layout is done before I draw the circle. It works, but it is ugly and I don't want to have such a hack in my code.
Can someone point me in the direction how to solve this problem correctly?
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/
I'm struggling to clear a canvas for 2 simple stroke paths.
Example: http://dl.dropbox.com/u/104380/canvas-test-case.html
... I'm using the new
requestAnimFrame()
by Paul Irish. But I don't think this should have any effect on Canvas contexts, as opposed to a setInterval. As far as I know, I'm also correctly using beginPath() and recalling getContext() inside the render loop.
... problem is, the two original strokes are not clearing!
Any ideas?
this line...
context.clearRect(0,0,canvas.width,canvas.height);
should be
context.clearRect(0,0,canvas[0].width,canvas[0].height);