html canvas - issue with moving image - javascript

I am learning html canvas and below is my html code.
<!DOCTYPE html>
<html>
<head>
<script language="javascript">
function moveImage(x) {
var context = document.getElementById('myCanvas').getContext("2d");
var img = new Image();
img.onload = function () {
context.drawImage(img, x, 259);
}
img.src = "flower.jpg";
}
function startDrawing() {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(50, 300);
context.lineTo(950, 300);
context.stroke();
var x=50;
setInterval(function() {
x = x+20;
moveImage(x);
}, 1000);
}
</script>
</head>
<body onload="startDrawing()">
<canvas id="myCanvas" width="1000" height="1000">
</body>
</html>
Please find the below output from this code:
How can I remove the traces of 'older frames' (of the flower), as you could see lots of flowers while it is moving from left to right in the screen shot ? Please help the code changes required.
Thanks.

The problem is you aren't clearing the canvas before drawing on it again. You can clear it using clearRect.
setInterval(function() {
// Clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
x += 20;
moveImage(x);
}, 1000);
Keep in mind that this will clear the entire canvas. If you're rendering anything else, you'll want to redraw it after the clear.

You need to re-render the frame. Here's some code from an incomplete game I wrote:
var main = function () {
var now = Date.now(),
delta = now - then;
update(delta / 1000);
render();
then = now;
// Request to do this again ASAP
requestAnimationFrame(main);
};
GitHub repo code
My render function contains the context.drawImg() work (getting properly re-rendered), and that's similar to your moveImage function.
Edit: A little explanation. The image traces are previous renderings of the your image at each updated position. Without the frame itself being reset, each move of the image is preserved on the screen, giving the appearance of a trail of images.

Related

image height displays 0, requestAnimationFrame(); javascript html5 game

I'm programming a game
I have the next settings:
HTML game.html
<canvas id="canvas" width="288" height="512"></canvas>
<script src="game.js"></script>
JAVASCRIPT game.js
var document;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//load images
var pipeNorth = new Image();
pipeNorth.src = "images/pipeNorth.png";
function draw(){
/*code */
alert(pipeNorth.height);
requestAnimationFrame(draw);
}
draw();
PROBLEM
If I set an alert displaying the image height, it shows 0 during the first two or three alerts, then it starts showing the real height.
Why does this happen? How do I fix this? I think it means the image is not fully loaded when the game begins?
From my experience this happens because the document rendering takes some time. My technique for this case is a time delay:
function draw(){
var delay = 200;//Your delay in milliseconds
setTimeout(function(){
/*code */
alert(pipeNorth.height);
requestAnimationFrame(draw);
},delay);
}
Is it usable for you?
Yes you are right the image is not fully loaded when the game begins.to fix this you simply have to use the "load" event :
var document;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//load images
var pipeNorth = new Image();
pipeNorth.src = "images/pipeNorth.png";
function draw(){
/*code */
alert(pipeNorth.height);
requestAnimationFrame(draw);
}
pipeNorth.addEventListener("load",function(){
//this function will execute when the image is fully loaded
draw();
});

Javascript function from a JS file doesn't get called from the canvas

I'm trying to learn about JavaScript and the html5 canvas, however, it's proving a little confusing and I don't understand why it doesn't seem to work...
I am working on creating a simple map that has some of the capabilities of google maps(drag and drop/zoom in/out/etc). In order to do this, I chose html5 canvas and easeljs for the drag and drop functions.
I have a javascript file (path.js) which contains 2 functions:
pathConstructor() - example function from the easeljs tutorial
drawMap() - copy of the first function slightly modified (and probably wrong right now)
Everything worked fine when I called pathConstructor() from the canvas, however, after I replaced it with drawMap(), everything stopped working. It won't even work if I replace drawMap() with pathContrcutor() right now.
I put some alerts before and after calling the function from the canvas and inside pathConstructor(). The before alert goes off but the others don't so for some reason the function never gets called...
If I use the pathConstructor code as inline code in the canvas then it works just fine, however, I would like to avoid that since I believe it's bad programming. I want it to be neat and each script to have its own file.
Anyone know why this is happening?
HTML
<!Doctype html>
<html>
<head>
<script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>
<script src="path.js" type="text/javascript"></script>
</head>
<body>
<canvas id="canvas" width="1300px" height="800px"style="border:1px dotted black;">
<script>pathConstructor();</script>
</canvas>
</body>
</html>
Javascript
var stage;
function pathConstructor() {
alert('inside pathConstructor');
stage = new createjs.Stage('canvas');
// this lets our drag continue to track the mouse even when it leaves the canvas:
// play with commenting this out to see the difference.
stage.mouseMoveOutside = true;
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
var label = new createjs.Text("drag me", "bold 14px Arial", "#FFFFFF");
label.textAlign = "center";
label.y = -7;
var dragger = new createjs.Container();
dragger.x = dragger.y = 100;
dragger.addChild(circle, label);
stage.addChild(dragger);
dragger.on("pressmove", function(evt) {
// currentTarget will be the container that the event listener was added to:
evt.currentTarget.x = evt.stageX;
evt.currentTarget.y = evt.stageY;
// make sure to redraw the stage to show the change:
stage.update();
});
stage.update();
}
function drawMap() {
stage = new createjs.Stage('canvas');
var bitMap = new createjs.Bitmap('middle-earth-map.jpg');
stage.mouseMoveOutside = true;
var dragger = new createjs.Container();
dragger.x = dragger.y = 0;
dragger.addChild(bitMap);
stage.addChild(dragger);
dragger.on('pressmove', function(evt2)) {
evt2.currentTarget.x = evt2.stageX;
evt2.currentTarget.y = evt2.stageY;
stage.update();
});
stage.update();
}
For me it's working fine, you just have to remove that extra ")" in dragger.on('pressmove', function(evt2)) {;
dragger.on('pressmove', function(evt2)) {
evt2.currentTarget.x = evt2.stageX;
evt2.currentTarget.y = evt2.stageY;
stage.update();
});

Drawing on a canvas element dynamically

I am trying to learn some new things and thought I experiment with canvas a bit.
I got a canvas element that loads an image that i want to draw over once i click an anchor.
HTML
Click Me
<canvas id="test" width=400 height=400></canvas>
Javascript
var c = document.getElementById("test");
var ctx = c.getContext("2d");
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
img.src = 'http://lorempixel.com/400/400/abstract';
$("#test").on('click', function() {
var c2 = document.getElementById('test').getContext('2d');
c2.fillStyle = '#76ff03';
c2.beginPath();
c2.lineTo(100, 50);
c2.lineTo(50, 100);
c2.lineTo(0, 90);
c2.closePath();
c2.fill();
});
All its meant to do is draw a red triangle on top the image that is loaded previously by the canvas.
Unfortunately i don't get anywhere with this.
Any help will be appreciated.
Apparently you are using the "$" function, which you are probably expecting from JQuery, but you are not including the JQuery script on your file.
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
Apart from that, your code seems to work properly.
By the way, the triangle you're drawing is actually green. If you want it to be red you could set
c2.fillStyle = '#ff0000';

HTML5 Frame by frame animation (multiple images)

I've been losing my mind over this. I spent 3 hours trying different methods and finding a solution online, and I still haven't fixed it.
I have two separate images(not a spritesheet) and they need to be displayed one after the other, as an animation, infinitely. Here's is my latest code:
var canvas, context, imageOne, imageTwo, animation;
function init(){
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
imageOne = new Image();
imageTwo = new Image();
imageOne.src = "catone.png";
imageTwo.src = "cattwo.png";
// Just to make sure both images are loaded
setTimeout(function() { requestAnimationFrame(main);}, 3000);
}
function main(){
animation = {
clearCanvas: function(){
context.clearRect(0, 0, canvas.width, canvas.height);
},
renderImageOne: function(){
context.drawImage(imageOne, 100, 100);
},
renderImageTwo: function(){
context.drawImage(imageTwo, 100, 100);
}
};
animation.renderImageOne();
// I also tried calling animation.clearCanvas();
context.clearRect(0, 0, canvas.width, canvas.height);
animation.renderImageTwo();
// I put this here to confirm that the browser has entered the function, and that it hasn't stopped after animation.renderImageTwo();
console.log("cats");
requestAnimationFrame(main);
}
init();
But the problem is that the only one image is displayed, and it's not moving. I can't see any errors or warnings in the console. I'm also sure HTML and JavaScript are connected properly and the images are in the right path. So in any case, only the image in the first function is displayed. Example: animation.renderImageOne(); displays catone, but if I replace it with animation.renderImageTwo(); it displays cattwo.
The problem is here:
animation.renderImageOne();
// I also tried calling animation.clearCanvas();
context.clearRect(0, 0, canvas.width, canvas.height);
animation.renderImageTwo();
Is it's drawing the first image, clearing the canvas, then drawing the second image, then after all that it draws to the screen. Leaving you with only seeing the second image. You will need a variable that alternates values, and use that to determine which picture you should draw:
var canvas, context, imageOne, imageTwo, animation;
var imageToDraw = "one";
And then:
function main() {
...
if(imageToDraw == "one") {
animation.renderImageOne();
imageToDraw = "two";
}
else if(imageToDraw == "two") {
animation.renderImageTwo();
imageToDraw = "one";
}
...
}
Note: You don't need to define animation inside main(), you can move it into global scope. That way you don't redefine it each time you call main().

How to make webkit free canvas context memory when canvas is destroyed

The code below seems to leak memory at a rather alarming rate on webkit (mobile safari & konqueror). I realize the test case could be rewritten to reuse the canvas instead of creating a new one, but I'm wondering why the below doesn't also work. Any insight would be appreciated.
<html>
<head>
<script>
function draw() {
var holder = document.getElementById("holder");
holder.innerHTML = "<canvas id=cnv height=250 width=250>";
var ctx = document.getElementById("cnv").getContext("2d");
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(Math.random()*100,Math.random()*100);
ctx.stroke();
}
function start() {
setInterval(draw, 100);
}
</script>
</head>
<body onload="start()">
<div id="holder"></div>
</body>
</html>
This issue happens on Webkit even when an image SRC is modified, so I don't get surprised if this happens when handling canvas too.
There is a bug filled on Chrome (that made them filling a bug to Webkit) and we hope this will be fixed soon, as it is making many Chrome extension unusable.
references
http://code.google.com/p/chromium/issues/detail?id=36142
https://bugs.webkit.org/show_bug.cgi?id=23372
Anyway, the suggestions above should mitigate this.
Don't:
Create the <canvas> element with .innerHTML
Create the <canvas> in each Interval
Do:
use var cv = document.createElement('canvas'); cv.setAttribute('height', '250'); // ...
cache the reference of cv at some init point and re-use that!!
<script>
var holder = document.getElementById("holder"),
var cv = document.createElement('canvas');
cv.setAttribute('id', 'cnv');
cv.setAttribute('height', '250');
cv.setAttribute('width', '250');
holder.appendChild(cv);
function draw() {
var ctx = cv.getContext("2d");
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(Math.random()*100,Math.random()*100);
ctx.stroke();
}
function start() {
setInterval(draw, 100);
}
</script>

Categories