Why doesn't this For loop work in Canvas? - javascript

I was trying to get the canvas to display the i in a loop - I want the i to be changing just like the counting t, from 1-9 non-stop. I just couldn't figure out what's wrong. The javascript looks like this:
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){window.setTimeout(callback, 1000/60)};
})();
var cvs = document.getElementById("canvasId"),
c = cvs.getContext("2d"),
t = 0;
window.onload=function loop(){
window.requestAnimFrame(loop);
t++;
for(i=0;i<10;i++){
c.clearRect(0,0,cvs.width,cvs.height);
c.font = "bold 90px Arial";
c.fillText(i + " " + t, 100, 200);
}
};
http://jsfiddle.net/luxiyalu/9UZU5/
This is part of a mini game and I've been stuck in here for 2 days; if anyone could tell me what's wrong with it... Thanks a lot!

As you're iterating i from 0 to 9 in your drawing function, there is no time left between two drawings and the user can only see the last iteration value, that is 9.
I'm not sure of what you really want to achieve but it looks like you want this :
var cvs = document.getElementById("canvasId"),
c = cvs.getContext("2d"),
t = 0,
i = 0;
window.onload = function loop(){
window.requestAnimFrame(loop);
i++;
if (i==10) {
i = 0;
t++;
}
c.clearRect(0,0,cvs.width,cvs.height);
c.font = "bold 90px Arial";
c.fillText(i + " " + t, 100, 200);
};
Demonstration

Related

Reuse canvas shape instead of writing same code many times

I am currently learning canvas and if I wanted to store my shape and create lets say 4 of them but position them at different locations or with different colors how would I do that?
http://jsfiddle.net/bp0bxgbz/50/
var x = 0;
var y = 15;
var speed = 5;
function animate() {
reqAnimFrame = window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame
;
reqAnimFrame(animate);
x += speed;
if(x <= 0 || x >= 475){
speed = -speed;
}
draw();
}
function draw() {
var canvas = document.getElementById("ex1");
var context = canvas.getContext("2d");
context.clearRect(0, 0, 500, 170);
context.beginPath();
context.moveTo(x,y);
context.lineTo(x + 105,y + 25);
context.lineTo(x+25,y+105);
context.fillStyle="red";
context.fill();
}
animate();
Create 4 objects--one for each triangle.
Each object holds the current x,y position and the current speed for its 1 triangle.
You can use the information inside any 1 object in the draw() function to draw that 1 triangle at its current x,y position.
In the animation function you can use the information inside each of the 4 objects to change the x position of each triangle.
var shapes=[];
shapes.push({x:10,y:10,speed:2});
shapes.push({x:10,y:125,speed:4});
shapes.push({x:10,y:250,speed:6});
shapes.push({x:10,y:375,speed:8});
In the animation loop, iterate through the array and draw each of the 4 objects by feeding them individually into the draw function.
context.clearRect(0, 0, 500, 170);
for(var i=0; i<shapes.length;i++){
var s=shapes[i];
s.x+=s.speed;
if(s.x <= 0 || s.x >= 475){
s.speed*=-1;
}
draw(s);
}
The draw function should take the specified object and draw according to its specified x,y & speed values.
// create canvas & context variables once at the beginning of the script
var canvas = document.getElementById("ex1");
var context = canvas.getContext("2d");
function draw(s) {
context.beginPath();
context.moveTo(s.x,s.y);
context.lineTo(s.x + 105,s.y + 25);
context.lineTo(s.x+25,s.y+105);
context.fillStyle="red";
context.fill();
}
Note: you can create the canvas & context variables once at the beginning of your script. No need to recreate those variables with each call to draw. Also, if all the drawings will be red-filled, then you could set that once at the beginning of the script, too.
Example code and a Demo:
var context=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var shapes=[];
shapes.push({x:10,y:10,speed:2,color:'red'});
shapes.push({x:10,y:125,speed:4,color:'green'});
shapes.push({x:10,y:250,speed:6,color:'blue'});
shapes.push({x:10,y:375,speed:8,color:'gold'});
animate();
function animate(){
context.clearRect(0,0,cw,ch);
for(var i=0; i<shapes.length;i++){
var s=shapes[i];
s.x+=s.speed;
if(s.x <= 0 || s.x >= cw){
s.speed*=-1;
}
draw(s);
}
requestAnimationFrame(animate);
}
function draw(s) {
context.beginPath();
context.moveTo(s.x,s.y);
context.lineTo(s.x + 105,s.y + 25);
context.lineTo(s.x+25,s.y+105);
context.fillStyle=s.color
context.fill();
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=450></canvas>

Html 5 Rotate image inside the Canvas

I need to rotate an image inside an canvas..I have googled and saw similar questions in stackoverflow.What i learnt is
I cannot rotate single object inside canvas.
I can rotate only thewhole canvas.
So i need to translate to center of the object and then rotate the
canvas.
I Followed exactly same stuffs , But i am struck at translating to the image center..Below is the code i am using.Here is the jsfiddle http://jsfiddle.net/J6Pfa/1/. This one is rotating the whole canvas regardless image..some one guide me where i am wrong.Thanks
//hero canvas
ball = new Hero();
var ang = 0;
herocanvas = document.createElement("canvas");
herocanvas.width = herocanvas.width = 500;
herocanvas.height = herocanvas.height = 500;
heroctx = herocanvas.getContext('2d');
document.body.appendChild(herocanvas);
var requestAnimFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame;
var imgSprite = new Image();
imgSprite.src = 'http://i.imgur.com/WTgOHGg.png';
imgSprite.addEventListener('load',init,false);
function init()
{
startloop();
}
function startloop()
{
heroctx.save(); //saves the state of canvas
clearherobg() ; // clear canvas
heroctx.translate(ball.drawX, ball.drawY); //let's translate
heroctx.rotate(Math.PI / 180 * (ang += 4));
ball.draw(); // draw image here
heroctx.restore();
requestAnimFrame(startloop);
}
function Hero() {
this.srcX = 0;
this.srcY = 500;
this.drawX = 220;
this.drawY = 200;
this.width = 100;
this.height = 40;
this.speed = 5;
this.isUpKey = false;
this.isRightKey = false;
this.isDownKey = false;
this.isLeftKey = false;
}
Hero.prototype.draw = function () {
heroctx.drawImage(imgSprite,this.srcX,this.srcY,this.width,this.height,this.drawX,this.drawY,this.width,this.height);
};
function clearherobg() {
heroctx.clearRect(0,0,500,500);
}
Those who cannot read full code ..Please check startloop() , thats the main infinite loop..ball.drawX and ball.drawY are the x and y position of image inside canvas
Hero's drawX and drawY need to be updated to new coordinate system of canvas, if u want it to be in the middle of canvas it needs to be 0,0.
Something like this: jsfiddle.net/J6Pfa/3
Hm, i dont exactly understand what you want to achieve, an image moving on the circle path ? or having image in one place, and just rotate it ?

Baddly drawn canvas

I would like to draw a line starting on a given point and crossing two other points. To do this, I get the x and y coordinates of these points, and then I drawn. This is what my code should do :
JS:
function getPosition(element)
{
var left = 0;
var top = 0;
var e = document.getElementById(element);
while (e.offsetParent != undefined && e.offsetParent != null)
{
left += e.offsetLeft + (e.clientLeft != null ? e.clientLeft : 0);
top += e.offsetTop + (e.clientTop != null ? e.clientTop : 0);
e = e.offsetParent;
}
return new Array(left,top);
}
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var point1 = getPosition('firstGalaxy');
var point2 = getPosition('secondGalaxy');
var point3 = getPosition('lastGalaxy');
console.log(point1);
console.log(point2);
console.log(point3);
ctx.beginPath();
ctx.moveTo(point1[0], point1[1]);
ctx.lineTo(point2[0], point2[1]);
ctx.lineTo(point3[0], point3[1]);
ctx.stroke(2);
ctx.closePath();
HTML:
<canvas id="myCanvas" style="position:absolute;" class="constellation">
The values printed in my console seems to be good, but the result is a mess.
Here is a picture of the result
The grey square on the right is the result, and the red line is what I would like to get.
I don't even know why I get a square because I am using "stroke()".
Can anyone tell me what is wrong with my code?
Change ctx.stroke(2) to ctx.stroke(), add ctx.strokeStyle="red" to change the line's color. And, add </canvas> to the HTML.
HTML:
<canvas id="myCanvas" style="position:absolute;" class="constellation"></canvas>
Javascript:
function getPosition(element)
{
var left = 0;
var top = 0;
var e = document.getElementById(element);
while (e.offsetParent != undefined && e.offsetParent != null)
{
left += e.offsetLeft + (e.clientLeft != null ? e.clientLeft : 0);
top += e.offsetTop + (e.clientTop != null ? e.clientTop : 0);
e = e.offsetParent;
}
return new Array(left,top);
}
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var point1 = getPosition('firstGalaxy');
var point2 = getPosition('secondGalaxy');
var point3 = getPosition('lastGalaxy');
console.log(point1);
console.log(point2);
console.log(point3);
ctx.beginPath();
ctx.moveTo(point1[0], point1[1]);
ctx.lineTo(point2[0], point2[1]);
ctx.lineTo(point3[0], point3[1]);
ctx.strokeStyle="red";
ctx.stroke();
ctx.closePath();
A few directions :
1) to debug, be sure your points are at the right place by drawing them using something like :
function drawPoint(ctx, pt, color, pointSize ) {
ctx.fillStyle = color || '#F88';
var pointSize = pointSize || 2;
var x = pt[0], y=pt[1];
ctx.fillRect(x - pointSize/2, y-pointSize/2, pointSize, pointSize);
}
2) use getBoundingClientRect to retrieve a control position with maximum reliability.
function getPosition(element, provideCenter)
{
var elementBoundingRect = element.getBoundingClientRect();
var point = [elementBoundingRect.left, elementBoundingRect.top];
if (provideCenter) {
point[0] += (elementBoundingRect.right - elementBoundingRect.left) /2;
point[1] += (elementBoundingRect.bottom - elementBoundingRect.top ) /2;
}
return point;
}
3) Be sure the canvas covers all the screen and do simple unit tests on various parts of the screen using getPosition and drawPoint on several visible html items.
Edit : The code provided in 1) is good. If in doubt, look at this test here :
http://jsbin.com/aDimoJI/1/
You must be able to draw points anywhere before going anywhere further.
Be sure your canvas is on top of everything else for this test, so you'll have to handle this issue...

Measure how many times iOS can draw per frame

I am trying to benchmark how many times iOS natively can draw between frame refresh compared to HTML5/JavaScript.
Using this JavaScript I get a number for how may times the browser can draw during the 33 ms (30 Hz):
var ctx = document.getElementById('canvas').getContext('2d');
var img = document.getElementById('img');
var draw = function(load) {
var angle = 0.01;
ctx.clearRect(0,0,400,400);
ctx.save();
ctx.translate(200,200);
for (var i=0; i<load; i++) {
ctx.rotate(angle);
ctx.drawImage(img, 0, 0);
}
ctx.restore();
};
var t, previousTime;
var drawLoad = 1;
var slowCount = 0;
var maxSlow = 10;
var requestAnimationFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame;
t = previousTime = Date.now();
var tick = function() {
var maximumFrameTime = 1000/30; // 30 FPS
t = Date.now();
var elapsed = t - previousTime;
previousTime = t;
if (elapsed < maximumFrameTime || slowCount < maxSlow) {
if (elapsed < maximumFrameTime) {
drawLoad+=10;
} else {
slowCount++;
}
draw(drawLoad);
requestAnimationFrame(tick);
} else {
// found maximum sustainable load at 30 FPS
document.getElementById('res').innerHTML = ("could draw "+(drawLoad)+" in " + maximumFrameTime + " ms");
}
};
requestAnimationFrame(tick);
See http://jsfiddle.net/tbhZs/117/ for complete code with HTML-markup.
I have fiddled around in objective-c without finding a fair way to get a comparable number. Is there a way to produce a comparable benchmark natively in iOS?
Try instruments tool. you can measure the frames per socond via the core animation instrument.

Waiting animation with html5 canvas

I am trying to implement a wating animation of the kind mentioned in this question, particularly something that looks like this:
But I do not want to use graphic files, and am trying to implement it purely in html5 canvas and javascript. Also, I want a circular black background rather than a square one. As a first step, I tried to draw a static frame (without any movement/rotation) and did this:
<html>
<head><script>
window.onload = function(){
var c=document.getElementById("waiting").getContext("2d");
c.lineCap="round";
c.fillStyle="#353535";
c.translate(100,100);
function slit(p){
shade = 256*p;
th = 2*Math.PI*p;
cos = Math.cos(th);
sin = Math.sin(th);
c.strokeStyle = '#'+((shade<<16)+(shade<<8)+shade).toString(16);
c.moveTo(55*cos, 55*sin);
c.lineTo(84*cos, 84*sin);
c.stroke();
c.closePath();
}
c.lineWidth=0;
c.arc(0,0,100,0,Math.PI*2);
c.fill();
c.lineWidth=7;
for(var i = 0;i<1;i+=0.05){slit(i);}
}
</script></head>
<body><canvas id="waiting" width=200 height=200></canvas></body>
</html>
The result I get is:
The problem is that, the lineCap="round" is not working correctly for all of the "slits", and the lineWidth=0 attribute is not working for the edge of the circle. What am I doing wrong? I checked it with Chrome 16.0.912.63 and Firefox 10.0, and got similar results.
For the next step, I am going to let parts of the functions that I created above interact with
window.animationFrames = (function(callback){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){window.setTimeout(callback, 1000 / 60);};
})();
but for the time being, I need to solve this problem first.
There's a bit of confusion here.
Zero is not an acceptable value for line width. The spec dictates that if you say lineWidth = 0 that it will be a no-op.
Furthermore you are not using lineWidth there because you are not stroking. fill() does not take line width into account.
As for the other issue, all you have to do is call beginPath! See here:
http://jsfiddle.net/JfcDL/
Just adding the beginPath call and you'll get this with your code:
What you were doing incorrectly was drawing the entire path so far with every new stroke(). You need to call beginPath to open a new one so that the stroke only applies to the last part and not all the parts made so far.
Thanks to the help by the several people here, I finally came up with this code, which works fully with the movement:
<html>
<head><script>
var r1 = 400;
var r2 = 340;
var r3 = 220;
var slitWidth = 40;
var speed = 0.0004;
var attenuation = 1.7;
function rgbToHex(r, g, b){
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
window.nextFrame = (function(callback){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){window.setTimeout(callback, 1000 / 60);};
})();
window.onload = function(){
var waiting=document.getElementById('waiting').getContext('2d');
function slit(d,p){
shade = Math.round(Math.pow(1-(d+p)%1, attenuation)*255)
th = Math.PI*2*(p);
cos = Math.cos(th);
sin = Math.sin(th);
waiting.strokeStyle = rgbToHex(shade, shade, shade);
waiting.beginPath();
waiting.moveTo(r2*cos, r2*sin);
waiting.lineTo(r3*cos, r3*sin);
waiting.stroke();
waiting.closePath();
}
function frame(){
waiting.arc(0,0,r1,0,Math.PI*2);
waiting.fill();
var time = new Date().getTime()* speed;
for(var p = 1;p>0;p-=0.05){slit(time,p);}
nextFrame(function(){frame();});
}
waiting.lineCap='round';
waiting.lineWidth=slitWidth;
waiting.fillStyle='#353535';
waiting.translate(r1, r1);
frame();
}
</script></head>
<body><canvas id='waiting' width=800 height=800></canvas></body>
</html>

Categories

Resources