I have the following lines from a canvas sprite animation from Git.
I am just wondering how can I stop the animations once it ends the sprite.
window.requestAnimFrame = (function(callback) { // shim
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function animate() { // Animation loop that draws the canvas
context.clearRect(0, 0, context.canvas.width, context.canvas.height); // Clear the canvas
spriteMap.draw(context, 100, 100); // Draw the sprite
requestAnimFrame(animate); // Run the animation loop
}
https://github.com/IceCreamYou/Canvas-Sprite-Animations
Use cancelAnimationFrame() together with the request-id returned by requestAnimationFrame():
var reqId;
function animate() {
// ...
reqId = requestAnimFrame(animate); // returns request ID
}
Then to stop:
cancelAnimationFrame(reqId);
If you depend on the polyfill you will also have to include the polyfill for cancelAnimationFrame():
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
Related
I am currently trying to add a play video on scroll animation to my project. The animation works smoothly on IPhone and Desktops, but is choppy on Android phones. Any suggestions on how to fix this? I used the example on code pen to achieve this animation.
https://codepen.io/marduklien/pen/MdvdEG
My code below:
var frameNumber = 0,
playbackConst = 950;
var requestAnimationFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame;
// Global selectors
const $scroll = document.getElementById('scroll'),
video = document.getElementById('video');
video.addEventListener('loadedmetadata', function() {
$scroll.style.height = Math.floor(video.duration) * playbackConst + "px";
});
function scrollPlay() {
var yPosition = window.pageYOffset || document.documentElement.scrollTop;
var frameNumber = yPosition / playbackConst;
video.currentTime = frameNumber;
requestAnimationFrame(scrollPlay);
}
requestAnimationFrame(scrollPlay)
I am using "smoothie charts" http://smoothiecharts.org/.
I'm trying to make the animation stop and restart, but all I can do is freeze the "viewing" image. The animation doesn't really stop. It seems to continue to run in the background?
Once I restart it, the entire chart jumps to actual time.
On "start" I need that animation to resume, from where it was paused.
How can I achieve this?
I'm new with to this and have been trying to figure it out for a week, but i'm stuck on this problem.
This is the code for animation:
SmoothieChart.AnimateCompatibility = (function() {
var requestAnimationFrame = function(callback, element) {
var requestAnimationFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
return window.setTimeout(function() {
callback(new Date().getTime());
}, 16);
};
return requestAnimationFrame.call(window, callback, element);
},
cancelAnimationFrame = function(id) {
var cancelAnimationFrame =
window.cancelAnimationFrame ||
function(id) {
clearTimeout(id);
};
return cancelAnimationFrame.call(window, id);
};
return {
requestAnimationFrame: requestAnimationFrame,
cancelAnimationFrame: cancelAnimationFrame
};
})();
And here is the original stop...
SmoothieChart.prototype.stop = function() {
if (this.frame) {
SmoothieChart.AnimateCompatibility.cancelAnimationFrame(this.frame);
delete this.frame;
}
};
This is the start function
SmoothieChart.prototype.start = function() {
if (this.frame) {
// We're already running, so just return
return;
}
// Make sure the canvas has the optimal resolution for the device's pixel ratio.
if (this.options.enableDpiScaling && window && window.devicePixelRatio !== 1) {
var canvasWidth = this.canvas.getAttribute('width');
var canvasHeight = this.canvas.getAttribute('height');
this.canvas.setAttribute('width', canvasWidth * window.devicePixelRatio);
this.canvas.setAttribute('height', canvasHeight * window.devicePixelRatio);
this.canvas.style.width = canvasWidth + 'px';
this.canvas.style.height = canvasHeight + 'px';
this.canvas.getContext('2d').scale(window.devicePixelRatio, window.devicePixelRatio);
}
// Renders a frame, and queues the next frame for later rendering
var animate = function() {
this.frame = SmoothieChart.AnimateCompatibility.requestAnimationFrame(function() {
this.render();
animate();
}.bind(this));
}.bind(this);
animate();
};
I'm animating some image presentation using
setInterval(function() {
$('.img').css('someprop', randomValue());
}, 2000);
..where .img has css transitions enabled, hence animation.
When i go over to another tab for a few minutes and come back to this tab, the animations go crazy for 5-6 seconds and catch up with everything at once.
Is there a way for me to stop the accumulation of undisplayed animations while the tab is not visible? What's the right approach to solve this? I understand the browser stops the animations while a window is not rendering, for performance reasons, but is there a way for me to tell it not to try to catch up with everything it "missed out on" ?
window.requestAnimationFrame does exactly what you want, only animating/running when the tab is "active" (visible).
See the MDN page on requestAnimationFrame for more details.
Example code by Paul Irish, posted here for posterity (here's a link to his explanation page)
// requestAnim shim layer by Paul Irish
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
// example code from mr doob : http://mrdoob.com/lab/javascript/requestanimationframe/
var canvas, context, toggle;
init();
animate();
function init() {
canvas = document.createElement( 'canvas' );
canvas.width = 512;
canvas.height = 512;
context = canvas.getContext( '2d' );
document.body.appendChild( canvas );
}
function animate() {
requestAnimFrame( animate );
draw();
}
function draw() {
var time = new Date().getTime() * 0.002;
var x = Math.sin( time ) * 192 + 256;
var y = Math.cos( time * 0.9 ) * 192 + 256;
toggle = !toggle;
context.fillStyle = toggle ? 'rgb(200,200,20)' : 'rgb(20,20,200)';
context.beginPath();
context.arc( x, y, 10, 0, Math.PI * 2, true );
context.closePath();
context.fill();
}
"requestAnimationFrame" method is not working in the following example. Console doesn't show any error messsage. Then what is the error in this code?
html:
<body>
<div id="container">
<canvas id="canvas" width="1024" height="1024"></canvas>
</div>
<script type="text/javascript" src = "Jquery/easy.js"></script>
</body>
javascript:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var chop1 = new Image();
chop1.src = "img/chopper.png";
var chopperX = 0;
var chopperY = 0;
var ascent = 20;
function fly()
{
chopperY += ascent;
ctx.drawImage(chop1, chopperX, chopperY, 30, 80);
requestAnimationFrame(fly);
}
window.onload = function() {
init()
};
function init()
{
chop1.src = "img/chopper.png";
ctx.drawImage(chop1, 0, 0, 30, 80);
fly()
}
;
You probably want to scale the animation using the timestamp that's passed to the callback given to requestAnimationFrame. Use something like this:
var ascent = 20;
var limit = 5000;
var start = null;
function fly(timestamp) {
if (start === null) {
start = timestamp;
}
var progress = timestamp - start;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(chop1, 0, Math.min(progress / ascent, canvas.height),
chop1.width, chop1.height);
if (progress < limit) {
requestAnimationFrame(fly);
}
}
requestAnimationFrame(fly);
You can modify ascent and limit to increase/decrease the animation's speed and final position to taste.
As others have mentioned, be sure to use the correct requestAnimationFrame:
window.requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
More information:
https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame
You need to call your draw() from within the fly() here is how I got it working with comments to explain. You'll need to change your image's src to what it is in your own project since I didn't have your image.
Edit:
Added a way to draw image based on image size and made image turn around at edges of canvas. And here is a fiddle to show it in action:
Canvas Animation
JavaScript
/**
* Namespace to set up your animation
* #namespace
*/
var anim = (function() {
var exports = {};
// Make sure we use the right "requestAnimationFrame"
// For the right browser
window.requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
// Keep some variables for the namespace
var canvas = null, // The Canvas element to draw to
ctx = null, // The context of the canvas
chop1 = null, // The image that will get drawn
chopperX = 0, // The X position of the image
chopperY = 0, // The Y position of the image
ascent = 20; // How much to increment height by per anim
/**
* The function to get called by, and to perpetuate
* the requestAnimationFrame() function
* #returns {undefined}
*/
function fly() {
// Increment the height of the image
chopperY += ascent;
// Switch directions at bottom of canvas
if (chopperY > 1000) {
ascent = -ascent;
}
if (chopperY < 0) {
ascent = -ascent;
}
// Clear the canvas so the animation looks good
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw the image to the canvas
ctx.drawImage(chop1, chopperX, chopperY, chop1.width, chop1.height);
// Get ready to draw again on the next animation frame
requestAnimationFrame(fly);
}
/**
* Function to start the animation process
* #param {Canvas DOM Element} canvasElement The canvas to draw on
* #returns {undefined}
*/
exports.go = function(canvasElement) {
// Set the canvas we draw to
canvas = canvasElement;
// Get a context to draw to
ctx = canvas.getContext("2d");
// Create the image we want to draw
chop1 = new Image();
// Set the image's source
chop1.src = "../../img/dice.png";
// Start the animation process
window.requestAnimationFrame(fly);
};
// Let our functions get called from our namespace
return exports;
}());
/**
* Function that gives the canvas element to the namespace to animate
* #returns {undefined}
*/
function init() {
anim.go(document.getElementById("canvas"));
}
/**
* Function to start the initialization on a window load
* #returns {undefined}
*/
window.onload = init;
//init();
HTML
<body>
<div id="container">
<canvas id="canvas" width="1024" height="1024"></canvas>
</div>
</body>
I have a simple draw image for my canvas but it won't display on the first frame.
It's driving me mad i dunno why it won't do it!!
This is my script:
img = new Image();
img.src = 'images/0.png'; //preLoad the image
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback, element){
window.setTimeout(callback, 1000 / 60);
};
})(); //frames per second
function gameUpdate(){
previous = 0;
requestAnimFrame( gameUpdate );
draw();
}
Then the draw() function has this:
//doesn't display on first fame
canvas['canvas1'].ctx.drawImage(img, 100, 150);
//displays on first frame
canvas['canvas1'].ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
canvas['canvas1'].ctx.fillRect (30, 30, 55, 50);
FillRect works fine but not the drawImage for the first frame, any ideas why this might be ??
I think you should start the animation loop by calling requestAnimFrame outside of your gameUpdate function
requestAnimFrame(gameUpdate)
You might also need to make sure the image is actually loaded
var img = new Image();
img.onload = function() {
// do the draw image here
}
img.src = 'images/0.png'; //preLoad the image