This question already has answers here:
How to clear the canvas for redrawing
(25 answers)
Closed 4 years ago.
How can I get the canvas to clear the previous image so that it looks like my character is moving? Right now, it is showing every animation of my character as he moves across the screen. I posted a picture below.
Here is my Javascript
function update(){
var imageObj = new Image();
if(fr1){
imageObj.src = 'https://i.ibb.co/yhbRD1R/Mega1.png';
}
if(fr2){
imageObj.src = 'https://i.ibb.co/S74hLKX/Mega2.png';
}
if(fr3){
imageObj.src = 'https://i.ibb.co/tC1j7wC/Mega3.png';
}
if(fr4){
imageObj.src = 'https://i.ibb.co/Tr2cqH9/Mega4.png';
}
if(fr5){
imageObj.src = 'https://i.ibb.co/jvr49xx/Mega5.png';
}
if(fr6){
imageObj.src = 'https://i.ibb.co/BrQnPNR/Mega6.png';
}
if(fr7){
imageObj.src = 'https://i.ibb.co/CJdzqGR/Mega7.png';
}
if(fr8){
imageObj.src = 'https://i.ibb.co/frbN0Dj/Mega8.png';
}
if(fr9){
imageObj.src = 'https://i.ibb.co/RjLL6z1/Mega9.png';
}
if(fr10){
imageObj.src = 'https://i.ibb.co/2ypxYjw/Mega10.png';
}
var canvas= document.getElementById('canvas');
var context = canvas.getContext('2d');
image1.style.visibility="hidden";
imageObj.onload = function() {
context.drawImage(imageObj,mainx,mainy,100,100);
};
}
Here is what's happening:
You can use context.clearRect(x, y, width, height) every time your new image loads. Also, I've simplified your code a little by putting all your animation sprites into an array, and then selecting the given frame using the frameCount % frames.length. Here frameCount is a variable which is incremented every game-loop (every time setInterval runs). Thus, using the modulo operator % you can restrict the number to be between 0 and the length of the array, allowing you to select a new frame from your frames array each time your loop runs.
See working example below:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var mainx = 0;
var mainy = canvas.height/2;
var frames = ['https://i.ibb.co/yhbRD1R/Mega1.png',
'https://i.ibb.co/S74hLKX/Mega2.png',
'https://i.ibb.co/tC1j7wC/Mega3.png',
'https://i.ibb.co/Tr2cqH9/Mega4.png',
'https://i.ibb.co/jvr49xx/Mega5.png',
'https://i.ibb.co/BrQnPNR/Mega6.png',
'https://i.ibb.co/CJdzqGR/Mega7.png',
'https://i.ibb.co/frbN0Dj/Mega8.png',
'https://i.ibb.co/RjLL6z1/Mega9.png',
'https://i.ibb.co/2ypxYjw/Mega10.png'];
function update(fr) {
var imageObj = new Image();
imageObj.src = frames[fr];
imageObj.onload = function() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(imageObj, mainx, mainy, 100, 100);
};
mainx = (mainx + 10) % canvas.width; // update position of character
frameCount += 1; // update frame count to move to next image frame
}
var frameCount = 0;
setInterval(function() {
update(frameCount % frames.length);
}, 100)
<canvas id="canvas" height="200" width="500" style="border: 1px solid black;"></canvas>
Try putting context.clearRect(0, 0, canvas.width, canvas.height); before the context.drawImage(imageObj,mainx,mainy,100,100);.
Related
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.
i would like to command my image.
Basically i have this code already;
But how to i move my image to its desired location?
Like a little bit on left, more to right, i mean the coordinates... where should i put it here?
if(document.getElementById('fig1').checked){
var canvas = document.getElementById('displaycake_sketch');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 10, 10);
};
imageObj.src = 'http://lh3.googleusercontent.com/-fsFMyfNLNG8/TuZs45U0dZI/AAAAAAAAg38/QIjqug0MnAo/Ic42/barbie6.png';
}
Thank you in advance!
The drawImage() method of canvas has two coordinates (x and y). If you look at the documentation, you'll see, the second and third parameters of drawImage() method represents the x-coordinates and y-coordinates of the image respectively. So, you can move around the image to its desired location by changing those coordinates.
context.drawImage(imageObj, 10, 10)
^ ^
DEMO
var canvas = document.getElementById('displaycake_sketch');
var context = canvas.getContext('2d');
var context2 = document.getElementById('displaycake_sketch_2').getContext('2d');
var imageObj = new Image();
imageObj.src = 'http://lh3.googleusercontent.com/-fsFMyfNLNG8/TuZs45U0dZI/AAAAAAAAg38/QIjqug0MnAo/Ic42/barbie6.png';
imageObj.onload = function() {
context.drawImage(imageObj, 10, 10);
context2.drawImage(imageObj, 25, 85);
};
#displaycake_sketch, #displaycake_sketch_2 {
background-color: pink;
}
<canvas width="298" height="397" id="displaycake_sketch"></canvas>
<canvas width="298" height="397" id="displaycake_sketch_2"></canvas>
context.drawImage(imageObj, 10, 10);
This is the line that controls the coordinates; the first 10 is the x value and the second 10 is the y value.
you can move the image using x,y coordinate with .drawImage(image,x,y) function
if(document.getElementById('fig1').checked){
var canvas = document.getElementById('displaycake_sketch');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 20, 20);
};
imageObj.src = 'http://lh3.googleusercontent.com/-fsFMyfNLNG8/TuZs45U0dZI/AAAAAAAAg38/QIjqug0MnAo/Ic42/barbie6.png';
}
Reference : https://www.w3schools.com/graphics/canvas_images.asp
I am using HTML5 canvas and putting two images there but I am facing one problem which is, one image is loaded and visible in chrome but another image is only visible in mozilla but after refresh. I don't know why this is happening as I am new in canvas.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var x = 0;
var y = 0;
var width = 900;
var height = 700;
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, x, y, width, height);
};
imageObj.src = 'http://img13.deviantart.net/1550/i/2011/353/4/2/mobile_game_background_by_disnie-d4jmr8r.jpg';
var startImageObj = new Image();
startImageObj.onload = function() {
context.drawImage(startImageObj, (canvas.width-startImageObj.width)/2, (canvas.height-startImageObj.height)/2)
};
startImageObj.src = 'http://assets.halfbrick.com/yc/v3/images/button-play.png';
<canvas id="canvas" width="900" height="700"></canvas>
fiddle
As onload event is asynchronous, make sure play-button is being set in the onload-handler of the base-image
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var x = 0;
var y = 0;
var width = 900;
var height = 700;
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, x, y, width, height);
var startImageObj = new Image();
startImageObj.onload = function() {
context.drawImage(startImageObj, (canvas.width - startImageObj.width) / 2, (canvas.height - startImageObj.height) / 2)
};
startImageObj.src = 'https://d30y9cdsu7xlg0.cloudfront.net/png/5670-200.png';
};
imageObj.src = 'http://img13.deviantart.net/1550/i/2011/353/4/2/mobile_game_background_by_disnie-d4jmr8r.jpg';
<canvas id="canvas" width="900" height="700"></canvas>
#Rayon's answer is right in that with your current implementation you can't know which image will have loaded first, but IMO it is wrong to wrap everything in the same callback, since you will have to wait for the first image has loaded before trigger the loading of the next one, whcih will produce a flicker apparition of the last image.
Instead, create a preloader function that will trigger a drawing function when both images have been loaded.
This has the advantage to make it easier to call your drawing function later, and also to keep your code a bit cleaner :
/* preloader
inputs :
an array containing the urls of the images to load,
a callback function called when all the images have loaded
outputs:
an array containing all the image elements in the same order has the urls where provided
*/
function preloader(imageURLs, callback) {
var toLoad = imageURLs.length,
toReturn = [],
decrement = function() {
if (--toLoad <= 0) {
callback();
}
};
imageURLs.forEach(function(url) {
var img = new Image()
// you may want to include a more verbose error function
img.onload = img.onerror = decrement;
img.src = url;
toReturn.push(img);
});
return toReturn;
}
function draw() {
ctx.drawImage(background, 0, 0, canvas.width, canvas.height);
ctx.drawImage(front, (canvas.width - front.width) / 2, (canvas.height - front.height) / 2);
}
var ctx = canvas.getContext('2d'),
urls = [
'http://img13.deviantart.net/1550/i/2011/353/4/2/mobile_game_background_by_disnie-d4jmr8r.jpg',
'https://d30y9cdsu7xlg0.cloudfront.net/png/5670-200.png'
],
images = preloader(urls, draw),
background = images[0],
front = images[1];
<canvas id="canvas" width="900" height="700"></canvas>
The title is poorly worded but there's no way to concisely describe the problem. I'm drawing images to the 2D context of a dynamically created canvas. The data of the context is then saved to an image via toDataURL, which is then draw on every frame. The code below is condensed, I will be drawing multiple images to the context, not just one; which is why I'm saving to an image. I will only draw part of the image at once but the image remains constant so I thought this was the best method, if there are alternatives I will happily accept those as answers.
In short: many images drawn on an image. Part of the image draw each frame.
The code below works:
var picture = new Image();
picture.src = "images/tilesheet.png";
var canvas = document.getElementById("background");
var context = canvas.getContext("2d");
function generate(){
var ctx = document.createElement("canvas").getContext("2d");
ctx.canvas.width = canvas.width;
ctx.canvas.height = canvas.height;
ctx.fillStyle = "red";
ctx.rect (0, 0, 40, 40);
ctx.fill();
ctx.drawImage(picture,0,0);
image = new Image();
image.src = ctx.canvas.toDataURL("image/png");
}
function draw(){
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(image, 0,0,100,100,0,0,100,100);
}
function play(){
generate();
setInterval(function(){draw();}, 0.0333);
}
window.onload = function(){
if(picture.complete)play();
else picture.onload = play;
}
<canvas id="background"></canvas>
However this doesn't:
window.Game = {};
canvas = document.getElementById("background");
var tilesheet = new Image();
tilesheet.src = "images/tilesheet.png";
(function(){
function Map(){
this.width = 2736;
this.height = 2736;
this.image = null;
}
Map.prototype.generate = function(){
var ctx = document.createElement("canvas").getContext("2d");
ctx.canvas.width = this.width;
ctx.canvas.height = this.height;
ctx.fillStyle = "red";
ctx.rect (0, 0, 40, 40);
ctx.fill();
ctx.drawImage(tilesheet,0,0);
this.image = new Image();
this.image.setAttribute('crossOrigin', 'anonymous');
this.image.src = ctx.canvas.toDataURL("image/png");
}
Map.prototype.draw = function(context){
context.drawImage(this.image, 0,0, context.canvas.height, context.canvas.height, 0, 0, context.canvas.height, context.canvas.height);
}
Game.Map = Map;
})();
(function(){
var room = new Game.Map();
room.generate();
var draw = function(){
canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
room.draw(canvas.getContext("2d"));
}
Game.play = function(){setInterval(function(){draw();}, 0.0333);}
})();
window.onload = function(){
if(tilesheet.complete)Game.play();
else tilesheet.onload = Game.play;
}
<canvas id="background"></canvas>
It seems therefore, that the problem is lying in the fact that I'm using function objects but I'm not sure. What am I doing wrong? There are no errors in the debug console.
Those two have different execution order.
First one:
...
Attach image.onload
Call generate()
...
Second one:
...
Call generate()
Attach image.onload
...
That's why it's not working - generate() expects image to be loaded, however second case order doesn't guarantees it.
Instead of
...
room.generate();
...
Game.play = function(){setInterval(function(){draw();}, 0.0333);}
do this
...
Game.play = function(){
room.generate();
setInterval(function(){draw();}, 0.0333);
}
I have problem creating simple circle. I think code drawing it is writed like it suposed to be, and another problem is with axis. I dont know why but 0x point begins in the middle of the "game screen". How to make game screen 640px/480px?
Fiddle demo | Screenshot
start.wyswietl = (function(){
var dom = start.dom,
$ = dom.$,
gracz = start.gracz,
canvas, ctx,
pUruchomienie = true;
function createBackground(){
var background = document.createElement("canvas");
bgctx = background.getContext("2d");
dom.dodKlase(background, "background");
background.width = 640;
background.height = 480;
background = new Image();
background.onload = function(){
bgctx.drawImage(background, 0, 0);
};
background.src = "../obrazki/tapeta.png";
dom.dodKlase(background, "board-bg");
return background;
}
function rysuj(callback){
var gracz = document.createElement("canvas");
gctx = gracz.getContext("2d");
gctx.fillStyle = "black";
gctx.arc(5, 40, 5, 0, 2*Math.PI);
gctx.fill();
// dom.dodKlase(gracz, "plansza");
dom.dodKlase(gracz, "gracze");
return gracz;
callback();
}
//function ()