I was making a dice gamein Javascript.
Someone told me to break that problem into many functions and create each app for each function.
So, I am now breaking the whole dice game into various functions such as drawing circles etc.
So, i like to create a circle (The dots on the dice), and for that; i used the initial source code and kept the useful code that helps me to draw an arc, ... but that is not working. Can anyone figure out why?
I think I missed some values to pass in the function, but I don't know if it is the problem?
I have tried to pass values inside the draw1() but that is not working
var cwidth = 400;
var cheight = 300;
var dicex = 50;
var dicey = 50;
var dicewidth = 100;
var diceheight = 100;
var dotrad = 6;
var ctx;
function init() {
draw1();
}
function draw1() {
var dotx;
var doty;
ctx.beginPath();
dotx = dicex + 0.5 * dicewidth;
doty = dicey + 0.5 * diceheight;
ctx.arc(dotx, doty, dotrad, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
init();
I want the same program to make a small circle
You had a few problems with your initial code, mostly down to variables being undefined. When you declare a variable, it's only defined if you give it a value. That means that code such as:
var ctx;
Creates a variable called ctx, but its value is undefined. This means that when you try and do things like
ctx.beginPath();
You'll get an error, because undefined doesn't have a property beginPath.
What you need to do in order to fix this is initialise variables as you declare them. In fact, it's rarely a good idea to define a variable without initialising it.
I've added a function here to create a canvas, and you can then use that canvas object to initialise your ctx variable. Here's how that might look:
var cwidth = 400;
var cheight = 300;
var dicex = 50;
var dicey = 50;
var dicewidth = 100;
var diceheight = 100;
var dotrad = 6;
function init() {
draw1();
}
function addCanvas(width, height) {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
document.body.appendChild(canvas);
return canvas;
}
function draw1() {
var dotx;
var doty;
var canvas = addCanvas(cwidth, cheight)
var ctx = canvas.getContext("2d");
ctx.beginPath();
dotx = dicex + 0.5 * dicewidth;
doty = dicey + 0.5 * diceheight;
ctx.arc(dotx, doty, dotrad, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
init();
<html>
<head>
<title>die</title>
</head>
<body onLoad="draw1()">
<canvas id="canvas"width="400"height="300" style="border:1px solid #000000;">
nope unsp browser
</canvas>
<script>
var cwidth = 400;
var cheight = 300;
var dicex = 50;
var dicey = 50;
var dicewidth = 100;
var diceheight = 100;
var dotrad = 6;
var c = document.getElementById('canvas');
var ctx = c.getContext('2d');;
function draw1() {
var dotx;
var doty;
ctx.beginPath();
dotx = dicex + 0.5 * dicewidth;
doty = dicey + 0.5 * diceheight;
ctx.arc(dotx, doty, dotrad, 0, Math.PI * 2, true);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
</script>
</body>
</html>
Related
Image of the bug is appearing only at one place i.e. x = 0,y = 0.
var canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var c = canvas.getContext('2d');
var bugSmashed = 0;
//rendering background image
function renderImage()
{
var backImage = new Image();
backImage.src = "jungle.jpg"
backImage.onload = function(){
c.drawImage(backImage,0,0,canvas.width,canvas.height)}
}
renderImage();
//Making a bug
class Bug {
constructor(x,y){
this.x = x;
this.y = y;
}
renderBug(){
var bugImage = new Image();
bugImage.src = "bug.png";
bugImage.onload = function(){
c.drawImage(bugImage,this.x,this.y,65,65)}}
}
Trying to make the bug appear randomly on the canvas
var interval = setInterval(function(){
var x = 32+Math.random()*(canvas.width-64);
var y = 32+Math.random()*(canvas.height-64);
var aBug = new Bug(x,y);
aBug.renderBug();}, 2000);
I am sure I am missing something. Any help is appreciated. Thanks
I found your problem: this changes its meaning inside a function. So when you use:
function(){c.drawImage(bugImage,this.x,this.y,65,65)}
this no longer refers to aBug! (It will instead refer to the global Window object.) You can use fat-arrow syntax instead (which preserves this):
() => c.drawImage(bugImage,this.x,this.y,65,65)
Another really ugly way which I discourage you from using is by creating a new reference to this, and then using that reference in your function:
let that = this;
function(){ c.drawImage(bugImage, that.x, that.y, 65, 65); };
Or you can simplify your code to have it gloss over onload logic, allowing you to avoid wrapping c.drawImage in a function in the first place (note the square which appears is a publicly addressable image):
var canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var c = canvas.getContext('2d');
//Making a bug
let bugImg = new Image();
bugImg.src = "https://th.bing.com/th/id/OIP.pXD0MAw4LeAcVrt3qRiEfwAAAA?pid=ImgDet&rs=1";
class Bug {
constructor(x,y){
this.x = x;
this.y = y;
}
renderBug(){
c.drawImage(bugImg, this.x, this.y, 65, 65);
}
}
var interval = setInterval(function(){
var x = 32 + Math.random()* (canvas.width - 64);
var y = 32 + Math.random()* (canvas.height - 64);
var aBug = new Bug(x, y);
aBug.renderBug();
}, 500);
<canvas id="canvas" width="100" height="100"></canvas>
What I'm trying to accomplish is simply to redraw some stuff on my canvas after it's resized. My problem is that after the canvas resizes, nothing seems to appearing on it. I tried to put some simple code for drawing a rectangle inside the resizing handler as well, and what I noticed is that the rectangle appears during the window resizing and afterwards the canvas is left blank. Below is my code.
var canvass = document.getElementById('zipper-canvas');
var ctx = canvass.getContext('2d');
var repetitions;
var firstRowX = 0; var firstRowY ;
var secondRowX = 5; var secondRowY ;
$(function() {
canvass.width = window.innerWidth;
repetitions = canvass.width / 10;
canvass.height = 30;
ctx = canvass.getContext('2d');
firstRowY = canvass.height / 2 - 3;
secondRowY = canvass.height / 2 + 1;
redraw();
//resize the canvass to fill browser window dynamically
window.addEventListener('resize', resizecanvass, false);
//for some reason i cannot draw on the canvas after it was resized
function resizecanvass() {
canvass.width = window.innerWidth;
repetitions = canvass.width / 10;
canvass.height = 30;
ctx = canvass.getContext('2d');
firstRowY = canvass.height / 2 - 3;
secondRowY = canvass.height / 2 + 1;
/**
* Your drawings need to be inside this function otherwise they will be reset when
* you resize the browser window and the canvass goes will be cleared.
*/
redraw();
}
function redraw() {
canvass = document.getElementById("zipper-canvas");
ctx = canvass.getContext('2d');
ctx.clearRect(0, 0, canvass.width, canvass.height);
console.log(repetitions);
for (var r = 0; r < repetitions; r++) {
ctx.beginPath();
ctx.rect(firstRowX, firstRowY, 5, 5);
ctx.fillStyle = "#edeeef";
ctx.fill();
ctx.closePath();
firstRowX = firstRowX + 10;
}
for (var r2 = 0; r2 < repetitions; r2++) {
ctx.beginPath();
ctx.rect(secondRowX, secondRowY, 5, 5);
ctx.fillStyle = "#a2a3a5";
ctx.fill();
ctx.closePath();
secondRowX = secondRowX + 10;
}
}
});
The problem is that you don't reset your firstRowX and secondRowX variables, so you end up drawing outside the canvas. I fixed that and also moved variable definitions where they belong.
var canvass = document.getElementById('zipper-canvas');
// Could be const
var firstRowX = 0;
var secondRowX = 5;
// Set the correct size on load
resizecanvass();
//resize the canvass to fill browser window dynamically
window.addEventListener('resize', resizecanvass, false);
//for some reason i cannot draw on the canvas after it was resized
function resizecanvass() {
canvass.width = window.innerWidth;
canvass.height = 30;
/**
* Your drawings need to be inside this function otherwise they will be reset when
* you resize the browser window and the canvass goes will be cleared.
*/
redraw();
}
function redraw() {
var ctx = canvass.getContext('2d');
ctx.clearRect(0, 0, canvass.width, canvass.height);
var repetitions = canvass.width / 10;
var firstRowY = canvass.height / 2 - 3;
var secondRowY = canvass.height / 2 + 1;
for (var r = 0; r < repetitions; r++) {
ctx.beginPath();
ctx.rect(firstRowX + r*10, firstRowY, 5, 5);
ctx.fillStyle = "#edeeef";
ctx.fill();
ctx.closePath();
}
for (var r2 = 0; r2 < repetitions; r2++) {
ctx.beginPath();
ctx.rect(secondRowX + r2*10, secondRowY, 5, 5);
ctx.fillStyle = "#a2a3a5";
ctx.fill();
ctx.closePath();
}
}
canvas {
outline:1px solid black;
}
body, html, canvas {
margin: 0px;padding:0px;
}
<canvas id='zipper-canvas'></canvas>
Here's a JSFiddle where you can test the resizing behavior:
https://jsfiddle.net/Darker/noxd4x64/1/
Note that the same effect could be achieved using CSS background without any programming.
I am working on drawing moving rectangles on my canvas. I made a template function for the test purpose and it works, but since i want to draw more of the rectangles with same animation effect I have to make this template function comes to the constructor, getContextand now the problem occurs:
the template function:
ctx = getContext('2d');
var boxHeight = canvas.height/40;
var boxWidth = canvas.width/20;
function drawBox(){
var x = 20;
var y = canvas.height;
var w = boxWidth;
var h = boxHeight;
var timer = 0;
var ladder = Math.floor(Math.random()*((canvas.height*0.5)/boxHeight)) + 1;
for(var i = 0; i < ladder; i++){
ctx.fillStyle = 'hsl('+Math.abs(Math.sin(timer) * 255)+', 40%, 50%)';
ctx.fillRect(x,y,w,h);
ctx.strokeRect(x,y,w,h);
ctx.lineWidth = 2;
ctx.stroke();
y -= boxHeight;
timer += Math.random()*0.3;
}
}
function animate(){
ctx.clearRect(0,0,canvas.width,canvas.height);
window.requestAnimationFrame(animate);
drawBox();
}
animate();
this template function drawBox()just working fine, then i tried to enclose its properties into a Box()constructor object:
function Box(x, width) {
this.postion = {
x: x,
y: canvas.height
};
this.width = width;
this.height = canvas.height / 40;
this.colorTimer = 0;
this.draw = function() {
this.colorTimer += Math.random() * 0.3;
var ladder = Math.floor(Math.random() * ((canvas.height * 0.5) / boxHeight)) + 1;
for (var i = 0; i < ladder; i++) {
ctx.fillStyle = 'hsl(' + Math.abs(Math.sin(this.colorTimer) * 255) + ', 40%, 50%)';
ctx.fillRect(this.postion.x, this.postion.y, this.width, this.height);
ctx.strokeRect(this.postion.x, this.postion.y, this.width, this.height);
ctx.lineWidth = 2;
ctx.stroke();
this.postion.y -= this.height;
}
}
}
var myBox = new Box(20, boxWidth);
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
window.requestAnimationFrame(animate);
myBox.draw();
}
animate();
this is not working, i have been stuck with this about 2 hours and i don't think there is any method or properties difference between my Boxconstructor and my drawBoxobject. When it comes to myBoxobject to calling its draw()method, there is nothing pop out on the screen.
I am wondering did i just miss something important when creating Boxconstructor object? Could someone give me a hint please?
As #Todesengel mentioned, the real issue here is, you are re-initializing all the variables each time the template function (drawBox) is called. But you are not doing the same for the constructor. To resolve this, put this.colorTimer = 0 and this.postion.y = canvas.height insde the draw method (as these are the variables that need to be re-initialized).
However, there are other issues :
you are increasing the timer variable inside the for loop, in template function, but not doing the same for constructor
as #Barmar mentioned, you should define draw method as Box.prototype.draw, for efficiency (not mandatory though)
Here is the revised version of your code :
ctx = canvas.getContext('2d');
var boxHeight = canvas.height / 40;
var boxWidth = canvas.width / 20;
function Box(x, width) {
this.postion = {
x: x,
y: canvas.height
};
this.width = width;
this.height = canvas.height / 40;
}
Box.prototype.draw = function() {
this.colorTimer = 0;
this.postion.y = canvas.height;
var ladder = Math.floor(Math.random() * ((canvas.height * 0.5) / this.height)) + 1;
for (var i = 0; i < ladder; i++) {
ctx.fillStyle = 'hsl(' + Math.abs(Math.sin(this.colorTimer) * 255) + ', 40%, 50%)';
ctx.fillRect(this.postion.x, this.postion.y, this.width, this.height);
ctx.strokeRect(this.postion.x, this.postion.y, this.width, this.height);
ctx.lineWidth = 2;
ctx.stroke();
this.postion.y -= this.height;
this.colorTimer += Math.random() * 0.3;
}
}
var myBox = new Box(20, boxWidth);
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
myBox.draw();
window.requestAnimationFrame(animate);
}
animate();
<canvas id="canvas" width="300" height="300"></canvas>
I believe the important thing to note here is that in your first case, there is a new drawBox function being called every time, with the variables being instantiated and initialized, or "reset", each time. In your second case, the myBox object is not being recreated each time, so you have left over variables. These will not behave the same way. It should work as expected if you move var myBox = new Box(20, boxWidth); into the animate function.
Another fix, if you don't want to do recreate the myBox object for each call, is to reset the left over variables after each animate call. It would be more efficient, and probably more desirable, to do it this way.
You should not modify this.position.y in the draw method.
So remove this assignment from the loop:
this.postion.y -= this.height;
... and change the following lines to dynamically add -i*this.height:
ctx.fillRect(this.postion.x, this.postion.y-i*this.height, this.width, this.height);
ctx.strokeRect(this.postion.x, this.postion.y-i*this.height, this.width, this.height);
As others have said, you should better define the method on the prototype. And colorTimer should change in the for loop. I think you could do with a local variable though.
Demo:
var ctx = canvas.getContext('2d');
var boxHeight = canvas.height/40;
var boxWidth = canvas.width/20;
function Box(x, width) {
this.postion = {
x: x,
y: canvas.height
};
this.width = width;
this.height = canvas.height / 40;
}
Box.prototype.draw = function() {
var ladder = Math.floor(Math.random() * ((canvas.height * 0.5) / boxHeight)) + 1;
var colorTimer = 0;
for (var i = 0; i < ladder; i++) {
ctx.fillStyle = 'hsl(' + Math.abs(Math.sin(colorTimer) * 255) + ', 40%, 50%)';
ctx.fillRect(this.postion.x, this.postion.y-i*this.height, this.width, this.height);
ctx.strokeRect(this.postion.x, this.postion.y-i*this.height, this.width, this.height);
ctx.lineWidth = 2;
ctx.stroke();
colorTimer += Math.random() * 0.3;
}
};
var myBox = new Box(20, boxWidth);
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
window.requestAnimationFrame(animate);
myBox.draw();
}
animate();
<canvas id="canvas"></canvas>
For a project, I need to take these two blocks of code and modify them to create a little animation. The Javascript document creates a background color and creates like white rectangles fall down, like snow. The HTML document creates the canvas.
I have worked with the HTML canvas and done some super basic animations, but I'm hitting a roadblock here. When I try to add stuff to this, it does not show up. All I want to do is add some text and then animate it going across the canvas and some other very basic stuff.
I tried adding the text to the script portion of the html document like I have done several times before, but it just didn't seem to do anything.
Any idea what I'm doing wrong?
(I'm an animation major, so I apologize in advance for my ignorance; scripting is not my forte)
html document:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>A Basic Animation</title>
<script type="text/javascript" src="buffer-script2.js"></script>
<style type="text/css">
body,td,th {
font-family: Arial, "Franklin Gothic Book", sans-serif;
}
</style>
</head>
<body>
<h2>An Animation with Double Buffer</h2>
<canvas id="Sky" width="600" height="300">
Canvas not supported
</canvas>
<script>
var canvas = document.getElementById("Sky");
var ctx = canvas.getContext("2d");
ctx.font = "30px Arial";
ctx.strokeText("Hello World",10,50);
</script>
</body>
</html>
Javascript file:
window.onload = init;
var canvas = null;
var context = null;
var bufferCanvas = null;
var bufferCanvasCtx = null;
var flakeArray = [];
var flakeTimer = null;
var maxFlakes = 200;
function Flake() {
this.x = Math.round(Math.random() * context.canvas.width);
this.y = -10;
this.drift = Math.random();
this.speed = Math.round(Math.random() * 5) + 1;
this.width = (Math.random() * 5) + 2;
this.height = this.width;
}
function init() {
canvas = document.getElementById('Sky');
context = canvas.getContext("2d");
bufferCanvas = document.createElement("canvas");
bufferCanvasCtx = bufferCanvas.getContext("2d");
bufferCanvasCtx.canvas.width = context.canvas.width;
bufferCanvasCtx.canvas.height = context.canvas.height;
// initialize the rects
flakeTimer = setInterval(addFlake, 200);
Draw();
setInterval(animate, 30);
}
function addFlake() {
flakeArray[flakeArray.length] = new Flake();
if (flakeArray.length == maxFlakes)
clearInterval(flakeTimer);
}
function blank() {
bufferCanvasCtx.fillStyle = "#330033";
bufferCanvasCtx.fillRect(0,0,bufferCanvasCtx.canvas.width, bufferCanvasCtx.canvas.height);
}
function animate() {
Update();
Draw();
}
function Update() {
for (var i = 0; i < flakeArray.length; i++) {
if (flakeArray[i].y < context.canvas.height) {
flakeArray[i].y += flakeArray[i].speed;
if (flakeArray[i].y > context.canvas.height)
flakeArray[i].y = -5;
flakeArray[i].x += flakeArray[i].drift;
if (flakeArray[i].x > context.canvas.width)
flakeArray[i].x = 0;
}
}
}
function Draw(){
context.save();
/*
// create a clipping region
bufferCanvasCtx.beginPath();
bufferCanvasCtx.fillStyle="black";
bufferCanvasCtx.fillRect(0,0,bufferCanvas.width,bufferCanvas.height);
bufferCanvasCtx.arc(bufferCanvas.width/2,bufferCanvas.height/2,bufferCanvas.height/3,0,2*Math.PI);
bufferCanvasCtx.clip();
*/
blank();
for (var i = 0; i < flakeArray.length; i++) {
bufferCanvasCtx.fillStyle = "white";
bufferCanvasCtx.fillRect(flakeArray[i].x,flakeArray[i].y,flakeArray[i].width,flakeArray[i].height);
}
// copy the entire rendered image from the buffer canvas to the visible one
context.drawImage(bufferCanvas, 0,0,bufferCanvas.width, bufferCanvas.height);
context.restore();
}
I suggest...
Use requestAnimationFrame instead of an interval.
Get rid of the flakeTimer by initializing flakes at negative heights.
Get rid of the double buffer and render everything on one canvas.
Update flake positions relative to the time passed between updates.
Encapsulate updating and drawing of flakes, e.g. by introducing a Snow class.
Simplify iterations such as for (var i = 0; i < flakeArray.length; i++) by using e.g. for (let flake of flakes).
Less reliance on globals, pass canvas context and dimensions as parameters.
function Flake(x, y, drift, speed, size) {
this.x = x;
this.y = y;
this.drift = drift;
this.speed = speed;
this.size = size;
}
class Snow {
constructor() {
this.flakes = [];
}
update(dt, width, height) {
for (let flake of this.flakes) {
flake.y += flake.speed * dt;
if (flake.y > height) {
flake.y = -flake.size;
}
flake.x += flake.drift * dt;
if (flake.x > width) {
flake.x = -flake.size;
}
}
}
draw(ctx) {
ctx.fillStyle = "white";
for (let flake of this.flakes) {
ctx.fillRect(flake.x, flake.y, flake.size, flake.size);
}
}
}
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
let snow = new Snow();
// Add flakes:
for (let i = 0; i < 200; ++i) {
snow.flakes.push(new Flake(
Math.round(Math.random() * canvas.width),
-i * 200,
Math.random() * 0.05,
Math.random() * 0.25 + 0.05,
Math.random() * 5 + 2)
);
}
// Animate:
let last = performance.now();
function frame(time) {
// Clear background:
ctx.fillStyle = "#330033";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Update & render snow:
snow.update(time - last, canvas.width, canvas.height);
snow.draw(ctx);
// Render text:
ctx.strokeStyle = "white";
ctx.font = "30px Arial";
ctx.strokeText("Hello World", 10, 50);
requestAnimationFrame(frame);
last = time;
}
requestAnimationFrame(frame);
<canvas id="canvas" width="600" height="300"></canvas>
I have three arcs, the first one loads on page-load, the second one loads on mouse-over and the third one on mouse-out. I want the mouse-over-out effect to happen each time rather than just one time (as it is now).
here's the fiddle: http://jsfiddle.net/krish7878/7bX7n/
Here's the JS code:
var currentEndAngle = 0;
var currentStartAngle = 0;
var currentEndAngle2 = 0;
var currentStartAngle2 = 0;
var currentEndAngle3 = -0.5;
var currentStartAngle3 = -0.5;
var something = setInterval(draw, 5);
$("#canvas1").hover(
function(){
var something2 = setInterval(draw2, 5);
},
function(){
var something3 = setInterval(draw3, 5);
}
);
function draw() { /***************/
var can = document.getElementById('canvas1'); // GET LE CANVAS
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius;
var width;
var currentColor = "#00b5ff";
var radius = 100;
var width = 8;
var startAngle = currentStartAngle * Math.PI;
var endAngle = (currentEndAngle) * Math.PI;
if(currentEndAngle < 0.1){
currentEndAngle = currentEndAngle - 0.01;
}
if (currentEndAngle < -0.5){
clearInterval(something);
}
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, true);
context.lineWidth = width;
// line color
context.strokeStyle = currentColor;
context.stroke();
/************************************************/
}
function draw2() { /***************/
var can = document.getElementById('canvas1'); // GET LE CANVAS
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius;
var width;
var currentColor = "#000";
var radius = 100;
var width = 7;
var startAngle = currentStartAngle2 * Math.PI;
var endAngle = (currentEndAngle2) * Math.PI;
if(currentEndAngle2 < 0.1){
currentEndAngle2 = currentEndAngle2 - 0.01;
}
if (currentEndAngle2 < -0.55){
clearInterval(something2);
}
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, true);
context.lineWidth = width;
// line color
context.strokeStyle = currentColor;
context.stroke();
/*
context.beginPath();
context.clearRect ( 0 , 0 , 400 , 400 );
context.stroke():
/************************************************/
}
function draw3() { /***************/
var can = document.getElementById('canvas1'); // GET LE CANVAS
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius;
var width;
var currentColor = "#00b5ff";
var radius = 100;
var width = 8;
var startAngle = currentStartAngle3 * Math.PI;
var endAngle = (currentEndAngle3) * Math.PI;
if(currentEndAngle3 < 0){
currentEndAngle3 = currentEndAngle3 + 0.01;
}
if (currentEndAngle3 > 0){
clearInterval(something3);
}
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, false);
context.lineWidth = width;
// line color
context.strokeStyle = currentColor;
context.stroke();
/************************************************/
}
Code Explanation: there are three functions draw(), draw2(), draw3() - draw is run when the page loads, it draws a blue arc, draw2() is executed when mouse-over happens and draws a black line, draw3 is run when mouse-out happens.
Show I draw them on individual canvases and clear them individually or is there a method to get this done?
Here's one way to do it:
A Demo: http://jsfiddle.net/m1erickson/wMy4G/
Define an arc object
var arc={
cx:canvas.width/2,
cy:canvas.height/2,
radius:100,
startRadians:0,
endRadians:-Math.PI/2,
linewidth:8,
animationPercent:0,
animationRate:10,
animationDirection:0,
};
Draw a portion of the arc based on an animation point
function drawArc(arc,color){
var rStart=arc.startRadians;
var rEnd=arc.endRadians;
if(!arc.animationDirection==0){
if(arc.animationDirection>0){
rEnd=arc.animationPercent/100*(rEnd-rStart);
}else{
rEnd=(100-arc.animationPercent)/100*(rEnd-rStart);
}
}
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
ctx.arc(arc.cx,arc.cy,arc.radius,rStart,rEnd,true);
ctx.strokeStyle=color;
ctx.stroke();
}
Animate portions of the arc
function animate(time){
if(continueAnimation){RAF=requestAnimationFrame(animate);}
drawArc(arc,"blue");
arc.animationPercent+=arc.animationRate;
if(arc.animationPercent>=100){
continueAnimation=false;
}
}
React to hover events by drawing or undrawing the arc
$("#canvas").hover(
function(){
cancelAnimationFrame(RAF);
arc.animationPercent=0;
arc.animationDirection=1;
continueAnimation=true;
requestAnimationFrame(animate);
},
function(){
cancelAnimationFrame(RAF);
arc.animationPercent=0;
arc.animationDirection=-1;
continueAnimation=true;
requestAnimationFrame(animate);
}
);