I'm trying to build a very simple animation function. I'm using this tutorial to build my project:
https://www.youtube.com/watch?v=hUCT4b4wa-8
The result after the button is clicked should be a green box moving across the page from left to right. When the button is clicked, nothing happens and I don't get any console errors.
Here's my fiddle:
https://jsfiddle.net/xkhpmrtu/7/
And here's a snippet of my code:
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<style type="text/css">
canvas {
border: 1px solid #666;
}
</style>
<script type="application/javascript" language="javascript">
function anim(x,y) {
var canvas = document.getElementById('canvas');//reference to canvas element on page
var ctx = canvas.getContext('2d');//establish a 2d context for the canvas element
ctx.save();//save canvas state if required (not required for the tutoriral anaimation, but doesn't hurt the script so it stays for now)
ctx.clearRect(0, 0, 550, 400);//clears the canvas for redrawing the scene.
ctx.fillStyle = "rgba(0,200,0,1)";//coloring the rectangle
ctx.fillRect = (x, 20, 50, 50);//drawing the rectangle
ctx.restore();//this restores the canvas to it's original state when we saved it on (at the time) line 18
x += 5; //increment the x position by some numeric value
var loopTimer = setTimeout('draw('+x+','+y+')', 2000);// setTimeout is a function that
</script>
</head>
<body>
<button onclick="animate(0,0)">Draw</button>
<canvas id="canvas" width="550" height="400"></canvas>
</body>
Any idea what I'm doing wrong?
I just had a look at the tutorial link. I will give if a major thumbs down as it demonstrates how not to animate and how not to do many other things in Javascript.
First the script tag and what is wrong with it
// type and language default to the correct setting for javascrip
// <script type="application/javascript" language="javascript">
<script>
function anim(x,y) {
// get the canvas once. Getting the canvas for each frame of an
// animation will slow everything down. Same for ctx though will not
// create as much of a slowdown it is not needed for each frame
// var canvas = document.getElementById('canvas');
// var ctx = canvas.getContext('2d');
// Dont use save unless you have to. It is not ok to add it if not needed
// ctx.save();
// dont use literal values, canvas may change size
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "rgba(0,200,0,1)";
// this line is wrong should be ctx.fillRect(x, 20, 50, 50). It is correct in the video
ctx.fillRect = (x, 20, 50, 50);//drawing the rectangle
// restore not needed
//ctx.restore();
x += 5; //increment the x position by some numeric value
// creating a string for a timer is bad. It invokes the parser and is slooowwwwww...
// For animations you should avoid setTimeout altogether and use
// requestAnimationFrame
// var loopTimer = setTimeout('draw('+x+','+y+')', 2000);
requestAnimationFrame(draw);
// you were missing the closing curly.
}
</script>
There is lots more wrong with the tut. It can be excused due to it being near 5 years old. You should look for more up todate tutorials as 5 years is forever in computer technology.
Here is how to do it correctly.
// This script should be at the bottom of the page just befor the closing body tag
// If not you need to use the onload event to start the script.
// define a function that starts the animation
function startAnimation() {
animating = true; // flag we are now animating
x = 10;
y = 10;
// animation will start at next frame or restart at next frame if already running
}
// define the animation function
function anim() {
if (animating) { // only draw if animating
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "red"; //coloring the rectangle
ctx.fillRect(x, y, 50, 50); //drawing the rectangle
x += xSpeed;
}
// set animation timer for next frame
requestAnimationFrame(anim);
}
// add a click listener to the start button. It calls the supplied function every time you click the button
startAnimButton.addEventListener("click", startAnimation);
const ctx = canvas.getContext('2d'); // get the 2d rendering context
// set up global variables to do the animation
var x, y, animating;
animating = false; // flag we are not animating
const xSpeed = 50 / 60; // Speed is 50 pixels per second at 60fps
// dont slow the animation down via frame rate
// slow it down by reducing speed.
// You only slow frame rate if the machine
// can not handle the load.
// start the animation loop
requestAnimationFrame(anim);
canvas {
border: 1px solid #666;
}
<!-- don't add events inline -->
<button id="startAnimButton">Draw</button>
<canvas id="canvas" width="512" height="128"></canvas>
Related
For an assignment I need to animate something simple using CSS and JavaScript. I've been able to figure out the CSS but everything I read to make an object fade in using JavaScript just doesn't seem to work with the object I drew in JavaScript. I just wanted to draw a circle in JavaScript and then animate it to fade in in 5 seconds.
Here is the basic Code I have so far:
HTML:
<body onload="draw();">
<canvas id="circle" width="450" height="450"></canvas>
</body>
JavaScript:
<script>
function draw()
{
var canvas = document.getElementById('circle');
if (canvas.getContext)
{
var ctx = canvas.getContext('2d');
var X = canvas.width / 2;
var Y = canvas.height / 2;
var R = 45;
ctx.beginPath();
ctx.arc(X, Y, R, 0, 2 * Math.PI, false);
ctx.lineWidth = 3;
ctx.strokeStyle = '#645862';
ctx.stroke();
}
}
</script>
As you can see I only have the circle part of the code. I have tried multiple versions of different fade in animations but I just can't quite get them to work. I'm not very good at JavaScript. It's the one language I have trouble understanding for some reason. I'm also really sick right now otherwise I would be troubleshooting more reasons as to why it isn't working.
To understand how a canvas works, you need to know that it's just a place to display something, and initially it doesn't do anything on its own. You've drawn the circle once, which is enough to display the circle, but not to animate it in any way.
If we want to move the circle in any direction, we must clear the canvas of the already drawn circle and draw the circle in a different place, changing its coordinates by N pixels. The same goes for transparency. We must change the transparency of the color of the circle in each frame, and draw the circle again and again.
This is how 2D and 3D canvas works, as well as all video games - they draw scenes 60 times per second, changing some values along the way, such as coordinates, values, color, transparency, height and width.
In order for this to work, we need two additional variables, opacity and the direction (fading) in which the opacity changes, to know whether the circle appears or disappears.
Also important is the recursive call to our draw() function. We will call it constantly, and we will constantly redraw our image on the canvas.
I also want to point out some conceptual mistakes in your code.
Dont use "var", it is deprecated. Use "let","const". Also don`t repeat "var","var","var" in every line. Use commas.
Dont use onload,onclick and others HTML on-attributes. They are only suitable for educational purposes, not for real work. Use script tag and document event listeners.
Dont name canvas id like "circle","box" etc. It is not a circle and a box, it is a canvas.
Use document.querySelector instead of document.getElementById. It is more modern
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas opacity animation</title>
</head>
<body>
<canvas id="canvas" width="450" height="450"></canvas>
<script>
document.addEventListener("DOMContentLoaded",()=>{
const OPACITY_SPEED = .005
let canvas = document.querySelector('canvas'),
context = canvas.getContext('2d'),
opacity = 1,
fading = true
draw()
function draw(){
// clear canvas for redrawing (important!)
context.clearRect(0, 0, canvas.width, canvas.height);
let circleX = canvas.width/2,
circleY = canvas.height/2,
radius = 45
// changing circle opacity
if(fading) opacity -= OPACITY_SPEED
else opacity += OPACITY_SPEED
// check if we need to fade in or to fade out
if(opacity >= 1) fading = true
if(opacity <= 0) fading = false
// draw circle
context.beginPath();
context.arc(circleX, circleY, radius, 0, 2 * Math.PI, false);
context.lineWidth = 3;
context.strokeStyle = `rgba(0, 0, 0, ${opacity})`;
context.stroke();
// call draw() again and again
requestAnimationFrame(draw)
}
})
</script>
</body>
</html>
I'm trying to run a simple animation each time when user clicks on canvas. I'm sure I did something wrong as the animation doesn't even fire at times. I have never used canvas animation before and have difficulty understanding how it should be constructed within a for loop.
fgCanvas.on('mousedown', function(e) {
var cX = Math.round((e.offsetX - m) / gS),
cY = Math.round((e.offsetY - m) / gS);
clickDot({x:cX,y:cY});
});
function clickDot(data) {
for (var i = 1; i < 100; i++) {
fctx.clearRect(0, 0, pW, pH);
fctx.beginPath();
fctx.arc(data.x * gS + m, data.y * gS + m, i/10, 0, Math.PI * 2);
fctx.strokeStyle = 'rgba(255,255,255,' + i/10 + ')';
fctx.stroke();
}
requestAnimationFrame(clickDot);
}
Full code is here: http://jsfiddle.net/3Nk4A/
The other question is how can slow down the animation or add some easing, so the rings are drawn slower towards the end when they disappear?
You can use requestAnimationFrame plus easing functions to create your desired effect:
A Demo: http://jsfiddle.net/m1erickson/cevGf/
requestAnimationFrame creates an animation loop by itself--so there's no need to use a for-loop inside requestAnimationFrame's animation loop.
In its simplest form, this requestAnimationFrame loop will animate your circle:
var counter=1;
animate();
function animate(){
// stop the animation after it has run 100 times
if(counter>100){return;}
// there's more animating to do, so request another loop
requestAnimationFrame(animate);
// calc the circle radius
var radius=counter/10;
// draw your circle
}
To get the animation to speed-up or slow-down, you can use easings. Easings change a value (like your radius) over time, but they change that value unevenly. Easings speed-up and slow-down over the duration of the animation.
Robert Penner made a great set of easing algorithms. Dan Rogers coded them in javascript:
https://github.com/danro/jquery-easing/blob/master/jquery.easing.js
You can see working examples of his easing functions here:
http://easings.net/
Here's annotated code using requestAnimationFrame plus easings to animate your circles.
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
// set the context styles
ctx.lineWidth=1;
ctx.strokeStyle="gold";
ctx.fillStyle="#888";
// variables used to draw & animate the ring
var PI2=Math.PI*2;
var ringX,ringY,ringRadius,ingCounter,ringCounterVelocity;
// fill the canvas with a background color
ctx.fillRect(0,0,canvas.width,canvas.height);
// tell handleMouseDown to handle all mousedown events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
// set the ring variables and start the animation
function ring(x,y){
ringX=x;
ringY=y;
ringRadius=0;
ringCounter=0;
ringCounterVelocity=4;
requestAnimationFrame(animate);
}
// the animation loop
function animate(){
// return if the animation is complete
if(ringCounter>200){return;}
// otherwise request another animation loop
requestAnimationFrame(animate);
// ringCounter<100 means the ring is expanding
// ringCounter>=100 means the ring is shrinking
if(ringCounter<100){
// expand the ring using easeInCubic easing
ringRadius=easeInCubic(ringCounter,0,15,100);
}else{
// shrink the ring using easeOutCubic easing
ringRadius=easeOutCubic(ringCounter-100,15,-15,100);
}
// draw the ring at the radius set using the easing functions
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
ctx.arc(ringX,ringY,ringRadius,0,PI2);
ctx.closePath();
ctx.stroke();
// increment the ringCounter for the next loop
ringCounter+=ringCounterVelocity;
}
// Robert Penner's easing functions coded by Dan Rogers
//
// https://github.com/danro/jquery-easing/blob/master/jquery.easing.js
//
// now=elapsed time,
// startValue=value at start of easing,
// deltaValue=amount the value will change during the easing,
// duration=total time for easing
function easeInCubic(now, startValue, deltaValue, duration) {
return deltaValue*(now/=duration)*now*now + startValue;
}
function easeOutCubic(now, startValue, deltaValue, duration) {
return deltaValue*((now=now/duration-1)*now*now + 1) + startValue;
}
// handle mousedown events
function handleMouseDown(e){
// tell the browser we'll handle this event
e.preventDefault();
e.stopPropagation();
// calc the mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// animate a ring at the mouse position
ring(mouseX,mouseY);
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Click in the canvas to draw animated circle with easings.</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
i have created a grass field which is a combination of several small 60x36 images.a grass object is introduced and then drawn on the canvas.now i want to give it motion .the continuous scrolling effect .i made a code for it and it isn't working( the images (the grass field)are not scrolling along the width of the canvas which is the goal of this script).i haven't work much with oop in js. a little discussion on the mistakes i have done will be great
(the image i have used is added to the post)
<html>
<body>
<canvas id="mycanvas"></canvas>
<script>
function makeit(){
var canvas=document.getElementById("mycanvas");
var ctx=canvas.getContext('2d');
var height=500-36;
var xpos=[];
var img=new Image();
img.src="grass.jpg";
drawcanvas();
function drawcanvas(){
canvas.width=600;
canvas.height=500;
canvas.style.border="1px solid black";
}
for(i=0;i<10;i++){
xpos.push(i*60);
}
var grass=function(x,y){
this.x=x;
this.y=y;
this.img=img;
ctx.drawImage(this.img,this.x,this.y);
}
grass.prototype.motion=function(){
for(i=0;i<xpos.length;i++){
xpos[i]--;
if(xpos[i]<=-60){
xpos[i]=canvas.width;
}
ctx.drawImage(this.img,this.x,this.y);
}
}
for(i=0;i<xpos.length;i++){
var grass1=new grass(xpos[i],height);
}
var m=setTimeout(function(){
for(i=0;i<xpos.length;i++){
grass1.motion();
}
},1000);
}
window.onload=makeit;
</script>
</body>
</html>
actual canvas after drawing all the images
In essence, all you need is to create an image pattern then translate and draw it to screen.
An example assuming image has been loaded:
var ph = img.height; // pattern height
var w = canvas.width; // width of canvas/scoll area
var h = canvas.height; // used to calculate y pos.
var x = 0; // scroll position
ctx.fillStyle = ctx.createPattern(img, 'repeat-x'); // pattern
Then in the loop scrolling the grass:
function scroll() {
ctx.translate(x, h - ph); // translate to next position
ctx.fillRect(-x, 0, w, ph); // fill rectangle (fillstyle = pattern)
ctx.translate(-x, -(h -ph)); // translate back for other operations
x--; // scroll speed (here 1 pixel / frame)
requestAnimationFrame(scroll); // loop
}
FIDDLE
Pattern fills are anchored to the coordinate system which is why the translate is necessary. As we translate we also compensate for it using draw position in the opposite direction. This will make the pattern be filled into the same position but at a variable offset which creates the animation effect.
Just note that if you change fillStyle you need to store the pattern in a variable and reinitialize the fill style. If the loop is long-running also limit x so it doesn't overflow. This can be done using w as a condition (or modulo) to reset x to 0.
I have a multipage site that the main home page simply has a single image logo on it. When this page is visited I need the image to move around like a screensaver. When any touch is registered the page will go to a second page. That second page has other data and info but nothing is touched for ten minutes it will default and go back to the entry page and the screensaver.
So, two things.
One, move an image around like a screensaver using jQuery.
Two, the other page has a timeout of ten minutes if no touch is registered that knocks the person back to the first page that has the screensaver.
This is an HTML5 page so if jQuery will not work, something using HTML5 and Canvas might.
This is for a site that will be used as a kiosk and a touch screen.
On the screensaver page:
You can use an html canvas that floats your logo image around the screen. Here's a link:
http://jsfiddle.net/m1erickson/E3Qda/
On the second page:
How about starting a 10 minute setTimeout when the page first loads.
If the user triggers a touch event before 10 minutes, (1) clearTimeout the original timeout (2) setTimeout for a new 10 minutes.
Here's example code for the screensaver page:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
img{border:1px solid purple;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var ball;
var ballX=60;
var ballY=150;
var ballRadius=50;
var image=new Image();
image.onload=function(){
// resize the image to fit inside the ball's radius
var c=document.createElement("canvas");
var cctx=c.getContext("2d");
// calc the max side length of a square that fits the ball
var maxSide=Math.sqrt(2*ballRadius*ballRadius);
// calc the max rect size that fits in the ball
var iw=image.width;
var ih=image.height;
var maxW,maxH;
if(iw>=ih){
maxW=maxSide;
maxH=maxSide*iw/ih;
}else{
maxW=maxSide*ih/iw;
maxH=maxSide;
}
// size the temp canvas to the max rect size
c.width=maxW;
c.height=maxH;
// draw the image to the temp canvas
cctx.drawImage(image,0,0,iw,ih,0,0,maxW,maxH);
var ballimg=new Image();
ballimg.onload=function(){
ball={x:ballX,y:ballY,r:ballRadius,img:ballimg,imgSide:maxSide,directionX:1,directionY:1};
drawBall(ball);
}
ballimg.src=c.toDataURL();
requestAnimationFrame(animate);
}
image.src="ship.png";
function drawBall(ball){
// clip image inside ball
ctx.save();
ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2,false);
ctx.closePath();
ctx.clip();
ctx.fillStyle="white";
ctx.fillRect(ball.x-ball.r,ball.y-ball.r,ball.r*2,ball.r*2);
ctx.drawImage(ball.img, ball.x-ball.imgSide/2,ball.y-ball.imgSide/2);
ctx.restore();
ctx.beginPath();
ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2,false);
ctx.closePath();
ctx.strokeStyle="lightgray";
ctx.lineWidth=2;
ctx.stroke();
ctx.beginPath();
ctx.arc(ball.x,ball.y,ball.r+2,0,Math.PI*2,false);
ctx.closePath();
ctx.strokeStyle="gray";
ctx.lineWidth=2;
ctx.stroke();
}
function animate(time) {
requestAnimationFrame(animate);
// move with collision detection
ball.x+=ball.directionX;
if(ball.x-ball.r<0 || ball.x+ball.r>canvas.width){
ball.directionX*=-1;
ball.x+=ball.directionX;
}
ball.y+=ball.directionY;
if(ball.y-ball.r<0 || ball.y+ball.r>canvas.height){
ball.directionY*=-1;
ball.y+=ball.directionY;
}
// Draw
ctx.clearRect(0,0,canvas.width,canvas.height);
drawBall(ball);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>
I have been trying to set up a javascript game loop and I have two issues I am running into. I find that in chrome when I lose focus of the browser window and then click back the animation I have running does this weird "catch up" thing where it quickly runs through the frames it should of been rendering in the background. I also have noticed that the animation is blury when moving at the current speed I have it at yet other people have been able to get their canvas drawings to move quickly and still look crisp. I know their seems to be a lot out about this but I cant make sense of what my issue really is. I thought this was a recommended way to create a game loop.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Frame Test</title>
<link href="/css/bootstrap.css" media="all" rel="stylesheet" type="text/css" />
<script language="javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"
type="text/javascript">
</script>
<script language="javascript" src="js/jquery.hotkeys.js" type="text/javascript"></script>
<script language="javascript" src="js/key_status.js" type="text/javascript"></script>
<script language="javascript" src="js/util.js" type="text/javascript"></script>
<script language="javascript" src="js/sprite.js" type="text/javascript"></script>
</head>
<body>
<button id="button1">
Toggle Loop</button>
<h1 id="frameCount">
Game Loop Test</h1>
<canvas id="gameCanvas" width="800" height="500">
<p>Your browser doesn't support canvas.</p>
</canvas>
<script type='text/javascript'>
// demo code used for playing around with javascript-canvas animations
var frameCount = 0;
var drawingCanvas = document.getElementById('gameCanvas');
// Check the element is in the DOM and the browser supports canvas
if (drawingCanvas.getContext) {
var context = drawingCanvas.getContext('2d');
var x = 100;
var y = 100;
var right = true;
context.strokeStyle = "#000000";
context.fillStyle = "Green";
context.beginPath();
context.arc(x, y, 50, 0, Math.PI * 2, true);
context.closePath();
context.stroke();
context.fill();
}
function Timer(settings) {
this.settings = settings;
this.timer = null;
this.on = false; //Bool that represents if the timer is running or stoped
this.fps = settings.fps || 30; //Target frames per second value
this.interval = Math.floor(1000 / 30);
this.timeInit = null; //Initial time taken when start is called
return this;
}
Timer.prototype =
{
run: function () {
var $this = this;
this.settings.run();
this.timeInit += this.interval;
this.timer = setTimeout(
function () { $this.run() },
this.timeInit - (new Date).getTime()
);
},
start: function () {
if (this.timer == null) {
this.timeInit = (new Date).getTime();
this.run();
this.on = true;
}
},
stop: function () {
clearTimeout(this.timer);
this.timer = null;
this.on = false;
},
toggle: function () {
if (this.on) { this.stop(); }
else { this.start(); }
}
}
var timer = new Timer({
fps: 30,
run: function () {
//---------------------------------------------run game code here------------------------------------------------------
//Currently Chorme is playing a catch up game with the frames to be drawn when the user leaves the browser window and then returns
//A simple canvas animation is drawn here to try and figure out how to solve this issue. (Most likely related to the timer implimentation)
//Once figured out probably the only code in this loop should be something like
//updateGameLogic();
//updateGameCanvas();
frameCount++;
if (drawingCanvas.getContext) {
// Initaliase a 2-dimensional drawing context
//Canvas commands go here
context.clearRect((x - 52), 48, (x + 52), 104);
// Create the yellow face
context.strokeStyle = "#000000";
context.fillStyle = "Green";
context.beginPath();
if (right) {
x = x + 6;
if (x > 500)
right = false;
} else {
x = x - 6;
if (x < 100)
right = true;
}
context.arc(x, 100, 50, 0, Math.PI * 2, true);
context.closePath();
context.stroke();
context.fill();
}
document.getElementById("frameCount").innerHTML = frameCount;
//---------------------------------------------end of game loop--------------------------------------------------------
}
});
document.getElementById("button1").onclick = function () { timer.toggle(); };
frameCount++;
document.getElementById("frameCount").innerHTML = frameCount;
</script>
</body>
</html>
-------------Update ---------------------
I have used requestanimation frame and that has solved the frame rate problam but I still get weird ghosting/bluring when the animation is running. any idea how I should be drawing this thing?
Okay, so part of your problem is that when you switch tabs, Chrome throttles down its performance.
Basically, when you leave, Chrome slows all of the calculations on the page to 1 or 2 fps (battery-saver, and more performance for the current tab).
Using setTimeout in the way that you have is basically scheduling all of these calls, which sit and wait for the user to come back (or at most are only running at 1fps).
When the user comes back, you've got hundreds of these stacked calls, waiting to be handled, and because they've all been scheduled earlier, they've all passed their "wait" time, so they're all going to execute as fast as possible (fast-forward), until the stack is emptied to where you have to start waiting 32ms for the next call.
A solution to this is to stop the timer when someone leaves -- pause the game.
On some browsers which support canvas games in meaningful ways, there is also support for a PageVisibility API. You should look into it.
For other browsers, it'll be less simple, but you can tie to a blur event on the window for example.
Just be sure that when you restart, you also clear your interval for your updates.
Ultimately, I'd suggest moving over to `requestAnimationFrame, because it will intelligently handle frame rate, and also handle the throttling you see, due to the stacked calls, but your timer looks like a decent substitute for browsers which don't yet have it.
As for blurriness, that needs more insight.
Reasons off the top of my head, if you're talking about images, are either that your canvas' width/height are being set in CSS, somewhere, or your sprites aren't being used at a 1:1 scale from the image they're pulled from.
It can also come down to sub-pixel positioning of your images, or rotation.
Hope that helps a little.
...actually, after looking at your code again, try removing "width" and "height" from your canvas in HTML, and instead, change canvas.width = 800; canvas.height = 500; in JS, and see if that helps any.