Create smooth animation in canvas - javascript

I have a canvas object which is rendering an image. When the user click on button the image will move to right. My problem is this movement is not smooth. The image is simply jumping to the specified position. How can I make this movement smooth? This is the codepen example Can anyone please help me?
$(window).on('load', function () {
myCanvas();
});
function myCanvas() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var x = 0;
function fly() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.closePath();
ctx.beginPath();
var img = new Image();
img.onload = function () {
ctx.drawImage(img, x, 0);
};
img.src = 'http://via.placeholder.com/200x200?text=first';
}
fly();
$('#movebutton').click(function () {
for (i = 0; i < 200; i++) {
x = i;
requestAnimationFrame(fly);
}
});
}
<canvas id="myCanvas" width="960" height="600"></canvas>
<button id="movebutton">Move</button>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

First of all, why are you loading your image in your frame rendering function - if cache is disabled, it will request an image every frame!
I rewrote the script so that the animation is linear and smooth, you can edit the speed variable to adjust the movement speed.
$(window).on('load', function () {
var img = new Image();
img.onload = function () {
myCanvas(img);
};
img.src = 'http://via.placeholder.com/200x200?text=first';
});
function myCanvas(img) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var x = 0;
var last_ts = -1
var speed = 0.1
function renderScene() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.closePath();
ctx.beginPath();
ctx.drawImage(img, x, 0);
}
function fly(ts) {
if(last_ts > 0) {
x += speed*(ts - last_ts)
}
last_ts = ts
if(x < 200) {
renderScene()
requestAnimationFrame(fly);
}
}
renderScene()
$('#movebutton').click(function () {
x = 0;
requestAnimationFrame(fly);
});
}

Related

Changing Image Position drawn with canvas drawImage function [duplicate]

I am trying to move an image from the right to the center and I am not sure if this is the best way.
var imgTag = null;
var x = 0;
var y = 0;
var id;
function doCanvas()
{
var canvas = document.getElementById('icanvas');
var ctx = canvas.getContext("2d");
var imgBkg = document.getElementById('imgBkg');
imgTag = document.getElementById('imgTag');
ctx.drawImage(imgBkg, 0, 0);
x = canvas.width;
y = 40;
id = setInterval(moveImg, 0.25);
}
function moveImg()
{
if(x <= 250)
clearInterval(id);
var canvas = document.getElementById('icanvas');
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
var imgBkg = document.getElementById('imgBkg');
ctx.drawImage(imgBkg, 0, 0);
ctx.drawImage(imgTag, x, y);
x = x - 1;
}
Any advice?
This question is 5 years old, but since we now have requestAnimationFrame() method, here's an approach for that using vanilla JavaScript:
var imgTag = new Image(),
canvas = document.getElementById('icanvas'),
ctx = canvas.getContext("2d"),
x = canvas.width,
y = 0;
imgTag.onload = animate;
imgTag.src = "http://i.stack.imgur.com/Rk0DW.png"; // load image
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // clear canvas
ctx.drawImage(imgTag, x, y); // draw image at current position
x -= 4;
if (x > 250) requestAnimationFrame(animate) // loop
}
<canvas id="icanvas" width=640 height=180></canvas>
drawImage() enables to define which part of the source image to draw on target canvas. I would suggest for each moveImg() calculate the previous image position, overwrite the previous image with that part of imgBkg, then draw the new image. Supposedly this will save some computing power.
Here's my answer.
var canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var myImg = new Image();
var myImgPos = {
x: 250,
y: 125,
width: 50,
height: 25
}
function draw() {
myImg.onload = function() {
ctx.drawImage(myImg, myImgPos.x, myImgPos.y, myImgPos.width, myImgPos.height);
}
myImg.src = "https://mario.wiki.gallery/images/thumb/c/cc/NSMBUD_Mariojump.png/1200px-NSMBUD_Mariojump.png";
}
function moveMyImg() {
ctx.clearRect(myImgPos.x, myImgPos.y, myImgPos.x + myImgPos.width, myImgPos.y +
myImgPos.height);
myImgPos.x -= 5;
}
setInterval(draw, 50);
setInterval(moveMyImg, 50);
<canvas id="canvas" class="canvas" width="250" height="150"></canvas>
For lag free animations,i generally use kinetic.js.
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var hexagon = new Kinetic.RegularPolygon({
x: stage.width()/2,
y: stage.height()/2,
sides: 6,
radius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
layer.add(hexagon);
stage.add(layer);
var amplitude = 150;
var period = 2000;
// in ms
var centerX = stage.width()/2;
var anim = new Kinetic.Animation(function(frame) {
hexagon.setX(amplitude * Math.sin(frame.time * 2 * Math.PI / period) + centerX);
}, layer);
anim.start();
Here's the example,if you wanna take a look.
http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-animate-position-tutorial/
Why i suggest this is because,setInterval or setTimeout a particular function causes issues when large amount of simultaneous animations take place,but kinetic.Animation deals with framerates more intelligently.
Explaining window.requestAnimationFrame() with an example
In the following snippet I'm using an image for the piece that is going to be animated.
I'll be honest... window.requestAnimationFrame() wasn't easy for me to understand, that is why I coded it as clear and intuitive as possible. So that you may struggle less than I did to get my head around it.
const
canvas = document.getElementById('root'),
btn = document.getElementById('btn'),
ctx = canvas.getContext('2d'),
brickImage = new Image(),
piece = {image: brickImage, x:400, y:70, width:70};
brickImage.src = "https://i.stack.imgur.com/YreH6.png";
// When btn is clicked execute start()
btn.addEventListener('click', start)
function start(){
btn.value = 'animation started'
// Start gameLoop()
brickImage.onload = window.requestAnimationFrame(gameLoop)
}
function gameLoop(){
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height)
// Draw at coordinates x and y
ctx.drawImage(piece.image, piece.x, piece.y)
let pieceLeftSidePos = piece.x;
let middlePos = canvas.width/2 - piece.width/2;
// Brick stops when it gets to the middle of the canvas
if(pieceLeftSidePos > middlePos) piece.x -= 2;
window.requestAnimationFrame(gameLoop) // Needed to keep looping
}
<input id="btn" type="button" value="start" />
<p>
<canvas id="root" width="400" style="border:1px solid grey">
A key point
Inside the start() function we have:
brickImage.onload = window.requestAnimationFrame(gameLoop);
This could also be written like: window.requestAnimationFrame(gameLoop);
and it would probably work, but I'm adding the brickImage.onload to make sure that the image has loaded first. If not it could cause some issues.
Note: window.requestAnimationFrame() usually loops at 60 times per second.

Canvas - drawImage() after clearRect()

I have a problem. I am creating simple game in Canvas using JavaScript. Image doesn't display after call clearRect(), does anyone know, how to solve it?
var left1 = 0;
var context1 = document.getElementById('canvas1').getContext('2d');
render1();
function render1() {
var image = new Image();
image.onload = function () {
context1.drawImage(image, left1, 0, 200, 200);
};
image.src = 'http://www.pngall.com/wp-content/uploads/2016/06/Earth-Free-Download-PNG.png';
left1++;
requestAnimationFrame(render1);
}
var left2 = 0;
var context2 = document.getElementById('canvas2').getContext('2d');
render2();
function render2() {
context2.clearRect(0, 0, 500, 250);
var image = new Image();
image.onload = function () {
context2.drawImage(image, left2, 0, 200, 200);
};
image.src = 'http://www.pngall.com/wp-content/uploads/2016/06/Earth-Free-Download-PNG.png';
left2++;
requestAnimationFrame(render2);
}
canvas {
display: block;
}
It works, but old images are not deleted:
<canvas id="canvas1" height="250" width="500"></canvas>
It doesn't work, because of clearRect():
<canvas id="canvas2" height="250" width="500"></canvas>
if you try to animate your image , its not necessary to make two canvas instead use a timer , i hope this will help
`
var left1 = 0;
var context1 = document.getElementById('canvas1').getContext('2d');
var canvas1 = document.getElementById('canvas1');
window.onload = init;
function init() {
setInterval(drawc, 1000 / 60);
};
function drawc() {
if (left1 > canvas1.width) {
left1 = 0;
}
render1();
}
function render1() {
with(context1) {
clearRect(0, 0, canvas1.width, canvas1.height);
var image = new Image();
image.src = 'http://www.pngall.com/wp-content/uploads/2016/06/Earth-Free-Download-PNG.png';
beginPath();
drawImage(image, left1, 0, 200, 200);
closePath();
fill();
left1++;
// requestAnimationFrame(render1);
}
};

Can't view the movement of my javascript animation?

So I'm trying to do some simple javascript animation with an image, and this is as far as I've gotten. I can load the file, but it simply shows the 'end result' and no actual movement (unless I step through each movement with console). I'm pretty sure I need to use setTimeout somewhere in my code, but can't seem to find the right way to use it.
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var img;
img = new Image();
img.src = "img/background4x3.png";
var sun;
sun = new Image();
sun.src = "img/rsz_sun_200x200.png";
var y = 250;
var func1 = function (y) {
ctx.clearRect(0, 0, 600, 500);
ctx.drawImage(img, 0, 0, 600, 500);
ctx.globalCompositeOperation = 'source-over';
setTimeout(100000);
ctx.drawImage(sun, 5, y);
};
img.onload = function() {
//x = 1;
while(y > 150) {
func1(y);
y = y - 5;
setTimeout(100000);
}
};
That's not a correct usage of setTimeout. It doesn't "sleep" for this time. The script just runs a function after some time. Please, read documentation before using.
setTimeout(myFunction, 1000); // runs myFunction after a second
In your case, there are several ways to do this properly. For example, you can use setInterval. Just something like this:
var y = 250, interval;
var func1 = function () {
if (y < 150) {
clearInterval(interval);
return;
}
ctx.clearRect(0, 0, 600, 500);
ctx.drawImage(img, 0, 0, 600, 500);
ctx.globalCompositeOperation = 'source-over';
ctx.drawImage(sun, 5, y);
y = y - 5;
};
img.onload = function() {
func1();
interval = setInterval(func1, 10000);
};
or using setTimeout in another way:
var y = 250, interval;
var func1 = function () {
ctx.clearRect(0, 0, 600, 500);
ctx.drawImage(img, 0, 0, 600, 500);
ctx.globalCompositeOperation = 'source-over';
ctx.drawImage(sun, 5, y);
y = y - 5;
if (y > 150) {
setTimeout(func1, 1000);
}
};
img.onload = function() {
func1();
};

Game loop not doing what its supposed to

Hi I'm trying to make a very simple game using javascripts canvas element. I have a rectangle thats drawn on the canvas and I would like for it to move across the canvas when user clicks a button but its not working.
here is my html:
<style>
canvas {
border: 1px solid black;
height: 300px;
width:500px;
}
</style>
</head>
<body>
<button id = "play">Click to play</button>
</body>
My javascript:
$( document ).ready(function() {
var x = document.createElement("CANVAS");
var ctx = x.getContext("2d");
ctx.fillStyle = "#FF0000";
var x1 = 10;
var y = 10;
ctx.fillRect(x1, y, 80, 10);
document.body.appendChild(x);
var Game = {stopped:true};;
Game.draw = function() {
ctx.fillRect(x1, y, 80, 10);
};
Game.update = function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
x1 = x1+5;
};
Game.run = function() {
Game.update();
Game.draw();
};
$("#play").click(function() {
Game.stopped = false;
while (!Game.stopped){
Game.run();
}
});
});
There are multiple problems in your script.
there is no variable called, canvas it is x
Your loop is an infinite while loop, which does not give any time for the UI to update - since browser tab is a single threaded app both js execution and the repaint/refresh of the UI happens in the same thread
So
var interval;
$("#play").click(function () {
Game.stopped = false;
interval = setInterval(Game.run, 5);
});
$("#stop").click(function () {
Game.stopped = true;
clearInterval(interval);
});
Demo: Fiddle
There is another simple implement:
$(document).ready(function () {
var canvas = document.createElement("CANVAS");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
var x1 = 10;
var y = 10;
ctx.fillRect(x1, y, 80, 10);
document.body.appendChild(canvas);
var Game = {stopped: true};
;
Game.draw = function () {
ctx.fillRect(x1, y, 80, 10);
};
Game.update = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
x1 = x1 + 5;
};
Game.run = function () {
Game.update();
Game.draw();
};
$("#play").click(function () {
Game.stopped = false;
// while (!Game.stopped) {
// Game.run();
// }
if(!Game.stopped){
setInterval(Game.run,1000);
}
});
});
For animation, it's better to use Window.requestAnimationFrame(), if you want to get a better performance.

FadeIn FadeOut in Html5 canvas

I ve got an canvas with an image and i want to fadein and fade out the image constantly. I ve used the above code:
<!DOCTYPE HTML>
<html>
<head>
<script>
var canvas;
var context;
var ga = 0.0;
var timerId = 0;
var timerId1 = 0;
function init()
{
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
timerId = setInterval("fadeIn()", 300);
console.log(timerId);
}
function fadeIn()
{
context.clearRect(0,0, canvas.width,canvas.height);
context.globalAlpha = ga;
var photo = new Image();
photo .onload = function()
{
context.drawImage(photo , 0, 0, 450, 500);
};
photo .src = "photo .jpg";
ga = ga + 0.1;
if (ga > 1.0)
{
fadeOut();
goingUp = false;
clearInterval(timerId);
}
}
function fadeOut()
{
context.clearRect(0,0, canvas.width,canvas.height);
context.globalAlpha = ga;
var photo = new Image();
photo .onload = function()
{
context.drawImage(photo , 0, 0, 450, 500);
};
photo .src = "photo .jpg";
ga = ga - 0.1;
if (ga < 0)
{
goingUp = false;
clearInterval(timerId);
}
}
</script>
</head>
<body onload="init()">
<canvas height="500" width="500" id="myCanvas"></canvas>
</body>
Is it possible to insert two functions into setIntervals?? I want to trigger fadeOut after fadeIn function. How is it possible??
Here is one way of doing this:
var alpha = 0, /// current alpha value
delta = 0.1; /// delta = speed
In the main loop then increase alpha with current alpha. When alpha has reached wither 0 or 1 reverse delta. This will create the ping-pong fade:
function loop() {
alpha += delta;
if (alpha <= 0 || alpha >= 1) delta = -delta;
/// clear canvas, set alpha and re-draw image
ctx.clearRect(0, 0, demo.width, demo.height);
ctx.globalAlpha = alpha;
ctx.drawImage(img, 0, 0);
requestAnimationFrame(loop); // or use setTimeout(loop, 16) in older browsers
}

Categories