here is my site:
I'm trying to get the CD to slowly stop spinning or slowly start up again when I click a button or press the spacebar, but setTimeout() hasn't worked for me.
Thanks.
Below is the js in my body.
var diskCenter = [480, 480];
var disk = new Image;
disk.src = 'disk.jpg';
window.onload = function () {
var ang = 0;
var c = document.getElementsByTagName('canvas')[0];
var ctx = c.getContext('2d');
setInterval(function () {
ctx.save();
ctx.clearRect(0, 0, c.width, c.height);
ctx.translate(c.width, 0);
ctx.rotate(Math.PI / 180 * (ang += 5));
ctx.drawImage(disk, -diskCenter[0], -diskCenter[1]);
ctx.restore();
}, 25);
};
Here's the code I used to get it to work (I have two buttons, one that slows down the animation (and reverses it) and one that speeds it up:
(function ($) {
var ang = 0;
var speed = 5;
var minSpeed = -10;
var maxSpeed = 10;
var c = $('#discCanvas')[0];
var ctx = c.getContext('2d');
var diskCenter = [480, 480];
var disk = new Image;
disk.src = 'http://swellgarfo.com/9/disk.jpg';
$(function () {
setInterval(function () {
ctx.save();
ctx.clearRect(0, 0, c.width, c.height);
ctx.translate(c.width, 0);
ctx.rotate(Math.PI / 180 * (ang += speed));
ctx.drawImage(disk, -diskCenter[0], -diskCenter[1]);
ctx.restore();
}, 25);
});
$('#slowButton').on('click', function () {
speed = Math.max(minSpeed, speed - 1);
});
$('#fastButton').on('click', function () {
speed = Math.min(maxSpeed, speed + 1);
});
})(jQuery);
You will have to use clearInterval() function for stopping your CD. Since you have rotated the CD using setInterval().
Here you go.
HTML :
Include a link :
Stop
Javascript : I am using Jquery here.
So include :
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
var my = setInterval(function(){
ctx.save();
ctx.clearRect( 0 , 0, c.width, c.height );
ctx.translate( c.width , 0 );
ctx.rotate(Math.PI / 180 * (ang += 5));
ctx.drawImage( disk, -diskCenter[0], -diskCenter[1] );
ctx.restore();
},25);
$(document).ready(function(){
$("#stop").click(function(e){
e.preventDefault();
window.clearInterval(my);
});
});
I believe it will make sense.
Related
I have a moving object and so it doesn't leave a trail behind I am using the clearRect(). However I can't remove everything in the canvas because that would remove my other object (which is the goal for the player to collect.)
var playerX = 350;
var playerY = 450;
function coin(posX, posY, width, height) {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'gold';
ctx.fillRect(posX, posY, width, height); //this is what I don't want to clear
}
function player() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.fillStyle = "gray";
ctx.fillRect(playerX, playerY, 50, 50);
ctx.closePath();
}
function random(min, max) {
var x = Math.floor(Math.random() * max) + min;
return x;
}
function moveLeft() {
playerX -= 5;
player();
window.requestAnimationFrame(moveLeft);
}
function moveRight() {
playerX += 5;
player();
window.requestAnimationFrame(moveLeft);
}
player();
coin(random(5, 650), random(5, 250), 50, 50);
</script>
Any help would be greatly appreciated.
One thing you can try is make a single animation function that would call itself recursively.
function animate(){
canvas.clearRect()
// draw everything here
window.requestanimationframe(animate)
}
animate()
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 am trying to create a template for initiating as many waterfall objects as I wish without having to create a new canvas for each of them. I want two waterfalls with different colors but it doesn't work. I can't figure out why and I'm on it since a few hours. How can I make both red and blue waterfalls appear where the first has a lower z index than the last instantiation?
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var w = canvas.width = window.innerWidth;
var h = canvas.height = window.innerHeight;
function waterfall(color) {
var self = this;
this.color = color;
this.water = [];
this.Construct = function(y, vel, acc) {
this.y = y;
this.vel = vel;
this.acc = acc;
}
for(var i = 0; i < 1000; i++) {
this.water.push(new this.Construct(Math.random() * 65, 0.1 + Math.random() * 4.3, 0));
}
this.flow = function(color) {
ctx.clearRect(0, 0, w, h);
for(var i = 0; i < this.water.length; i++) {
this.water[i].vel += this.water[i].acc;
this.water[i].y += this.water[i].vel;
ctx.beginPath();
ctx.arc(0 + i * 0.5, this.water[i].y, 2, 0, Math.PI * 2, false);
ctx.fillStyle = this.color;
ctx.fill();
ctx.closePath();
}
for(var i = 0; i < this.water.length; i++) {
if(this.water[i].y > window.innerHeight) {
this.water[i].y = 0;
}
}
requestAnimationFrame(function() {
self.flow.call(self);
});
}
this.flow(this.color)
}
new waterfall("blue");
new waterfall("red");
Here's my working code: https://jsfiddle.net/testopia/d9jb08xb/5/
and here again my intention to create two separate waterfalls but this time with the prototype inheritance:
https://jsfiddle.net/testopia/d9jb08xb/8/
I do prefer the latter but I just cant get either working.
The problem is that you are clearing the canvas in each waterfall. One is overpainting the other. You can immediately see that by commenting out the line
ctx.clearRect(0, 0, w, h);
Of course the water smears that way.
You have to manage your waterfalls in a way that in each animation frame you first clear the canvas then let them paint all.
Here is a quick attempt using a master flow_all() function:
https://jsfiddle.net/kpomzs83/
Simply move this line...
ctx.clearRect(0, 0, w, h);
... to here...
requestAnimationFrame(function() {
ctx.clearRect(0, 0, w, h); // ensure that w and h are available here.
self.flow.call(self);
});
This ensures that you do not clear the canvas before the 2nd waterfall is drawn. This clears the canvas, then draws the two waterfalls. Make sure you've added them to your water array, of course.
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();
};
I have this animation of a semicircle being drawn, and I basically want to copy it, and move the copy down 60px then add a delay of a second to the new one, So that it draws a "B"
html
<canvas id="thecanvas"></canvas>
script
var can = document.getElementById('thecanvas');
ctx = can.getContext('2d');
can.width = window.innerWidth;
can.height = window.innerHeight;
window.drawCircle = function (x, y) {
segments = 90, /* how many segments will be drawn in the space */
currentSegment = 0,
toRadians = function (deg) {
return (Math.PI / 180) * deg;
},
getTick = function (num) {
var tick = toRadians(180) / segments; /*360=full, 180=semi, 90=quarter... */
return tick * num;
},
segment = function (end) {
end = end || getTick(currentSegment);
ctx.clearRect(0, 0, can.width, can.height);
ctx.beginPath();
ctx.arc(x, y, 60, (1.5 * Math.PI), end + (1.5 * Math.PI), false);
ctx.stroke();
ctx.closePath();
};
ctx.lineWidth = 5;
ctx.strokeStyle = 'rgba(0,0,0,0.5)';
setTimeout(function render() {
segment(getTick(currentSegment));
currentSegment += 1;
if (currentSegment < segments) {
setTimeout(render, 5);
} else {
currentTick = 0;
}
}, 250);
};
drawCircle(100, 100);
Here is a fiddle http://jsfiddle.net/zhirkovski/bJqdN/
first you can put the setTimeout function outside of your drawCircle method.
Then you have at least 2 options :
to create an "endDraw" Event which will be dispatched at the end of 1 draw. When this event is handle, just call again the drawCircle method. To achieve this, of course you need a main method to call the first drawCircle.
To make a better solution, you can describe a workflow of calls. ie describe a list of method to call and for each of them the start frame:
var workflow = [{method:"drawCircle", frame:0, x:100, y:100}, //the first half circle at the frame 0, x=100, y=100
{method:"drawCircle", frame:1000, x:100, y:190}]; //the second half circle starting at frame 1000, x=100, y=190
The your main timer will just be configured to use this array to know what call to do