cancelAnimationFrame for Animation on Javascript - javascript

Hello I'm trying to create a rectangle that grows from the side of the canvas until it fills the whole canvas, once it has done that shrink back to is original state, the approach I'm taking is using requestAnimationFrame /cancelAnimationFrame for some reason I'm not sure cancelAnimationFrame does not seem to work my code is the following one :
<script>
function grRectangle(){
var canvas = document.getElementById("paper");
var context= canvas.getContext("2d");
//var forpi = Math.PI * 2;
//context.fillStyle = "black";
context.fillRect(0,0,canvas.width,canvas.height);
var posX = 200;
var posY = 100;
var color = 0;
function draw(){
context.fillStyle = 'hsl('+ color++ + ',100%,50%)';
context.beginPath();
context.rect(0,0,posX,posY);
context.fill();
posX = posX + 0.9;
posY = posY + 0.9;
if(posX < canvas.width ){
requestAnimationFrame(draw);
} if (posX >= canvas.width){
posX = posX - 0.9;
posY = posY - 0.9;
cancelAnimationFrame(draw);
}
}
draw();
};
</script>
<body onload= "grRectangle();" >
<h1>Growing Rectangle</h1>
<canvas id = "paper" width="800" height="600">
</canvas>
Any help is kindly appreciatted

It seems to me like the code you wrote doesn't actually need a cancelAnimationFrame. I am not sure what you think it does exactly, but it seems like you misunderstood it.
The cancelAnimationFrame method is used to prevent a previous call to requestAnimationFrame from getting executed, as long as this didn't happen yet. There are really few situations where you need this.
In your case I would put that growth-per-frame constant of 0.9 into a variable. When the rectangle size reaches the upper bound, just change it to -0.9 and it will get smaller again. When it reaches the lower bound, change it again to 0.9 and it will grow again.
You will, however, not see that shrinking, because you aren't erasing your canvas. Every frame is drawn on top of the previous one. You will have to erase your canvas at the beginning of your drawing loop. To do that, move the code which fills the canvas with a black rectangle into the drawing loop (remember to set the fill-style to black).

Related

Simple canvas animation: 50x50 image moving across

I've done this sort of programming before but It was a long while back, and despite trying for a while now, I am unable to get this working. I've tried loads of other similar codes that I've found on the internet but they don't work exactly the way I want it to! I basically want a 155x55 canvas, with a 50x50 image moving across it, simple! Despite how simple it sounds... I'm struggling... I've tried adapting my previous code but that was for bouncing balls and it was a long time ago. I'll appreciate any help. Thanks!
var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");
var speed = 1;
a = new Image();
a.src = "http://www.animated-gifs.eu/category_cartoons/avatars-100x100-cartoons-spongebob/0038.gif";
function frameRate(fps) {
timer = window.setInterval( updateCanvas, 1000/fps );
}
function updateCanvas() {
ctx.fillRect(0,0, myCanvas.width, myCanvas.height);
draw();
}
function draw() {
/* Add code here to randomly add or subtract small values
* from x and y, and then draw a circle centered on (x,y).
*/
var x = 0 + speed;
var y = 20;
if (x > 150) {
x == 1;
}
ctx.beginPath();
ctx.drawImage(a,x,y,100,100);
}
/* Begin animation */
frameRate(25);
Fiddle Link:
https://jsfiddle.net/th6fcdr1/
The problem you have is that your variable x and y are always reset to 0 and 20. Your speed is 1 so your x is always 1.
Since you never update the x position and always reset it to 0. What you could do is to increase the variable speed by 1 at the end of the frame.
speed += 1
At first, you'll have:
x = 0 + 1
then
x = 0 + 2
... and so on.
Then you'll have to check for speed being above 150 and reset speed to 1.
Then I suggest renaming speed by posX which is more accurate. Also, instead of using setInterval you should be using requestAnimationFrame(). And instead of incrementing the posX by 1, you should be incrementing the posX by speed * elapsedTime to get a fluent move and stable speed move which doesn't depend on the framerate.
In the end, you'd have this:
posX += speed * elapsedTime
var x = posX

Edges on arc, using Canvas

I am experimenting with drawing using javascript and the canvas element..my goal now is to draw a circle and gradually increase the opacity; I have this code:
http://codepen.io/anon/pen/zrVvOQ
Which seems to work, but the circle has rough edges; I found I need to clear the canvas each time the frame is redrawn, but the attempts I have made have not quite worked...any suggestions on how to?
window.onload = function draw(){
var frame1 = document.getElementById('frame1');
if (frame1.getContext){
var ctx = frame1.getContext('2d');
var centerX = frame1.width / 2;
var centerY = frame1.height / 2;
var radius = 50;
var alpha = 1.0;
/*call function over and over */
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
var rendergreen = function()
{
var opacityValue = 0;
opacityValue += 0.03;
ctx.fillStyle = 'rgba(68,107,62, ' + opacityValue + ')';
animate();
ctx.arc(50, centerY, radius, 0, 2 * Math.PI, false);
ctx.clip();
ctx.fill();
ctx.closePath;
function animate() {
if (opacityValue < 1) {
opacityValue += 0.3;
} else {
opacityValue = 1;
}
}
requestAnimationFrame(rendergreen);
}
rendergreen();
}
}
You say the circle has "rough edges". That's pixellation and is inherent in using canvas to draw, which is a bit-mapped style of graphics. That means that you essentially can't get higher resolution than a single pixel. Contrast that with svg which is vector-based. An svg image can be magnified a thousand times and still have a smooth edge. I've shown an svg circle next to the canvas circle so that you can see the difference. It becomes much more apparent if you zoom in with your browser. There are pro's and con's to using canvas vs svg, too much to go into here, but it's worth looking into if you're really concerned.
In terms of changing the opacity of the circle, you've got several problems with your approach. With the way you've written it, you're actually not changing the opacity. Instead, you're drawing the same very transparent circle many times over top of each other so that by the end it looks opaque, giving the impression that you are gradually increasing the transparency of a single circle. Notice that you're setting your opacity to zero in each drawing iteration, then incrementing it to 0.05 (note that there are differences in the code in your question versus in the codepen that you linked to...I'm referring to the codepen version), then drawing it (so it will always be drawn at opacity 0.05), then further changing the value of the variable opacityValue which is never used in the drawing. The example below shows a relatively simple example of what I think you were trying to achieve. Note that I've deliberately made the 'clearRect' too small so that you can see how not clearing the canvas each time allows semi-transparent drawings to "pile up". This also allows you to see that the blockiness gets worse if you overlay many semi-transparent images. e.g. Compare the left and right sides of the canvas circle. The part of the circle that is cleared every time ends up looking smoother because of anti-aliasing, but the overlaid images have the smoothing effects of anti-aliasing effectively destroyed.
window.onload = function draw() {
var frame1 = document.getElementById('frame1');
if (frame1.getContext) {
var ctx = frame1.getContext('2d');
var opacityValue = 0;
var render = function() {
ctx.clearRect(0, 0, 80, 80); // deliberately set too small
ctx.beginPath();
opacityValue += 0.01;
ctx.fillStyle = 'rgba(68,107,62, ' + opacityValue + ')';
ctx.arc(60, 60, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath;
requestAnimationFrame(render);
}
render();
}
}
<canvas id="frame1" width="120" height="120"></canvas>
<svg width="120" height="120">
<circle cx="60" cy="60" r="50" fill="#446B3E"></circle>
</svg>

How to increase the resolution of lines in canvas

window.onload=function(){
var c = document.getElementById('canvas'),
ctx = c.getContext('2d'),
x=0, y=0, cnt=1;
for(var i=0;i<(window.innerWidth)/10;i++){
ctx.moveTo(x, y); x+=5;
if(cnt%2){
y=5; cnt++;
ctx.lineTo(x, y);ctx.stroke();
}else{
y=0; cnt++;
ctx.lineTo(x, y);ctx.stroke();
}
}
}
<canvas id="canvas" style="width:100%; height:250px"></canvas>
If you run the above code then the resolution of lines in the zig-zag pattern in the if fine but in here you can see the image the resoultion of this pattern is very poor (please click on this image to view this problem):
what i have tried is that i have changed the condition (window.innerWidth)/10 to (winodw.innerWidth)/4 and x+=5 to x+=2
but what it does is that it makes the line so thick and bad that you don't want to see it.
so, what should i do to increase the resolution of the lines of the pattern?
Just make sure your canvas element is as big as you are displaying it.
i added c.width = windows.innerWidth and also c.heigth = 250 and the resolution looks correct now.
window.onload=function(){
var c = document.getElementById('canvas'),
ctx = c.getContext('2d'),
x=0, y=0, cnt=1;
c.width = window.innerWidth;
c.height = 250;
for(var i=0;i<(window.innerWidth);i++){
ctx.moveTo(x, y); x+=5;
if(cnt%2){
y=5; cnt++;
ctx.lineTo(x, y);ctx.stroke();
}else{
y=0; cnt++;
ctx.lineTo(x, y);ctx.stroke();
}
}
}
<canvas id="canvas" style="width:100%; height:250px"></canvas>
There are a couple of things, but mostly it comes down to this: you are drawing at a width of 100%, which is stretching the default size of a canvas you are drawing in - thats why it blurs. Set your width correctly using javascript and the sharpness increases. The only thing is, a difference of 5 pixels is barely noticeable, so you have to increase your size to something more... average. I have opted for 1/100 of the windows width, but you can turn it into anything.
// For safety, use event listeners and not global window method overwriting.
// It will become useful if you have multiple scripts you want to
// execute only after loading them!
window.addEventListener('DOMContentLoaded', function(){
var c = document.getElementById('canvas'),
ctx = c.getContext('2d'),
x = 0, y = 0;
// Set the correct width and height
c.width = window.innerWidth;
c.height = window.innerWidth / 100;
// Use moveTo once, then keep drawing from your previous lineTo call
ctx.moveTo(x, y);
// You only need your x value here, once we are off screen we can stop drawing and end the for loop!
for(; x < window.innerWidth; x += window.innerWidth / 100){
// Use lineTo to create a path in memory
// You can also see if your y needs to change because y = 0 = falsy
ctx.lineTo(x, (y = y ? 0 : window.innerWidth / 100));
}
// Call stroke() only once!
ctx.stroke();
// And for safety, call closePath() as stroke does not close it.
ctx.closePath();
}, false);
<canvas id="canvas"></canvas>
<!-- Remove all styling from the canvas! Do this computationally -->
maybe you can find your ans here
Full-screen Canvas is low res
basically it summarizes that instead of setting height and width in the css, you should set it via html (inside the canvas element via width and height attr) or via javaScript.
because when doing it in css, you are basically scaling it and thus reducing the resolution, so you have to mention the actual size in html element and not scale it in css.

Transparent Background not working

I'm making a small simple game in HTML and Javascript but I've run into an error. The sprite I've made on the "canvas" is not able to reach the canvas borders (the edge of the game world). After looking at it alot, I deduced it wasn't the code but the fact that the background of the image isn't transparent. But this makes no sense because the image file does have a transparent background.
How can I completely get rid of the background? Or is something in the code causing the sprite to have it's own border?
Image file:
What it looks like when run
http://prntscr.com/4btb32
Code:
// JavaScript Document
var canvasWidth = 800;
var canvasHeight = 600;
$('#gameCanvas').attr('width', canvasWidth);
$('#gameCanvas').attr('height', canvasHeight);
var keysDown = {};
$('body').bind('keydown', function(e){
keysDown[e.which] = true;
});
$('body').bind('keyup', function(e){
keysDown[e.which] = false;
});
var canvas = $('#gameCanvas')[0].getContext('2d');
var FPS = 30;
var image = new Image();
image.src = "ship.png";
var playerX = (canvasWidth/2) - (image.width/2);
var playerY = (canvasHeight/2) - (image.height/2);
setInterval(function() {
update();
draw();
}, 1000/FPS);
function update(){
if(keysDown[37]){
playerX -= 10;
}
if(keysDown[38]){
playerY -= 10;
}
if(keysDown[39]){
playerX += 10;
}
if(keysDown[40]){
playerY += 10;
}
playerX = clamp(playerX, 0, canvasWidth - image.width);
playerY = clamp(playerY, 0, canvasHeight - image.height);
}
function draw() {
canvas.clearRect(0,0, canvasWidth, canvasHeight);
canvas.strokeRect(0, 0, canvasWidth, canvasHeight);
canvas.drawImage(image, playerX, playerY);
}
function clamp(x, min, max){
return x < min ? min : (x > max ? max : x);
}
Thanks,
Ab
Your clamp function is making is so the x and y values are always between 0 and the canvas size minus the image size. This makes it so that your image will never leave the canvas (making the full image always on the canvas), and your image size is actually a bit larger than the ship image. The transparency of the image has nothing to do with the ship leaving the canvas, it has to do with the size. If you want to be able to have the ship leave the canvas, or get right next to the edge then decrease the size of the image to not have a border on it.
Alternatively you could have your clamp function clamp to 0 - image.width and canvasWidth + image.width (or height). This will allow the ship to fully disappear off the canvas.
Whether or not the sprite has a transparent background, the height and width of the image are still being used. you need to create your sprite in a way that the ship fills the entire canvas that you are painting it on.
The image will be as wide and tall as your background... so your ship wont reach the edge because there is still a background on your image that extend beyond your ship.

HTML5 canvas character jump

I try to make an animation of character by reading this tutorial:
http://mrbool.com/html5-canvas-moving-a-character-with-sprites/26239 .
It's quite ease to make the character go left ('go right' is already done). But how to make the character jump (with animation)?
I was thinking about something like this:
case 38:
if (y + dy > HEIGHT){
y += dy
}
break;
...but it just move character up (without animation). Can someone help me? Some code example will be useful.
You get the jumping behavior like this (using the same code on the tutorial)
JSFiddle
var canvas;// the canvas element which will draw on
var ctx;// the "context" of the canvas that will be used (2D or 3D)
var dx = 50;// the rate of change (speed) horizontal object
var x = 30;// horizontal position of the object (with initial value)
var y = 150;// vertical position of the object (with initial value)
var limit = 10; //jump limit
var jump_y = y;
var WIDTH = 1000;// width of the rectangular area
var HEIGHT = 340;// height of the rectangular area
var tile1 = new Image ();// Image to be loaded and drawn on canvas
var posicao = 0;// display the current position of the character
var NUM_POSICOES = 6;// Number of images that make up the movement
var goingDown = false;
var jumping;
function KeyDown(evt){
switch (evt.keyCode) {
case 39: /* Arrow to the right */
if (x + dx < WIDTH){
x += dx;
posicao++;
if(posicao == NUM_POSICOES)
posicao = 1;
Update();
}
break;
case 38:
jumping = setInterval(Jump, 100);
}
}
function Draw() {
ctx.font="20px Georgia";
ctx.beginPath();
ctx.fillStyle = "red";
ctx.beginPath();
ctx.rect(x, y, 10, 10);
ctx.closePath();
ctx.fill();
console.log(posicao);
}
function LimparTela() {
ctx.fillStyle = "rgb(233,233,233)";
ctx.beginPath();
ctx.rect(0, 0, WIDTH, HEIGHT);
ctx.closePath();
ctx.fill();
}
function Update() {
LimparTela();
Draw();
}
var Jump = function(){
if(y > limit && !goingDown){
y-=10;
console.log('jumping: ' + y);
} else{
goingDown = true;
y +=10;
if(y > jump_y){
clearInterval(jumping);
goingDown = false;
}
}
}
function Start() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
return setInterval(Update, 100);
}
window.addEventListener('keydown', KeyDown);
Start();
There's no one right answer to this question, and unless you find a game-design library, there's no simple one, either. Your problem is that you're moving the character instantaneously in response to input, but a jump requires movement over time. You'll have to either find a moving sprites library - I don't have one in particular to recommend, but I'm sure Google has several - or set up something yourself that runs every so many milliseconds and updates the character's position and some sort of velocity variable.
Edit: Looking at that tutorial, the simplest solution that comes to mind is to put your animation code inside of Update(), like so:
function Update() {
LimparTela();
Animate();
Draw();
}
Inside of Animate(), you should keep track of the character's height and vertical momentum. If the momentum is positive, increase the y position a little, otherwise decrease it a little. Either way, reduce momentum a bit. Add something to keep the character from going through the floor, and have the up key set the character's momentum to be positive if he's on the floor.
Note that this is an incredibly bare-bones solution, but for a basic tutorial it'll do the job.

Categories