EDIT: solution some lines above.
I'm trying to have bouncing pictures with html5, canvas and some jQuery.
I've successfully made some balls bouncing, but I can't figure out how to draw pictures instead of simple 'particles'.
I've tried in different ways, but actually I think I'missing something.
I post the whole html so you can just copy/paste it easily.
Under my try there is a commented section with working bouncing balls.
Thank you so much!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML5 Canvas Explode Demo</title>
<link rel="stylesheet" href="styles.css" />
<meta name="viewport" content="width=320 initial-scale=1.0, user-scalable=no" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<style type="text/css">
* {
margin: 0; padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
canvas {
display: block;
background: whiteSmoke;
width: 100%;
height: 100%;
}
#presentation{
position: fixed;
background: rgba(0,0,0,0.7);
width: 100%;
height: 70px;
box-shadow: 7px 7px 13px rgba(0,0,0,0.3);
color: white;
font-family:futura;
font-size: 30px;
padding-left: 50px;
padding-top: 10px;
}
</style>
</head>
<body>
<div id="presentation">Bouncing Baaaaalls!</div>
<canvas id="output" ></canvas>
<script type="text/javascript">
(function() {
window.requestAnimationFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||function(f){window.setTimeout(f,40/60)
}}});
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
function Particle() {
var W = canvas.width = window.innerWidth;
var H = canvas.height = window.innerHeight;
this.radius = 20;
this.x = parseInt(Math.random() * W);
this.y = H;
this.color = 'rgb(' +
parseInt(Math.random() * 255) + ',' +
parseInt(Math.random() * 255) + ',' +
parseInt(Math.random() * 255) + ')';
if (this.x > W/2 ){
this.vx = Math.random() * (-15 - -5) + -5;
}else{
this.vx = Math.random() * (15 - 5) + 5;
}
this.vy = Math.random() * (-32 - -25) + -25;
this.draw = function() {
var img = new Image();
img.src = 'troll1.png';
ctx.beginPath();
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.closePath();
ctx.beginPath();
ctx.arc(this.x, this.y, 20, 0, 6.28, false);
ctx.clip();
ctx.stroke();
ctx.closePath();
ctx.drawImage(img, 0, 0);
// WORKING PARTICLES STARTS HERE
// ctx.fillStyle = this.color;
// ctx.beginPath();
// ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2, false);
// ctx.fill();
// ctx.closePath();
// WORKING PARTICLES ENDS HERE
};
}
var particle_count = 20;
var particles = [];
// Now lets quickly create our particle
// objects and store them in particles array
for (var i = 0; i < particle_count; i++) {
var particle = new Particle();
particles.push(particle);
}
function renderFrame() {
requestAnimationFrame(renderFrame);
// Clearing screen to prevent trails
var W = canvas.width = window.innerWidth;
var H = canvas.height = window.innerHeight;
ctx.clearRect(0, 0, W, H);
particles.forEach(function(particle) {
// The particles simply go upwards
// It MUST come down, so lets apply gravity
particle.vy += 1;
// Adding velocity to x and y axis
particle.x += particle.vx;
particle.y += particle.vy;
// We're almost done! All we need to do now
// is to reposition the particles as soon
// as they move off the canvas.
// We'll also need to re-set the velocities
if (
// off the right side
particle.x + particle.radius > W ||
// off the left side
particle.x - particle.radius < 0 ||
// off the bottom
particle.y + particle.radius > H
) {
// If any of the above conditions are met
// then we need to re-position the particles
// on the base :)
// If we do not re-set the velocities then
// the particles will stick to base :D
// Velocity X
particle.x = parseInt(Math.random() * W);
particle.y = H;
if (particle.x > W/2 ){
particle.vx = Math.random() * (-15 - -5) + -5;
}else{
particle.vx = Math.random() * (15 - 5) + 5;
}
particle.vy = Math.random() * (-32 - -28) + -28;
}
particle.draw();
});
}
$(document).ready(function(){
renderFrame();
});
</script>
</body>
</html>
EDIT WITH SOLUTION:
First, thanks to markE
I edited the code as he said, the problem was actually about timing (and understanding what I was doing). His answer really helped me a lot.
The image was not moving because I didn't told it to do that actually ( with ctx.drawImage(img, this.x, this.y)).
NOTE: For debugging canvas rendering with chrome take a look at HTML5 canvas inspector?
So here is the working (and ultra commented, thanks for the lesson markE) code for bouncing troll faces (put a troll1.png picture in the same folder):
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML5 Canvas Explode Demo</title>
<!-- <link rel="stylesheet" href="styles.css" /> --> <meta name="viewport" content="width=320 initial-scale=1.0, user-scalable=no" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<style type="text/css">
* {
margin: 0; padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
canvas {
display: block;
background: whiteSmoke;
width: 100%;
height: 100%;
}
#presentation{
position: fixed;
background: rgba(0,0,0,0.7);
width: 100%;
height: 70px;
box-shadow: 7px 7px 13px rgba(0,0,0,0.3);
color: white;
font-family:futura;
font-size: 30px;
padding-left: 50px;
padding-top: 10px;
}
</style>
</head>
<body>
<div id="presentation">Bouncing Baaaaalls!</div>
<canvas id="output" ></canvas>
<script type="text/javascript">
(function() {
//define the animation refresh (frame rendering) with built-in browser timing
window.requestAnimationFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||function(f){window.setTimeout(f,40/60)
}}});
//define some variables: canvas, context, img to put inside the context and an array of bouncing objects
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
//IMPORTANT: Wait for the picture to be loaded!
img.onload = function(){
alert('troll1 is LOADED.');
beginAnimation();
};
//yes, the src goes after
img.src = 'troll1.png';
//how many bouncing objects?
var particle_count = 4;
var particles = [];
var particle;
function Particle() {
//define properties of a bouncing object, such as where it start, how fast it goes
var W = canvas.width = window.innerWidth;
var H = canvas.height = window.innerHeight;
this.radius = 20;
this.x = parseInt(Math.random() * W);
this.y = H;
//Uncomment for coloured particles:
// this.color = 'rgb(' +
// parseInt(Math.random() * 255) + ',' +
// parseInt(Math.random() * 255) + ',' +
// parseInt(Math.random() * 255) + ')';
//end coloured particles
if (this.x > W/2 ){
this.vx = Math.random() * (-15 - -5) + -5;
}else{
this.vx = Math.random() * (15 - 5) + 5;
}
this.vy = Math.random() * (-32 - -25) + -25;
//we will call this function to actually draw the bouncing object at EVERY FRAME
this.draw = function() {
// Bouncing pictures were not bouncing because there were no this.x this.y . Shame on me.
ctx.drawImage(img,this.x,this.y);
// WORKING PARTICLES STARTS HERE
// ctx.fillStyle = this.color;
// ctx.beginPath();
// ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2, false);
// ctx.fill();
// ctx.closePath();
//WORKING PARTICLES ENDS HERE
};
}
function renderFrame() {
//RENDER THE PARTICLEEEEEEES!
requestAnimationFrame(renderFrame);
// Clearing screen to prevent trails
var W = canvas.width = window.innerWidth;
var H = canvas.height = window.innerHeight;
ctx.clearRect(0, 0, W, H);
particles.forEach(function(particle) {
// The bouncing objects simply go upwards
// It MUST come down, so lets apply gravity
particle.vy += 1;
// Adding velocity to x and y axis
particle.x += particle.vx;
particle.y += particle.vy;
// We're almost done! All we need to do now
// is to reposition the bouncing objects as soon
// as they move off the canvas.
// We'll also need to re-set the velocities
if (
// off the right side
particle.x + particle.radius > W ||
// off the left side
particle.x - particle.radius < 0 ||
// off the bottom
particle.y + particle.radius > H
) {
// If any of the above conditions are met
// then we need to re-position the bouncing objects
// on the base :)
// If we do not re-set the velocities then
// the bouncing objects will stick to base :D
// Velocity X
particle.x = parseInt(Math.random() * W);
particle.y = H;
if (particle.x > W/2 ){
particle.vx = Math.random() * (-15 - -5) + -5;
}else{
particle.vx = Math.random() * (15 - 5) + 5;
}
particle.vy = Math.random() * (-32 - -28) + -28;
}
particle.draw();
});
}
function beginAnimation(){
//create the particles and start to render them
for (var i = 0; i < particle_count; i++) {
particle = new Particle();
particles.push(particle);
}
//BOUNCE MOFOS!
renderFrame();
}
</script>
You're not waiting for troll1.png to load before trying to draw it.
Var img=new Image();
img.onload=function(){
beginMyAnimation();
}
img.src=”troll1”;
alert(“troll1 is not loaded yet.”);
function beginAnimation(){
….
ctx.drawImage(img,0,0);
….
}
The order of execution is like this:
First var img=new Image().
Javascript creates a new image object and puts a reference in img.
Second img.onload….
Javascript doesn’t execute this code yet. It just takes note that onload must be executed after troll1.jpg has successfully been loaded into the new image object.
Third img.src=”something.jpg”.
Javascript immediately begins loading troll1.jpg.
Since loading will take a while, Javascript also continues executing any code that follows.
Fourth alert(“Image is not loaded yet.”);
Javascript displays this alert message. Note that troll1.jpg has not been loaded yet. Therefore, any code that tried to use the image now would fail—no image yet!
Fifth img.onload.
Javascript has finally fully loaded troll1.jpg so it executes the onload function.
Sixth beginMyAnimation()
Javascript will finally execute beginAnimation(). At this point any code that tries to use the image will succeed. You can do ctx.drawImage(img,0,0) will succeed now.
So rearrange all your setup code inside in beginAnimation(). Finally, put renderFrame() last in beginAnimation().
Related
in my code, how the lineTo() method is working even i didn't call moveTo() method. also i am trying to create an animation using canvas lines, but i can't make it properly. here's the work in progress
the css -> body {margin: 0; overflow: hidden;}
the html ->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="main.js"></script>
</body>
</html>
the jquery ->
$(document).ready(function () {
// make canvas fullpage
var canvas = $('canvas');
var ctx = canvas[0].getContext('2d');
var innerWidth = $(window).width();
var innerHeight = $(window).height();
canvas.attr('width', innerWidth);
canvas.attr('height', innerHeight);
var x = 0;
var y = 0;
var dx = 10;
var dy = 10;
// animate function
$.fn.animate = function () {
requestAnimationFrame($.fn.animate);
ctx.clearRect(0, 0, innerWidth, innerHeight);
// for diagonal motion
ctx.lineTo((innerWidth / 1000) * x, (innerHeight / 1000) * y);
ctx.stroke();
// for horizontal motion
// ctx.lineTo((innerWidth / 1000) * x, innerHeight / 2);
// ctx.stroke();
// for vartical motion
// ctx.lineTo(innerWidth / 2, (innerHeight / 1000) * y);
// ctx.stroke();
if (x > innerWidth || x < 0) {
dx = -dx;
}
if (y > innerHeight || y < 0) {
dy = -dy;
}
x += dx;
y += dy;
}
$.fn.animate();
});
how to make this animation in correct form and how to stop the animate function ?
In order to stop the animation you need to use cancelAnimationFrame. This method takes as argument the animation id. Now if you click the canvas you can stop the animation or start the animation if it's stopped.
$(document).ready(function() {
var rid = null;
// make canvas fullpage
var canvas = $("canvas");
var ctx = canvas[0].getContext("2d");
var innerWidth = $(window).width();
var innerHeight = $(window).height();
canvas.attr("width", innerWidth);
canvas.attr("height", innerHeight);
var x = 0;
var y = 0;
var dx = 10;
var dy = 10;
// animate function
$.fn.animate = function() {
rid = requestAnimationFrame($.fn.animate);
ctx.clearRect(0, 0, innerWidth, innerHeight);
// for diagonal motion
ctx.lineTo(innerWidth / 1000 * x, innerHeight / 1000 * y);
ctx.stroke();
if (x > innerWidth || x < 0) {
dx = -dx;
}
if (y > innerHeight || y < 0) {
dy = -dy;
}
x += dx;
y += dy;
};
$.fn.animate();
canvas.click(function() {
if (rid) {
cancelAnimationFrame(rid);
rid = null;
} else {
rid = requestAnimationFrame($.fn.animate);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas></canvas>
previous arc needs to disappear and only the recent one should show up.
Here is the code I have until now.
context.fill();
context.closePath();
}
})(document);
function randomColor() {
var color = [];
for (var i = 0; i < 3; i++) {
color.push(Math.floor(Math.random() * 256));
}
return 'rgb(' + color.join(',') + ')';
}
<canvas id="testCanvas" style="border:1px solid #000000;"></canvas>
Here is how to do it:
We need to keep a list of all circles
Loop over the circle checking if the click overlap a previous one
We need to detect overlaps (collisions) between two circles, easy Pythagorean calculation
Here is a working sample:
(function(doc) {
var canvas = doc.getElementById("testCanvas");
var context = canvas.getContext("2d");
var circles = []
function drawCircle(circle) {
context.beginPath();
context.fillStyle = circle.color;
context.arc(circle.x, circle.y, circle.rad, 0, 2 * Math.PI, true);
context.fill();
context.closePath();
}
function collision(circle1, circle2) {
var dx = circle1.x - circle2.x
var dy = circle1.y - circle2.y
return Math.sqrt(dx * dx + dy * dy) < (circle1.rad + circle2.rad);
}
function drawCircles(data) {
context.clearRect(0, 0, canvas.width, canvas.height);
drawCircle(data)
for (var i = circles.length - 1; i >= 0; i--) {
if (collision(circles[i], data)) {
circles.splice(i, 1);
} else {
drawCircle(circles[i])
}
}
circles.push(data)
}
// click event handler
canvas.onclick = function(e) {
drawCircles({
color: randomColor(),
rad: 5 + Math.random() * 30,
x: e.clientX - e.target.offsetLeft,
y: e.clientY - e.target.offsetTop
})
}
})(document);
function randomColor() {
var color = [];
for (var i = 0; i < 3; i++) {
color.push(Math.floor(Math.random() * 256));
}
return 'rgb(' + color.join(',') + ')';
}
<canvas id="testCanvas" style="border:1px solid #000000;"></canvas>
To make it interesting I made the new circle with a random radius...
If you want to make things even more interesting (and have the time for it) instead of making the overlapping circles disappear, make them move & shrink until they do not overlap.
I am struggling to understand why my angles are returning weird angles if anything other than a right angle is drawn. I drew a basic triangle using Canvas in HTML5.
I have the html code and js code to paste here: Please can someone tell me why only these right angles adds up to 180degrees. I have set the js code to output the angles and the sum thereof to the console... so you can see what I am talking about.
You can modify the draw function code to set the position of one of the points to make a right angle.. then you will see the 180 degrees and the angles are correct.
I searched all over the internet for an explanation and checked my formulas. Cant seem to figure this one out.
Thank you very much for any help you can offer..
--- CODE FOR HTML ---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Canvas - Triangle experiment</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="js/drawShapes.js"></script>
<style>
* { margin: 0; }
* { padding: 0; }
span.markings {
position: absolute;
}
div.drawingArea {
margin: 50px 0 0 10px;
padding: 0;
width: 500px;
height: 500px;
position: relative;
background: #ccc;
}
.coords { position: absolute; top: 0; left: 200px; }
.coords p { position: relative; }
.xcoord, .ycoord { font-weight: bold; color: red; }
#myCanvas { background: #eee; }
</style>
</head>
<body>
<div class="coords"><p>X: <span class="xcoord"></span></p><p>Y: <span class="ycoord"></span></p></div>
<div class="drawingArea">
<span class="markings A"></span>
<span class="markings B"></span>
<span class="markings C"></span>
<canvas id="myCanvas" width="410" height="410">Your browser does not have support for Canvas. You should see:</canvas>
</div>
</body>
</html>
--- CODE FOR JS ---
$(document).ready(function(){
// Just for dev purposes.. show X and Y coords when inside drawingArea
$('.drawingArea').mousemove(function(e){
$('.xcoord').html(e.pageX -10); // subtract 10 for margin left is 10
$('.ycoord').html(e.pageY -50); // subtract 40 bc margin top is 40
});
draw();
function draw()
{
// Initialize context
createContext('2d');
// Set the style properties.
context.fillStyle = '#fff';
context.strokeStyle = '#FF9900';
context.lineWidth = 5;
// Set initial positions and lengths
pts = {};
pts.AXLoc = 60;
pts.AYLoc = 40;
pts.BXLoc = 360;
pts.BYLoc = 40;
pts.CXLoc = 100;
pts.CYLoc = 340;
// Get difference between points
vector = {};
vector.Ax = Math.abs(pts.AXLoc-pts.BXLoc);
vector.Ay = Math.abs(pts.AYLoc-pts.BYLoc);
vector.Bx = Math.abs(pts.BXLoc-pts.CXLoc);
vector.By = Math.abs(pts.BYLoc-pts.CYLoc);
vector.Cx = Math.abs(pts.CXLoc-pts.AXLoc);
vector.Cy = Math.abs(pts.CYLoc-pts.AYLoc);
console.log(vector.Ax);
console.log(vector.Ay);
console.log(vector.Bx);
console.log(vector.By);
console.log(vector.Cx);
console.log(vector.Cy);
// Find the magnitude of each vector
vector.magA = Math.sqrt(Math.pow(vector.Ax, 2) + Math.pow(vector.Ay, 2));
vector.magB = Math.sqrt((Math.pow((vector.Bx), 2) + Math.pow((vector.By), 2)));
vector.magC = Math.sqrt((Math.pow((vector.Cx), 2) + Math.pow((vector.Cy), 2)));
// Cos A = (A.C) / sqrt(magnitude of A) x (magnited of C)
// This should return radian which is then converted to degrees
// Create function once code works!
vector.angleA = ((vector.Ax * vector.Cx) + (vector.Ay * vector.Cy)) / (vector.magA * vector.magC);
vector.angleA = Math.acos(vector.angleA) * (180/Math.PI);
vector.angleB = ((vector.Ax * vector.Bx) + (vector.Ay * vector.By)) / (vector.magA * vector.magB);
vector.angleB = Math.acos(vector.angleB) * (180/Math.PI);
vector.angleC = ((vector.Bx * vector.Cx) + (vector.By * vector.Cy)) / (vector.magB * vector.magC);
vector.angleC = Math.acos(vector.angleC) * (180/Math.PI);
// Output test data
console.log('angle a = ' + vector.angleA);
console.log('angle b = ' + vector.angleB);
console.log('angle c = ' + vector.angleC);
vector.allangles = vector.angleA + vector.angleB + vector.angleC;
console.log('All angles = ' +vector.allangles ); // only adds up to 180deg if right angle??!!
// Begin drawing
context.beginPath();
// Start from the top-left point.
context.moveTo(pts.AXLoc, pts.AYLoc); // give the (x,y) coordinates
context.lineTo(pts.BXLoc, pts.BYLoc);
context.lineTo(pts.CXLoc, pts.CYLoc);
//context.lineTo(pts.AXLoc, pts.AYLoc); // closes the origin point? alternate way of closing???
context.lineJoin = 'mitre';
context.closePath(); // closes the origin point? good for strokes
// Done! Now fill the shape, and draw the stroke.
// Note: your shape will not be visible until you call any of the two methods.
context.fill();
context.stroke();
context.closePath();
// Set position of markings (spans)
$('span.markings.A').css({
'top' : pts.AYLoc -30,
'left' : pts.AXLoc -5
});
$('span.markings.B').css({
'top' : pts.BYLoc -5,
'left' : pts.BXLoc +10
});
$('span.markings.C').css({
'top' : pts.CYLoc -5,
'left' : pts.CXLoc -25
});
// Write markings onto canvas (degrees and lengths)
$('span.markings.A').html('A');
$('span.markings.B').html('B');
$('span.markings.C').html('C');
}
function createContext(contextType)
{
// Get the canvas element.
var elem = document.getElementById('myCanvas');
if (!elem || !elem.getContext) {
return;
}
// Get the canvas 2d context.
context = elem.getContext(contextType);
if (!context) {
return;
}
}
});
You've got your angle formulas a little wrong. Here's a working fiddle: http://jsfiddle.net/manishie/AgmF4/.
Here are my corrected formulas:
vector.angleA = (Math.pow(vector.magB, 2) + Math.pow(vector.magC, 2) - Math.pow(vector.magA, 2)) / (2 * vector.magB * vector.magC);
vector.angleA = Math.acos(vector.angleA) * (180/Math.PI);
vector.angleB = (Math.pow(vector.magA, 2) + Math.pow(vector.magC, 2) - Math.pow(vector.magB, 2)) / (2 * vector.magA * vector.magC);
vector.angleB = Math.acos(vector.angleB) * (180/Math.PI);
vector.angleC = (Math.pow(vector.magA, 2) + Math.pow(vector.magB, 2) - Math.pow(vector.magC, 2)) / (2 * vector.magA * vector.magB);
vector.angleC = Math.acos(vector.angleC) * (180/Math.PI);
I implemented a small script to test requestAnimationFrame and it generates
"Uncaught RangeError: Maximum call stack size exceeded" error ..This is the code
<html>
<head>
<meta charset="utf-8">
<script>
window.onload=function(){
if (document.createElement("canvas").getContext){
//alert("browser supports canvas");
//console.log(document.getElementById("canvas").getContext);
canvas = document.getElementById("canvas");
shape = new shapes();
shape.drawball(canvas,5,"red");
}
};
function shapes(){
this.drawtriangle = function(canvas){
triangles = new triangle(0,0,0,200,200,200);
triangles.draw(canvas.getContext('2d'));
}
this.drawball = function(canvas,radius,color) {
ball = new Ball(radius,color);
ball.drawBall(canvas.getContext('2d'),canvas);
}
}
function coordinates(x1,y1){
this.x = x1;
this.y = y1;
}
function angle(angle){
this.angle = angle;
}
function Ball(radius,color){
this.origin = new coordinates(100,100);
this.radius = (radius === "undefined" ) ? 5 : radius;
this.color = (color === "undefined") ? red : color;
this.rotation = 0;
this.index = 0;
this.angles = new angle(0);
this.speed = 10;
}
Ball.prototype.drawBall = function (context,canvas){
context.fillStyle = this.color;
context.strokeStyle = "blue";
context.rotate(this.rotation);
context.beginPath();
context.arc(this.origin.x,this.origin.y,this.radius,0,(Math.PI*2),true);
context.closePath();
context.fill();
context.stroke(); this.animate(context,canvas);
}
Ball.prototype.animate = function (context,canvas){
var that = this;console.log(".......");
var time = new Date().getTime() * 0.002;
this.origin.x = Math.sin( time ) * 96 + 128;
this.origin.y = Math.cos( time * 0.9 ) * 96 + 128;
//context.clearRect(0,0,1000,1000);
console.log("Animating ... ");
this.origin.x = this.origin.x + this.speed;
this.origin.y = this.origin.y + this.speed;
this.angles.angle = this.angles.angle + this.speed;
window.webkitrequestAnimationFrame(that.drawBall(context,canvas));
}
</script>
<style>
body {
background-color: #bbb;
}
#canvas {
background-color: #fff;
}
</style>
</head>
<body>
<canvas id="canvas" width="1000px" height="1000px">
Your browser dows bot suppoet canvas
</canvas>
</body>
</html>
I got another code from the net and this works fine although it has recursion..
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>RequestAnimationFrame.js example</title>
</head>
<body>
<script >/**
* Provides requestAnimationFrame in a cross browser way.
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
*/
if ( !window.requestAnimationFrame ) {
window.requestAnimationFrame = ( function() {
return window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame || // comment out if FF4 is slow (it caps framerate at ~30fps: https://bugzilla.mozilla.org/show_bug.cgi?id=630127)
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
window.setTimeout( callback, 1000 / 60 );
};
} )();
}</script>
<script>
var canvas, context;
init();
animate();
function init() {
canvas = document.createElement( 'canvas' );
canvas.width = 256;
canvas.height = 256;
context = canvas.getContext( '2d' );
document.body.appendChild( canvas );
}
function animate() {
requestAnimationFrame( animate );
draw();
}
function draw() {
var time = new Date().getTime() * 0.002;
var x = Math.sin( time ) * 96 + 128;
var y = Math.cos( time * 0.9 ) * 96 + 128;
context.fillStyle = 'rgb(245,245,245)';
context.fillRect( 0, 0, 255, 255 );
context.fillStyle = 'rgb(255,0,0)';
context.beginPath();
context.arc( x, y, 10, 0, Math.PI * 2, true );
context.closePath();
context.fill();
}
</script>
<div style="width:256px">
view source<br /><br/>
requestAnimationFrame() allows modern browsers to stop drawing graphics when a tab or window is not visible. Improving overall performance and batteries on mobile devices.<br /><br />
RequestAnimationFrame.js emulates the basic usage for old browsers.
</div>
</body>
</html>
What may be causing this error and how do I fix it ?
Ball.animate calls Ball.drawBall and vice versa. So, before either finishes executing, they call each other until the "call stack" size exceeds its limit (causing the error).
Instead of
ball.drawBall(canvas.getContext('2d'),canvas);
try
setInterval(function () { ball.animate(canvas.getContext('2d'),canvas); }, 1000/60);
and remove
this.animate(context,canvas);
from Ball.prototype.drawBall
There are many, many problems with your code, but that's the one you asked about.
I've explained the simple errors. My annotations are in /* */ comments. There are also formatting and style errors, which I've omitted.
<html>
<head>
<meta charset="utf-8">
<script>
window.onload=function(){
if (document.createElement("canvas").getContext){
//alert("browser supports canvas");
//console.log(document.getElementById("canvas").getContext);
canvas = document.getElementById("canvas");
shape = new shapes();
/* drawball should be called by a run() function, or similar */
shape.drawball(canvas,5,"red");
}
};
/**
* Is this supposed to be a singleton, or perhaps a module?
* otherwise, you should use prototype to define these methods
*/
function shapes(){
this.drawtriangle = function(canvas){
/* triangles isn't defined in this file? */
triangles = new triangle(0,0,0,200,200,200);
/* I'd store a reference to context as a property of the function (class)
* aka a "static variable" */
triangles.draw(canvas.getContext('2d'));
}
this.drawball = function(canvas,radius,color) {
ball = new Ball(radius,color);
/* same here */
ball.drawBall(canvas.getContext('2d'),canvas);
}
}
/**
* this is reasonable, but don't pluralize a class name unless you mean it
* I'd maybe call it "Point" or "Vec2d"
*/
function coordinates(x1,y1){
this.x = x1;
this.y = y1;
}
/* so you'd use this object as angle.angle?? Just store it as a scalar.*/
function angle(angle){
this.angle = angle;
}
/* This is correct, I'm sure it's also copy/pasted */
function Ball(radius,color){
this.origin = new coordinates(100,100);
this.radius = (radius === "undefined" ) ? 5 : radius;
this.color = (color === "undefined") ? red : color;
this.rotation = 0;
this.index = 0;
this.angles = new angle(0);
this.speed = 10;
}
/**
* Ball.drawBall()? I'd use Ball.draw()
* I'd again store context in the function object, and you don't need to
* pass canvas
*/
Ball.prototype.drawBall = function (context,canvas){
context.fillStyle = this.color;
context.strokeStyle = "blue";
context.rotate(this.rotation);
context.beginPath();
context.arc(this.origin.x,this.origin.y,this.radius,0,(Math.PI*2),true);
context.closePath();
context.fill();
context.stroke();
/* There is no reason to have your whole animation call here,
* there should only be code to _draw_ the _ball_ (like the function says) */
this.animate(context,canvas);
}
/* This makes sense for a singleton Ball, but in this case animate should be
* on a containing object. The Ball doesn't animate anything, the App does */
Ball.prototype.animate = function (context,canvas){
/* I can't explain this. I'm 99.999% sure it's not what you want. */
var that = this;console.log(".......");
var time = new Date().getTime() * 0.002;
this.origin.x = Math.sin( time ) * 96 + 128;
this.origin.y = Math.cos( time * 0.9 ) * 96 + 128;
//context.clearRect(0,0,1000,1000);
console.log("Animating ... ");
this.origin.x = this.origin.x + this.speed;
this.origin.y = this.origin.y + this.speed;
this.angles.angle = this.angles.angle + this.speed;
/* you complete your cycle here (animate calls drawBall and vice versa) */
window.webkitrequestAnimationFrame(that.drawBall(context,canvas));
}
</script>
<style>
body {
background-color: #bbb;
}
#canvas {
background-color: #fff;
}
</style>
</head>
<body>
<canvas id="canvas" width="1000px" height="1000px">
Your browser dows bot suppoet canvas
</canvas>
</body>
</html>
I want to animate a ball using html5 and i implemented this small script . However, I cannot see any animation .. How do I fix this ?
<html>
<head>
<meta charset="utf-8">
<script>
canvas = document.getElementById("canvas");
window.onload=function(){
if (document.createElement("canvas").getContext){
//alert("browser supports canvas");
//console.log(document.getElementById("canvas").getContext);
canvas = document.getElementById("canvas");
shape = new shapes();
shape.drawball(canvas,100,"red");
}
};
function shapes(){
this.drawtriangle = function(canvas){
triangles = new triangle(0,0,0,200,200,200);
triangles.draw(canvas.getContext('2d'));
}
this.drawball = function(canvas,radius,color) {
ball = new Ball(radius,color);
ball.draw(canvas.getContext('2d'),canvas);
}
}
function coordinates(x1,y1){
this.x = x1;
this.y = y1;
}
function angle(angle,speed){
this.angle = angle;
this.speed = speed;
}
function Ball(radius,color){
this.origin = new coordinates(100,100);
this.radius = (radius === "undefined" ) ? 40 : radius;
this.color = (color === "undefined") ? red : color;
this.rotation = 0;
this.index = 0;
this.angles = new angle(0,0.2);
}
Ball.prototype.draw = function(context,canvas){
context.fillStyle = this.color;
context.strokeStyle = "blue";
context.rotate(this.rotation);
context.beginPath();
context.arc(this.origin.x,this.origin.y,this.radius,0,(Math.PI*2),true)
context.closePath();
context.fill();
context.stroke();
this.animate(context,canvas);
}
Ball.prototype.animate = function(context,canvas){
if (this.angles.angle < 1){
context.clearRect(0,0,1000,1000);
console.log("Animating ... ");
this.origin.x = this.origin.x + 10;
this.origin.y = this.origin.y + 10;
this.angles.angle = this.angles.angle + this.angles.speed;
window.requestAnimationFrame(this.draw(context));
}
}
</script>
<style>
body {
background-color: #bbb;
}
#canvas {
background-color: #fff;
}
</style>
</head>
<body>
<canvas id="canvas" width="1000px" height="1000px">
Your browser dows bot suppoet canvas
</canvas>
</body>
</html>
Your call to requestAnimationFrame() is not passing a callback, it's executing a function and passing its return value which is undefined. I would suggest you change this:
Ball.prototype.animate = function(context,canvas) {
if (this.angles.angle < 1) {
context.clearRect(0,0,1000,1000);
console.log("Animating ... ");
this.origin.x = this.origin.x + 10;
this.origin.y = this.origin.y + 10;
this.angles.angle = this.angles.angle + this.angles.speed;
window.requestAnimationFrame(this.draw(context));
}
}
to this:
Ball.prototype.animate = function(context,canvas) {
if (this.angles.angle < 1) {
context.clearRect(0,0,1000,1000);
console.log("Animating ... ");
this.origin.x = this.origin.x + 10;
this.origin.y = this.origin.y + 10;
this.angles.angle = this.angles.angle + this.angles.speed;
var self = this;
window.requestAnimationFrame(function() {self.draw(context)});
}
}
so that you pass an appropriate callback function to requestAnimationFrame().
Now that you've included all the code, here is another issue. You can't do this:
canvas = document.getElementById("canvas");
in javascript in the head tag because the DOM is not yet loaded so it will not find that object. You must do that only when the DOM has been loaded either by waiting for an event that signifies the DOM has been loaded or by running the javascript at the every end of the <body> section AFTER all DOM elements.
Then, thirdly, you have to use the browser-specific form of requestAnimationFrame since each browser may have it's own prefix. I used this code:
var reqestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.webkitRequestAnimationFrame;
When I put your script into a jsFiddle and make the above changes, what I find is that the animation runs so quickly that it isn't seen. Your code will need to add a time element to it so that the animation runs over a particular time period. Usually this is done by defining a duration for the animation and at each animation step, you scale the position of the animation based on what percentage of the duration has elapsed.
Here's an example of a time-based animation using requestAnimationFrame: http://jsfiddle.net/jfriend00/nRE7S/