I'm trying to have a simple rectangle move from current location to the clicked location on the canvas. When I provide a constant speed, the rectangle appears and moves fine. But when I multiply it by deltatime the rectangle doesn't appear anymore. I'm using requestAnimationFrame as the draw loop.
canvas.js
window.addEventListener('DOMContentLoaded', (event) => {
let canvas = document.getElementById("gamecanvas");
let ctx = canvas.getContext('2d');
var oldframetime = 0;
var x = 0;
var y = 0;
var dstx = 0;
var dsty = 0;
var deltatime = 0;
var speed = 5;
function getmousepos(evt){
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener("mousedown",e=>{
let coord = getmousepos(e);
dstx = coord.x;
dsty = coord.y;
});
function movetowards(current,target,maxdistancedelta){
if(Math.abs(target - current)<=maxdistancedelta){
return target;
}
return current+Math.sign(target - current) * maxdistancedelta;
}
function tick(timestamp){
deltatime = (timestamp - oldframetime)/1000;
var step = deltatime*speed;
var newlocx = movetowards(x,dstx-50,5);
var newlocy = movetowards(y,dsty-50,5);
ctx.clearRect(0,0,canvas.clientWidth,canvas.clientHeight);
ctx.fillStyle = 'green';
ctx.fillRect(newlocx,newlocy,100,100);
x = newlocx;
y = newlocy;
console.log(newlocx+":"+newlocy);
oldframetime = timestamp;
requestAnimationFrame(tick);
}
requestAnimationFrame(function(){
tick();
});
});
In that example, newlocx and newlocy both print NaN:NaN
But if I choose not to use step and give it a constant speed of like 5, then it works fine.
function tick(timestamp){
deltatime = (timestamp - oldframetime)/1000;
var step = deltatime*speed;
var newlocx = movetowards(x,dstx-50,5);
var newlocy = movetowards(y,dsty-50,5);
ctx.clearRect(0,0,canvas.clientWidth,canvas.clientHeight);
ctx.fillStyle = 'green';
ctx.fillRect(newlocx,newlocy,100,100);
x = newlocx;
y = newlocy;
console.log(newlocx+":"+newlocy);
oldframetime = timestamp;
requestAnimationFrame(tick);
}
The print is also accurate now. Why does multiplyng step by deltatime prevent the rectangle from moving? Or even appearing?
Here's the HTML if anyone's interested.
index.html
<html>
<head>
<script src="canvas.js"></script>
</head>
<body>
<canvas id="gamecanvas" width="2000" height="1000"></canvas>
</body>
</html>
I have checked and found out the issue is in the first statement of tick function. When program starts then value of parameter is undefined. And thats why first statement of tick function result in NaN.
Just use some default value for parameter "timestamp". Its working now but speed is low and i hope you are aware about it.
Line to check:
function tick(timestamp=10)
function tick(timestamp=10) {
deltatime = (timestamp - oldframetime) / 1000;
var step = deltatime * speed;
var newlocx = movetowards(x, dstx - 50, 5);
var newlocy = movetowards(y, dsty - 50, 5);
ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
ctx.fillStyle = 'green';
ctx.fillRect(newlocx, newlocy, 100, 100);
x = newlocx;
y = newlocy;
console.log(newlocx + ":" + newlocy);
oldframetime = timestamp;
requestAnimationFrame(tick);
}
You should be starting the animation with requestAnimationFrame rather than indirectly as you have done.
Replace
requestAnimationFrame(function(){
tick();
});
with
requestAnimationFrame(tick)
Then in the function tick you check if oldframetime has been set, if not set deltaTime to 0, as no time has passed, and thus starts the animation at the start. If you set the value of deltaTime to any other value you end up not rendering the animation from the start.
function tick(timestamp){
if (!oldframetime) {
deltaTime = 0;
} else {
deltatime = (timestamp - oldframetime)/1000;
}
// .. animation code
oldframetime = timestamp;
requestAnimationFrame(tick);
}
Related
I want to move a object (circle in this case) through array of coordinates (for example: {(300,400), (200,300), (300,200),(400,400)})on HTML5 Canvas. I could move the object to one coordinate as follows. The following code draws a circle at (100,100) and moves it to (300,400). I am stuck when trying to extend this so that circle moves through set of coordinates one after the other.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
//circle object
let circle ={
x:100,
y:100,
radius:10,
dx:1,
dy:1,
color:'blue'
}
//function to draw above circle on canvas
function drawCircle(){
ctx.beginPath();
ctx.arc(circle.x,circle.y,circle.radius,0,Math.PI*2);
ctx.fillStyle=circle.color;
ctx.fill();
ctx.closePath();
}
//Moving to a target coordinate (targetX,targetY)
function goTo(targetX,targetY){
if(Math.abs(circel.x-targetX)<circle.dx && Math.abs(circel.y-targetY)<circle.dy){
circle.dx=0;
circle.dy=0;
circel.x = targetX;
circle.y = targetY;
}
else{
const opp = targetY - circle.y;
const adj = targetX - circle.x;
const angle = Math.atan2(opp,adj)
circel.x += Math.cos(angle)*circle.dx
circle.y += Math.sin(angle)*circle.dy
}
}
function update(){
ctx.clearRect(0,0,canvas.width,canvas.height);
drawCircle()
goTo(300,400)
requestAnimationFrame(update);
}
update()
Random access key frames
For the best control of animations you need to create way points (key frames) that can be accessed randomly by time. This means you can get any position in the animation just by setting the time.
You can then play and pause, set speed, reverse and seek to any position in the animation.
Example
The example below uses a set of points and adds data required to quickly locate the key frames at the requested time and interpolate the position.
The blue dot will move at a constant speed over the path in a time set by pathTime in this case 4 seconds.
The red dot's position is set by the slider. This is to illustrate the random access of the animation position.
const ctx = canvas.getContext('2d');
const pathTime = 4; // Total time to travel path from start to end in seconds
var startTime, animTime = 0, paused = false;
requestAnimationFrame(update);
const P2 = (x, y) => ({x, y, dx: 0,dy: 0,dist: 0, start: 0, end: 0});
const pathCoords = [
P2(20, 20), P2(100, 50),P2(180, 20), P2(150, 100), P2(180, 180),
P2(100, 150), P2(20, 180), P2(50, 100), P2(20, 20),
];
createAnimationPath(pathCoords);
const circle ={
draw(rad = 10, color = "blue") {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(this.x, this.y, rad, 0, Math.PI * 2);
ctx.fill();
}
};
function createAnimationPath(points) { // Set up path for easy random position lookup
const segment = (prev, next) => {
[prev.dx, prev.dy] = [next.x - prev.x, next.y - prev.y];
prev.dist = Math.hypot(prev.dx, prev.dy);
next.end = next.start = prev.end = prev.start + prev.dist;
}
var i = 1;
while (i < points.length) { segment(points[i - 1], points[i++]) }
}
function getPos(path, pos, res = {}) {
pos = (pos % 1) * path[path.length - 1].end; // loop & scale to total length
const pathSeg = path.find(p => pos >= p.start && pos <= p.end);
const unit = (pos - pathSeg.start) / pathSeg.dist; // unit distance on segment
res.x = pathSeg.x + pathSeg.dx * unit; // x, y position on segment
res.y = pathSeg.y + pathSeg.dy * unit;
return res;
}
function update(time){
// startTime ??= time; // Throws syntax on iOS
startTime = startTime ?? time; // Fix for above
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (paused) { startTime = time - animTime }
else { animTime = time - startTime }
getPos(pathCoords, (animTime / 1000) / pathTime, circle).draw();
getPos(pathCoords, timeSlide.value, circle).draw(5, "red");
requestAnimationFrame(update);
}
pause.addEventListener("click", ()=> { paused = true; pause.classList.add("pause") });
play.addEventListener("click", ()=> { paused = false; pause.classList.remove("pause") });
rewind.addEventListener("click", ()=> { startTime = undefined; animTime = 0 });
div {
position:absolute;
top: 5px;
left: 20px;
}
#timeSlide {width: 360px}
.pause {color:blue}
button {height: 30px}
<div><input id="timeSlide" type="range" min="0" max="1" step="0.001" value="0" width= "200"><button id="rewind">Start</button><button id="pause">Pause</button><button id="play">Play</button></div>
<canvas id="canvas" width="200" height="200"></canvas>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// array of path coords
const pathCoords = [
[200,100],
[300, 150],
[200,190],
[400,100],
[50,10],
[150,10],
[0, 50],
[500,90],
[20,190],
[10,180],
];
// current point
let currentTarget = pathCoords.shift();
//circle object
const circle ={
x:10,
y:10,
radius:10,
dx:2,
dy:2,
color:'blue'
}
//function to draw above circle on canvas
function drawCircle(){
ctx.beginPath();
ctx.arc(circle.x,circle.y,circle.radius,0,Math.PI*2);
ctx.fillStyle=circle.color;
ctx.fill();
ctx.closePath();
}
//Moving to a target coordinate (targetX,targetY)
function goTo(targetX, targetY){
if(Math.abs(circle.x-targetX)<circle.dx && Math.abs(circle.y-targetY)<circle.dy){
// dont stop...
//circle.dx = 0;
//circle.dy = 0;
circle.x = targetX;
circle.y = targetY;
// go to next point
if (pathCoords.length) {
currentTarget = pathCoords.shift();
} else {
console.log('Path end');
}
} else {
const opp = targetY - circle.y;
const adj = targetX - circle.x;
const angle = Math.atan2(opp,adj)
circle.x += Math.cos(angle)*circle.dx
circle.y += Math.sin(angle)*circle.dy
}
}
function update(){
ctx.clearRect(0,0,canvas.width,canvas.height);
drawCircle();
goTo(...currentTarget);
requestAnimationFrame(update);
}
update();
<canvas id=canvas width = 500 height = 200></canvas>
The Problem
I have been creating a game, I have got to a stage where I want to see what it looks like with a mockup background I have created.
The Question
Where about in my code should I place this code as the place it currently is doesnt show the background.
I want this background on the canvas, the dimensions are correct.
The Code
var game = create_game();
game.init();
function create_game() {
debugger;
var level = 1;
var projectiles_per_level = 1;
var min_speed_per_level = 1;
var max_speed_per_level = 2;
var last_projectile_time = 0;
var next_projectile_time = 0;
var width = 600;
var height = 500;
var delay = 1000;
var item_width = 30;
var item_height = 30;
var total_projectiles = 0;
var projectile_img = new Image();
var projectile_w = 30;
var projectile_h = 30;
var player_img = new Image();
var background_img = new Image();
var c, ctx;
var projectiles = [];
var player = {
x: 200,
y: 400,
score: 0
};
function init() {
projectile_img.src = "projectile.png";
player_img.src = "player.png";
background_img.src = "background.png";
background_img.onload = function(){
context.drawImage(background_img, 0, 0);
}
level = 1;
total_projectiles = 0;
projectiles = [];
c = document.getElementById("c");
ctx = c.getContext("2d");
ctx.fillStyle = "#410b11";
ctx.fillRect(0, 0, 500, 600);
c.addEventListener("mousemove", function (e) {
//moving over the canvas.
var bounding_box = c.getBoundingClientRect();
player.x = (e.clientX - bounding_box.left) * (c.width / bounding_box.width) - player_img.width / 2;
}, false);
setupProjectiles();
requestAnimationFrame(tick);
}
function setupProjectiles() {
var max_projectiles = level * projectiles_per_level;
while (projectiles.length < max_projectiles) {
initProjectile(projectiles.length);
}
}
function initProjectile(index) {
var max_speed = max_speed_per_level * level;
var min_speed = min_speed_per_level * level;
projectiles[index] = {
x: Math.round(Math.random() * (width - 2 * projectile_w)) + projectile_w,
y: -projectile_h,
v: Math.round(Math.random() * (max_speed - min_speed)) + min_speed,
delay: Date.now() + Math.random() * delay
}
total_projectiles++;
}
function collision(projectile) {
if (projectile.y + projectile_img.height < player.y + 20) {
return false;
}
if (projectile.y > player.y + 74) {
return false;
}
if (projectile.x + projectile_img.width < player.x + 20) {
return false;
}
if (projectile.x > player.x + 177) {
return false;
}
return true;
}
function maybeIncreaseDifficulty() {
level = Math.max(1, Math.ceil(player.score / 10));
setupProjectiles();
}
function tick() {
var i;
var projectile;
var dateNow = Date.now();
c.width = c.width;
for (i = 0; i < projectiles.length; i++) {
projectile = projectiles[i];
if (dateNow > projectile.delay) {
projectile.y += projectile.v;
if (collision(projectile)) {
initProjectile(i);
player.score++;
} else if (projectile.y > height) {
initProjectile(i);
} else {
ctx.drawImage(projectile_img, projectile.x, projectile.y);
}
}
}
ctx.font = "bold 24px sans-serif";
ctx.fillStyle = "#410b11";
ctx.fillText(player.score, c.width - 50, 50);
ctx.fillText("Level: " + level, 20, 50);
ctx.drawImage(player_img, player.x, player.y);
maybeIncreaseDifficulty();
requestAnimationFrame(tick);
ctx.drawImage(background_img, 0, backgroundY);
}
return {
init: init
};
}
As already pointed out in a comment, here more precisely:
First of all, the background picture must be rendered first in every animation frame.
However, the picture didn't show up at all. This is due to the fact that variable was used (backgroundY), which is never declared somewhere.
This should actually printed to the console as an error "backgroundY" is not defined.
Whenever an the property src of an image object is set to a value, it takes some time until it's loaded. So in many cases, it's necessary to indicate the moment, when it's finished loading by the onload callback.
In this case, however, it's not necessary. The tick / animation loop function will just draw nothing (an empty image object) until it's loaded. After it's loaded it will continue to draw the loaded image every frame.
If the background is really important, meaning, the app should only start, when it's there, of course, one can only start the whole game / animation from within the img.onload handler.
You must draw:
the background first
the player later
level/score info last
Background < Player < UI < You Looking
The drawing order is from back to top (painters algorithm)
Also note that for performance reasons if you background never changes you could draw it in another 'static' canvas under the game canvas.
Otherwise the background will be drawn above/over the player and hide it.
How can I reset the velocity variable in my objects. I am making a canvas game, in which stars fall from the top of the Canvas. Problem is when I run the game in a setinterval() the velocity keeps getting greater and greater. What i want is the speed to stay the same unless i change it.
function Star(x, y, rad, velocity, fill){
this.x = Math.floor(Math.random() * 999);//this create a random number between 0 and 599 on the x axis
this.y = 0;
this.rad = Math.floor((Math.random() * 30) + 15);//this create a random number between 10 and 30 for the radius
this.velocity = 5;
this.fill = fill
this.draw = function(){
ctx.beginPath();
ctx.fillStyle = this.fill;
ctx.arc(this.x, this.y, this.rad, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
this.y += this.velocity;
}
}
function createMultipleStars(){
for (var i = 0; i <= numOfStars; i++)
stars[i] = new Star(i * 50, 10, i, i, "rgba(255,215,0,0.6)");
}
//createMultipleStars();
function step() {
ctx.clearRect(0,0,canvas.width, canvas.height);
for (var i = 0; i<= numOfStars; i++)
stars[i].draw();
requestAnimationFrame(step);
}
spaceShip.drawSpaceShip();
var myVar = setInterval(function(){ init() }, 4000);
function init(){
createMultipleStars();
step();
}
Your frames per second were increasing with each interval. Every four seconds another step function is added to the animation frame. To fix this I added an fps counter and singleton pattern. With the singleton pattern you shouldn't break the requestAnimationFrame max 60 fps. Without it you will see that the fps increases. Technically it can't go above 60 but the step function runs multiple times in the same frame increasing the velocity each time and making the stars run faster.
var canvas = document.getElementById('can');
var ctx = canvas.getContext('2d');
var stars = [];
var numOfStars = 10;
function Star(x, y, rad, velocity, fill) {
this.x = Math.floor(Math.random() * 999); //this create a random number between 0 and 599 on the x axis
this.y = 0;
this.rad = Math.floor((Math.random() * 30) + 15); //this create a random number between 10 and 30 for the radius
this.velocity = 5;
this.fill = fill
this.draw = function() {
ctx.beginPath();
ctx.fillStyle = this.fill;
ctx.arc(this.x, this.y, this.rad, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
this.y += this.velocity;
}
}
function createMultipleStars() {
for (var i = 0; i <= numOfStars; i++) {
stars[i] = new Star(i * 50, 10, i, i, "rgba(255,215,0,0.6)");
}
}
function fps() {
var now = (new Date()).getTime();
fps.frames++;
if ((now - fps.lastFps) >= 1000) {
fps.total = fps.frames;
fps.lastFps = now;
fps.frames = 0;
}
return fps.total;
}
fps.frames = 0;
fps.lastFps = (new Date()).getTime();
fps.total = 0;
// Step is a singleton. Only one instance can be created.
function Step() {
// comment out the line below to see what happens when not running
// singleton
if (Step.instance !== null) return Step.instance;
var self = this;
function frame() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i <= numOfStars; i++) {
stars[i].draw();
}
ctx.fillStyle = "red";
ctx.fillText("FPS: " + fps(), 10, 10);
requestAnimationFrame(frame);
}
frame();
Step.instance = this;
return this;
}
Step.instance = null;
//spaceShip.drawSpaceShip();
function init() {
var myVar = setInterval(function() {
createMultipleStars();
var step = new Step();
}, 4000);
createMultipleStars();
//
var step = new Step();
var step = new Step();
var step = new Step();
var step = new Step();
}
init();
#can {
border: 1px solid #FF0000;
}
<canvas id="can" width="400" height="200"></canvas>
Your issue is very simple : you are using both requestAnimationFrame and setInterval to drive the animation. More and more render loops get created and run at the same time, causing the issue
Separate the concerns :
have one render loop working for ever with RequestAnimationFrame
Have a setInterval-ed function inject some new stuff in your game.
So the only change you need to do is here :
var myVar = setInterval(createMultipleStars, 4000);
I am trying to create what I thought would be a simple Canvas to move a point from A to B using requestAnimationFrame.
http://jsfiddle.net/p1L81yk4/1/
Unfortunately it is not showing anything, and the animation loop seems to be headed towards infinity.
Can anyone explain what I am doing wrong? And is there a flag I can create to show when the animation should stop?
var startX = 10,
startY = 10;
var endX = 200,
endY = 350;
var speed = 1;
var dx = endX - startX;
var dy = endY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
var moves = distance / speed;
var xunits = (dx / moves);
var yunits = (dy / moves);
var posit = {
x: startX,
y: startY
};
var fps = 60;
var delay = 1000 / 30;
function draw() {
ctx.clearRect(0, 0, canv.width, canv.height);
ctx.save();
ctx.translate(startX, startY);
ctx.beginPath();
ctx.arc(0, 0, 5, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
function move() {
startX += dx;
startY += dy;
console.log(posit);
if (moves > 0) {
moves++;
posit.x += xunits;
posit.y += yunits;
}
}
var start = 0;
function animate() {
running = true;
var current = new Date().getTime(),
delta = current - start;
if (delta >= delay) {
move();
draw();
start = new Date().getTime();
}
anim = requestAnimationFrame(animate);
}
animate();
You should not use save and restore, these functions is for saving and restoring the images.
You should translate posit.x and posit.y instead of startX and startY.
You are changing startX and startY which is not reasonable.
You need a if to determinate if or if not to continue aniamtion.
Which ends up with a working code:
var canv = document.getElementById('canv'),
ctx = canv.getContext('2d');
var startX = 10,
startY = 10;
var endX = 200,
endY = 350;
var speed = 2;
var dx = endX - startX;
var dy = endY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
var moves = distance / speed;
var xunits = (dx / moves);
var yunits = (dy / moves);
var posit = {
x: startX,
y: startY
};
var fps = 60;
var delay = 1000 / 60;
function draw() {
ctx.clearRect(0, 0, canv.width, canv.height);
//ctx.save();
ctx.translate(posit.x, posit.y);
ctx.beginPath();
ctx.arc(0, 0, 5, 0, Math.PI * 2);
ctx.fill();
ctx.translate(-posit.x, -posit.y);
//ctx.restore();
}
function move() {
//startX += dx;
//startY += dy;
//console.log(posit);
if (moves > 0) {
moves++;
posit.x += xunits;
posit.y += yunits;
}
}
var start = 0;
function animate() {
running = true;
var current = new Date().getTime(),
delta = current - start;
if (delta >= delay) {
move();
draw();
start = new Date().getTime();
}
if(posit.y < endY)
anim = requestAnimationFrame(animate);
}
animate();
<canvas id="canv" width="500" height="500"></canvas>
Using basic trigonometry you can make the entire code look and read easier, with less up front variables. I still need to set quite a lot of variables here, but you would want to mostly calculate them on the fly (which means you would have to move things like angle, from and to value and distance into the myDraw() function).
var myCanvas = document.getElementById('myCanvas');
var myContext = myCanvas.getContext('2d');
myContext.fillStyle = '#000';
// Values expressed as x, y, positions
var fromValue = [300,20];
var toValue = [100,100];
// time expressed in Milliseconds
var time = 5000;
var start = Date.now();
// Get the angle with the arctangent function
// tan(angle) = opposite / adjacent => atan(opposite / adjacent) = angle
// atan2 is used because you can pass it the lengths and it takes care of
// some negative edge cases.
var angle = Math.atan2(toValue[0] - fromValue[0], toValue[1] - fromValue[1]);
// Basic distance because.. Pythagoras. (a^2 = sqrt(b^2 + c^2))
var distance = Math.sqrt(Math.pow(toValue[0] - fromValue[0], 2) + Math.pow(toValue[1] - fromValue[1], 2));
function myDraw(now){
// The max distance can be divided by the total time, multiplied by the time that has passed
var t = (distance / time * (now - start));
var x = fromValue[0] + Math.sin(angle) * t;
var y = fromValue[1] + Math.cos(angle) * t;
// Clear the canvas by resetting its width
myCanvas.width = myCanvas.width;
// Draw the arc at position x and y
myContext.arc(x, y, 3, 0, Math.PI * 2);
myContext.fill();
// Return false if the animation is done.
if(now < start + time) return true;
else return false;
}
function myAnimate(){
// Keep executing as long as myDraw() returns true
if(myDraw(Date.now())) window.requestAnimationFrame(myAnimate);
}
myAnimate();
<canvas width="500" height="500" id="myCanvas" />
So right now I have a simple canvas element with functions that create random colors, sizes, and positions of arcs (circles).
The 'for' loop that generates the random positions of these random circles executes 1 circle every 100 milliseconds (This is done onclick).
I want to know how I can make each circle slowly come near the cursor, and then follow the cursor around wherever it moves.
http://jsfiddle.net/JXXgx/
You may try something like this:
var MAXIMUM_AMOUNT = 1000,
FPS = 30,
targetToGo, //
shapes = []; //storage of circles
//Helper class
function CircleModel(x,y,r,color){
this.x = x;
this.y = y;
this.r = r;
this.color = color;
}
function initScene(){
//Listening for mouse position changes
$('canvas').mousemove(function(e){
targetToGo.x = e.pageX;
targetToGo.y = e.pageY;
});
//Circle generation timer
var intervalID = setInterval(function(){
if( shapes.length < MAXIMUM_AMOUNT ){
for(var i = 0; i < 1; i++){
//Generating random parameters for circle
var randX = targetToGo.x - 500 + Math.floor(Math.random() * 1000); //position x
var randY = targetToGo.y - 300 + Math.floor(Math.random() * 600); //position y
var randRadius = Math.floor(Math.random() * 12); //radius
var randColor = "#"+("000000"+(0xFFFFFF*Math.random()).toString(16)).substr(-6); //color
//Adding circle to scene
shapes.push( new CircleModel(randX,randY,randRadius,randColor) );
}
}else{
clearInterval(intervalID);
}
}, 100);
//Starts rendering timer -
// '1000' represents 1 second,as FPS represents seconds,not miliseconds
setInterval(render,1000/FPS);
}
function render(){
var ctx = $('canvas')[0].getContext("2d");
var circle;
//Clearing the scene
ctx.clearRect(0,0,$('canvas').width(),$('canvas').height());
//Drawing circles
for(var i=0; i < shapes.length;++i){
circle = shapes[i];
//(animation part)
//repositioning circle --
// (1/circle.r) is a degree of inertion,and the bigger radius,the slower it moves
circle.x += (targetToGo.x - circle.x)*1/circle.r;
circle.y += (targetToGo.y - circle.y)*1/circle.r;
////////////////////////////////////////////
ctx.fillStyle = circle.color;
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
}
$("canvas").click(function(e){
targetToGo = {x: e.pageX, y:e.pageY};
initScene();
});
Put this code inside of $(document).ready handler.
Demo