Canvas Object flickering - javascript

I have eyesore flickering in my canvas animation. I have no idea what causes the flicker and the Google is not offering help on the transition global element I added to my text. On separate canvases, they work fine. It's only when I add them to the main code do I run into the flicker.
var canvas,
context,
ox = 60,
oy = 60,
ux = Math.random(),
uy = Math.random();
var drops = [];
var squares = [];
var clouds = [];
var text, step = 190, steps = 255;
delay = 180;
var rgbstep = 120;
function Drop(x,y,color){
this.x = x;
this.y = y;
this.color = color;
this.dy = Math.random();
}
function Square(x,y,w,color){
this.sx = x;
this.sy = y;
this.sw = w;
this.color = color;
this.qy = Math.random();
}
function init(){
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
//alert("Hello!\nClick on the screen for rain drops!");
window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('orientationchange', resizeCanvas, false);
resizeCanvas()
Textfadeup();
canvas.onclick = function(event){
handleClick(event.clientX, event.clientY);
};
setInterval(handleClick,50);
setInterval(draw, 1);
}
addEventListener("keydown", function(event) {
if (event.keyCode == 32)
document.body.style.background = "yellow";
});
addEventListener("keyup", function(event) {
if (event.keyCode == 32)
document.body.style.background = "";
});
function handleClick(x,y,w){
var found = false;
for(var i = 0; i<drops.length; i++){
d = Math.sqrt((drops[i].x-x)*(drops[i].x-x) + (drops[i].y-y)*(drops[i].y-y));
if(d<=5){
drops.splice(i,1);
found = true;
}
}
fillBackgroundColor();
if(!found){
var colors = ["#000080", "#add8e6", "blue"];
var color = colors[Math.floor(Math.random()*colors.length)];
drops.push(new Drop(x,y,color));
squares.push(new Square(x,y,w,color));
}
for(var i = 0; i<drops.length; i++){
drawDrop(drops[i]);
}
for(var i = 0; i<squares.length; i++){
drawSquare(squares[i]);
}
}
function Textfadeup() {
rgbstep++;
//context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "rgb(" + rgbstep + "," + rgbstep + "," + rgbstep + ")"
context.fillText("Drip, drip, drop, little April shower...", 500, canvas.height);
context.font= "40px Arial";
if (rgbstep < 255)
var t = setTimeout('Textfadeup()', 10);
if (rgbstep == 255) {
Textfadedown();
}
}
function Textfadedown() {
rgbstep=rgbstep-1;
// context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "rgb(" + rgbstep + "," + rgbstep + "," + rgbstep + ")"
context.fillText("Drip, drip, drop, little April shower...", 500, canvas.height);
context.font= "40px Arial";
if (rgbstep > 30)
var t = setTimeout('Textfadedown()', 10);
if (rgbstep == 30) {
Textfadeup();
}
}
/* function drawDrop(drop){
context.beginPath();
context.moveTo(drop.x,drop.y);
context.lineTo(drop.x+10,drop.y+25);
context.lineTo(drop.x+13,drop.y+32);
context.lineTo(drop.x+46,drop.y+50);
context.lineTo(drop.x+72,drop.y+51);
context.lineTo(drop.x+81,drop.y+43);
context.lineTo(drop.x+104,drop.y+52);
context.lineTo(drop.x+111,drop.y+46);
context.lineTo(drop.x+83,drop.y+40);
context.lineTo(drop.x+75,drop.y+20);
context.lineTo(drop.x+57,drop.y+8);
context.closePath();
context.fillStyle = 'orange';
context.fill();
if (drop.y + drop.dy > canvas.height || drop.y + drop.dy < 0)
drop.dy != -drop.dy;
drop.y += drop.dy;
};
function drawDrop(drop){
context.beginPath();
context.moveTo(drop.x,drop.y);
context.beginPath();
context.moveTo(drop.x,drop.y);
context.lineTo(drop.x+24,drop.y);
context.lineTo(drop.x-2,drop.y+25);
context.lineTo(drop.x+17,drop.y+25);
context.lineTo(drop.x-18,drop.y+53);
context.lineTo(drop.x-3,drop.y+54);
context.lineTo(drop.x-47,drop.y+77);
context.lineTo(drop.x-31,drop.y+59);
context.lineTo(drop.x-40,drop.y+59);
context.moveTo(drop.x-40,drop.y+59);
context.moveTo(drop.x-14,drop.y+33);
context.lineTo(drop.x-30,drop.y+32);
context.closePath();
context.fillStyle = 'yellow';
context.fill();
if (drop.y + drop.dy > canvas.height || drop.y + drop.dy < 0)
drop.dy != -drop.dy;
drop.y += drop.dy;
};*/
function drawDrop(drop){
context.beginPath();
context.arc(drop.x, drop.y, 5, 0, Math.PI);
context.fillStyle = drop.color;
context.moveTo(drop.x - 5, drop.y);
context.lineTo(drop.x, drop.y - 7);
context.lineTo(drop.x + 5, drop.y);
context.closePath();
context.fill();
if (drop.y + drop.dy > canvas.height || drop.y + drop.dy < 0)
drop.dy != -drop.dy;
drop.y += drop.dy;
};
function drawSquare(square){
var sw = Math.floor(4);
var sx = Math.floor(Math.random() * canvas.width);
var sy = Math.floor(Math.random() * canvas.height);
context.beginPath();
context.rect(sx, sy, sw, sw);
context.fillStyle = '#add8e6';
context.fill();
};
function drawCloud(ox,oy) {
context.beginPath();
context.moveTo(ox,oy);
context.bezierCurveTo(ox-40, oy+20, ox-40, oy+70, ox+60, oy+70);
context.bezierCurveTo(ox+80, oy+100, ox+150, oy+100, ox+170, oy+70);
context.bezierCurveTo(ox+250, oy+70, ox+250, oy+50, ox+220, oy+20);
context.bezierCurveTo(ox+260, oy-40, ox+200, oy-50, ox+170, oy-30);
context.bezierCurveTo(ox+150, oy-75, ox+80, oy-10, ox+170, oy+5);
context.bezierCurveTo(ox+30, oy-75, ox-20, oy-60, ox, oy);
context.closePath();
context.fillStyle = 'white';
context.fill();
};
function fillBackgroundColor(){
context.fillStyle = 'gray';
context.fillRect(0,0,canvas.width,canvas.height);
}
function resizeCanvas(){
canvas.width = window.innerWidth - 20;
canvas.height = window.innerHeight - 20;
for(var i = 0; i<drops.length; i++){
drawDrop(drops[i]);
}
for(var i = 0; i<squares.length; i++){
drawSquare(squares[i]);
}
}
function draw() {
drawCloud(ox, oy, 500);
if (ox + ux > canvas.width || ox + ux < 0)
ux = -ux;
if (oy + uy > canvas.height || oy + uy < 0)
uy = -uy;
ox += ux;
}
function degreesToRadians(degrees) {
return (degrees * Math.PI)/180;
}
window.onload = init;
</script>
<body>
<canvas id='canvas' width=500 height=500></canvas>
</body>

You should not use setInterval to render to the canvas. You have set the time to 10 which is quicker than the screen refresh rate. There is no easy fix to your code as it's a little convoluted.
What you need to do is set up a main loop. From that function you do everything you need to do per animation frame. At the end of that function you use window.requestAnimationFrame(mainLoop) to request the next frame. It syncs the animation with the display refresh rate and stops the flicker.
Example
function mainLoop(){
drawCloud(); // draw your cloud
// other stuff did not get a chance to see what else you did.
// request the next animation frame that should occur in 1/60th of a second.
requestAnimationFrame(mainLoop);
}
To start it all call mainLoop from the init function
mainLoop(); // starts it all happening
You should NEVER use setInterval for anything but very short simple functions or long time periods. It caused your jsFiddle to crash the tab each time I looked.

Related

switch color (context.fillStyle) when drawing circles with <canvas>

I found the codes on codepen and modified as follow:
<canvas id="heatmap" width=300 height=150></canvas>
var canvas;
var context;
var screenH;
var screenW;
var circles = [];
var numcircles = 30;
$('document').ready(function() {
canvas = $('#heatmap');
screenH = canvas.height();
screenW = canvas.width();
canvas.attr('height', screenH);
canvas.attr('width', screenW);
context = canvas[0].getContext('2d');
for(var i = 0; i < numcircles; i++) {
var x = Math.round( Math.random() * screenW);
var y = Math.round( Math.random() * screenH);
var opacity = Math.random();
var circle = new Circle(x, y, opacity);
circles.push(circle);
}
drawCircles();
});
function drawCircles() {
var i = 0, me = this;
if (!circles.length) return;
(function loop() {
var circle = circles[i++];
circle.draw(context);
if (i < circles.length)
setTimeout(loop, 16);
})();
}
function Circle(x, y, opacity) {
this.x = parseInt(x);
this.y = parseInt(y);
this.opacity = opacity;
}
Circle.prototype.draw = function(){
context.save();
context.translate(this.x, this.y);
context.beginPath()
context.arc(0,0,Math.floor(Math.random() * (40 - 10) / 10) * 10 + 10,0,2*Math.PI);
context.closePath();
context.fillStyle = "rgba(25, 35, 50, " + this.opacity + ")";
context.shadowBlur = 5;
context.shadowColor = '#ffffff';
context.fill();
context.restore();
}
So I have 30 cirlces now. I like to have last 5 circles as red color.(25 as blue, 5 red)
context.fillStyle = "rgba(190, 60, 80, " + this.opacity + ")";
What is the best practice to achieve the goal?
There is never a best way to do anything. When you are pushing the circles you can just send in the style there instead just the opacity.
var circle = new Circle(x, y, i + 6 > numcircles ? "rgba(190, 60, 80, " + opacity + ")" : "rgba(25, 35, 50, " + opacity + ")");
var canvas;
var context;
var screenH;
var screenW;
var circles = [];
var numcircles = 30;
$('document').ready(function() {
canvas = $('#heatmap');
screenH = canvas.height();
screenW = canvas.width();
canvas.attr('height', screenH);
canvas.attr('width', screenW);
context = canvas[0].getContext('2d');
for (var i = 0; i < numcircles; i++) {
var x = Math.round(Math.random() * screenW);
var y = Math.round(Math.random() * screenH);
var opacity = Math.random();
var circle = new Circle(x, y, i + 6 > numcircles ? "rgba(190, 60, 80, " + opacity + ")" : "rgba(25, 35, 50, " + opacity + ")");
circles.push(circle);
}
drawCircles();
});
function drawCircles() {
var i = 0,
me = this;
if (!circles.length) return;
(function loop() {
var circle = circles[i++];
circle.draw(context);
if (i < circles.length)
setTimeout(loop, 16);
})();
}
function Circle(x, y, style) {
this.x = parseInt(x);
this.y = parseInt(y);
this.style = style;
}
Circle.prototype.draw = function() {
context.save();
context.translate(this.x, this.y);
context.beginPath()
context.arc(0, 0, Math.floor(Math.random() * (40 - 10) / 10) * 10 + 10, 0, 2 * Math.PI);
context.closePath();
context.fillStyle = this.style;
context.shadowBlur = 5;
context.shadowColor = '#ffffff';
context.fill();
context.restore();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id=heatmap width=300 height=150></canvas>
Start by modifying the Circle method so it accepts a color.
Then use that color, if set, in the draw function.
Now you can do new Circle(x, y, opacity, color); where the last argument is an optional color
var canvas;
var context;
var screenH;
var screenW;
var circles = [];
var numcircles = 30;
$(document).ready(function() {
canvas = $('#heatmap');
screenH = canvas.height();
screenW = canvas.width();
canvas.attr('height', screenH);
canvas.attr('width', screenW);
context = canvas[0].getContext('2d');
for (var i = 0; i < numcircles; i++) {
var x = Math.round(Math.random() * screenW);
var y = Math.round(Math.random() * screenH);
var opacity = Math.random();
var color = i > 24 ? '255,0,0' : null; // CHANGE COLOR AFTER 24 (RGB for red)
var circle = new Circle(x, y, opacity, color);
circles.push(circle);
}
drawCircles();
});
function drawCircles() {
var i = 0,
me = this;
if (!circles.length) return;
(function loop() {
var circle = circles[i++];
circle.draw(context);
if (i < circles.length)
setTimeout(loop, 16);
})();
}
function Circle(x, y, opacity, color) { // add color argument
this.x = parseInt(x);
this.y = parseInt(y);
this.opacity = opacity;
this.color = color; // set color
}
Circle.prototype.draw = function(color) {
context.save();
context.translate(this.x, this.y);
context.beginPath()
context.arc(0, 0, Math.floor(Math.random() * (40 - 10) / 10) * 10 + 10, 0, 2 * Math.PI);
context.closePath();
/* use color, if set*/
context.fillStyle = 'rgba(' + (this.color || '25, 35, 50') + ", " + this.opacity + ")";
context.shadowBlur = 5;
context.shadowColor = '#ffffff';
context.fill();
context.restore();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="heatmap" width="600" height="400"></canvas>

How do I properly introduce a delay after a drawImage function in an html5 canvas game?

I'm making a simple memory game and I have put a short delay after 2 cards have been flipped face up and before they are checked for a match. If they are unmatched they will then flip back face down. The problem I'm having is that the delay comes before the second card is flipped face up even though it comes afterwards in the code, resulting in the second card not showing face up. I'm using the drawImage function with pre-loaded images so the call shouldn't have to wait for an image to load. I've added my code below and commented after the draw face up and delay functions.
An online version: http://dtc-wsuv.org/mscoggins/hiragana/seindex.html
var ROWS = 2;
var COLS = 3;
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
canvas.width = COLS * 80 + (COLS - 1) * 10 + 40;
canvas.height = ROWS * 100 + (ROWS - 1) * 10 + 40;
var Card = function(x, y, img) {
this.x = x;
this.y = y;
this.w = 80;
this.h = 100;
this.r = 10;
this.img = img;
this.match = false;
};
Card.prototype.drawFaceDown = function() {
this.drawCardBG();
ctx.beginPath();
ctx.fillStyle = "red";
ctx.arc(this.w / 2 + this.x, this.h / 2 + this.y, 15, 0, 2 * Math.PI);
ctx.fill();
ctx.closePath();
this.isFaceUp = false;
};
Card.prototype.drawFaceUp = function() {
this.drawCardBG();
var imgW = 57;
var imgH = 70;
var imgX = this.x + (this.w - imgW) / 2;
var imgY = this.y + (this.h - imgH) / 2;
ctx.drawImage(this.img, imgX, imgY, imgW, imgH);
this.isFaceUp = true;
};
Card.prototype.drawCardBG = function() {
ctx.beginPath();
ctx.fillStyle = "white";
ctx.fillRect(this.x, this.y, this.w, this.h);
ctx.closePath();
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
ctx.moveTo(this.x + this.r, this.y);
ctx.lineTo(this.w + this.x - this.r * 2, this.y);
ctx.arcTo(this.w + this.x, this.y, this.w + this.x, this.y + this.r, this.r);
ctx.lineTo(this.w + this.x, this.h + this.y - this.r * 2);
ctx.arcTo(this.w + this.x, this.h + this.y, this.w + this.x - this.r, this.h + this.y, this.r);
ctx.lineTo(this.x + this.r, this.h + this.y);
ctx.arcTo(this.x, this.h + this.y, this.x, this.h + this.y - this.r, this.r);
ctx.lineTo(this.x, this.y + this.r);
ctx.arcTo(this.x, this.y, this.x + this.r, this.y, this.r);
ctx.stroke();
ctx.closePath();
};
Card.prototype.mouseOverCard = function(x, y) {
return x >= this.x && x <= this.x + this.w && y >= this.y && y <= this.y + this.h;
};
var imgLib = [
'img/a.png', 'img/ka.png', 'img/sa.png', 'img/ta.png', 'img/na.png', 'img/ha.png',
'img/ma.png', 'img/ya.png', 'img/ra.png', 'img/wa.png', 'img/i.png', 'img/ki.png',
'img/shi.png', 'img/chi.png', 'img/ni.png', 'img/hi.png', 'img/mi.png', 'img/ri.png',
'img/u.png', 'img/ku.png', 'img/su.png', 'img/tsu.png', 'img/nu.png', 'img/hu.png',
'img/mu.png', 'img/yu.png', 'img/ru.png', 'img/n.png', 'img/e.png', 'img/ke.png',
'img/se.png', 'img/te.png', 'img/ne.png', 'img/he.png', 'img/me.png', 'img/re.png',
'img/o.png', 'img/ko.png', 'img/so.png', 'img/to.png', 'img/no.png', 'img/ho.png',
'img/mo.png', 'img/yo.png', 'img/ro.png', 'img/wo.png'
];
var imgArray = [];
imgArray = imgLib.slice();
var flippedCards = [];
var numTries = 0;
var doneLoading = function() {};
canvas.addEventListener("click", function(e) {
for(var i = 0;i < cards.length;i++) {
var mouseX = e.clientX - e.currentTarget.offsetLeft;
var mouseY = e.clientY - e.currentTarget.offsetTop;
if(cards[i].mouseOverCard(mouseX, mouseY)) {
if(flippedCards.length < 2 && !this.isFaceUp) {
cards[i].drawFaceUp(); //draw card face up
flippedCards.push(cards[i]);
if(flippedCards.length === 2) {
numTries++;
if(flippedCards[0].img.src === flippedCards[1].img.src) {
flippedCards[0].match = true;
flippedCards[1].match = true;
}
delay(600); //delay after image has been drawn
checkMatches();
}
}
}
}
var foundAllMatches = true;
for(var i = 0;i < cards.length;i++) {
foundAllMatches = foundAllMatches && cards[i].match;
}
if(foundAllMatches) {
var winText = "You Win!";
var textWidth = ctx.measureText(winText).width;
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "red";
ctx.font = "40px Arial";
ctx.fillText(winText, canvas.width / 2 - textWidth, canvas.height / 2);
}
}, false);
var gameImages = [];
for(var i = 0;i < ROWS * COLS / 2;i++) {
var imgId = Math.floor(Math.random() * imgArray.length);
var match = imgArray[imgId];
gameImages.push(match);
gameImages.push(match);
imgArray.splice(imgId, 1);
}
gameImages.sort(function() {
return 0.5 - Math.random();
});
var cards = [];
var loadedImages = [];
var index = 0;
var imgLoader = function(imgsToLoad, callback) {
for(var i = 0;i < imgsToLoad.length;i++) {
var img = new Image();
img.src = imgsToLoad[i];
loadedImages.push(img);
cards.push(new Card(0, 0, img));
img.onload = function() {
if(loadedImages.length >= imgsToLoad.length) {
callback();
}
};
}
for(var i = 0;i < COLS;i++) {
for(var j = 0;j < ROWS;j++) {
cards[index].x = i * 80 + i * 10 + 20;
cards[index].y = j * 100 + j * 10 + 20;
index++;
}
}
for(var i = 0;i < cards.length;i++) {
cards[i].drawFaceDown();
}
};
imgLoader(gameImages, doneLoading);
var checkMatches = function() {
for(var i = 0;i < cards.length;i++) {
if(!cards[i].match) {
cards[i].drawFaceDown();
}
}
flippedCards = [];
};
var delay = function(ms) {
var start = new Date().getTime();
var timer = false;
while(!timer) {
var now = new Date().getTime();
if(now - start > ms) {
timer = true;
}
}
};
The screen won't be refreshed until your function exits. The usual way to handle this is using setTimeout. Put the code that you want to run after the delay in a separate function and use setTimeout to call that function after the desired delay. Note that setTimeout will return immediately; the callback will be executed later.
I have implemented this below, just replace your click event listener code with the following:
canvas.addEventListener("click", function(e) {
for(var i = 0;i < cards.length;i++) {
var mouseX = e.clientX - e.currentTarget.offsetLeft;
var mouseY = e.clientY - e.currentTarget.offsetTop;
if(cards[i].mouseOverCard(mouseX, mouseY)) {
if(flippedCards.length < 2 && !this.isFaceUp) {
cards[i].drawFaceUp(); //draw card face up
flippedCards.push(cards[i]);
if(flippedCards.length === 2) {
numTries++;
if(flippedCards[0].img.src === flippedCards[1].img.src) {
flippedCards[0].match = true;
flippedCards[1].match = true;
}
//delay(600); //delay after image has been drawn
//checkMatches();
window.setTimeout(checkMatchesAndCompletion, 600);
}
}
}
}
function checkMatchesAndCompletion() {
checkMatches();
var foundAllMatches = true;
for(var i = 0;i < cards.length;i++) {
foundAllMatches = foundAllMatches && cards[i].match;
}
if(foundAllMatches) {
var winText = "You Win!";
var textWidth = ctx.measureText(winText).width;
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "red";
ctx.font = "40px Arial";
ctx.fillText(winText, canvas.width / 2 - textWidth, canvas.height / 2);
}
}
}, false);

HTML5 based game doesn't show up on browser?

Recently, i made a game on codepen.io called flappy bird an it was working fine there but when i tried to show it on my website it doesn't show up anything.
Can someone tell what's missing or what is the problem in my code.
here is the code ( sorry it's too long , i know but i need help ):
<html>
<head>
<style type="text/css">
#stage {
display:block;
border:solid 1px #000;
margin:auto;
}
body{
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background:#333;
}
</style>
<script type="text/javascript">
window.requestAnimationFrame = (function(){
return window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(cb){
return setTimeout(cb, 1000/60);
};
})()
var can = document.getElementById("stage"),
ctx = can.getContext('2d'),
wid = can.width,
hei = can.height,
player, floor, pillars, gravity, thrust, running,
rainbows, colider, score, gPat, pPat, trans, termVel, pillGap,
pillWid, pillSpace, speed, stars, high,
sprite = document.createElement("img");
sprite.src = "http://www.cutmypic.com/uploads/title85083782.png";
//sprite.src = "http://i.stack.imgur.com/Vy3qB.gif";
sprite.onload = function(){
sprite.style.height = 0;
loop();
};
sprite.width = 34;
sprite.height = 21;
document.body.appendChild(sprite);
function init() {
high = localStorage.getItem("high") || 0;
player = {
x: 1 / 3 * wid,
y: 2 / 5 * hei,
r: 13,
v: 0
};
speed = 2.5;
floor = 4 / 5 * hei;
pillars = [];
rainbows = [];
stars = [];
gravity = .30;
thrust = gravity * -21;
termVel = -thrust + 2;
running = false;
colider = false;
score = 0;
trans = 0;
pillGap = 135;
pillWid = 55;
pillSpace = pillWid*3;
pPat = ctx.createPattern((function(){
var can = document.createElement("canvas"),
ctx = can.getContext("2d");
can.width = 60;
can.height = 60;
["green", "green", "green",
"#3b5998", "green", "#3b5998"].forEach(function(color, i){
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(i*10, 0);
ctx.lineTo(i*10+10, 0);
ctx.lineTo(0, i*10+10);
ctx.lineTo(0, i*10);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(i*10, 60);
ctx.lineTo(i*10+10, 60);
ctx.lineTo(60, i*10+10);
ctx.lineTo(60, i*10);
ctx.closePath();
ctx.fill();
});
return can;
})(), "repeat");
gPat = ctx.createPattern((function(){
var can = document.createElement("canvas"),
ctx = can.getContext("2d");
can.width = 32;
can.height = 32;
ctx.save();
ctx.translate(16,16);
ctx.rotate(Math.PI/4);
ctx.fillStyle = "#79CDCD";
ctx.fillRect(-64,-64,128,128);
ctx.fillStyle = "#528B8B";
ctx.fillRect(-8,-64,8,128);
ctx.fillRect(14.5,-64,8,128);
ctx.restore();
return can;
})(), "repeat");
}
function render() {
trans -= speed;
rainbows = rainbows.filter(function(r){
r.x -= speed;
return r.x > -speed;
});
if (trans % speed === 0){
rainbows.push({x:player.x-10, y:player.y - (trans%50/25|0)*2 - 1});
}
stars = stars.filter(function(s){
trans % 10 || (s.r += 1);
s.x -= speed;
return s.x > -speed && s.r < 10;
});
if(trans % 20 === 0){
stars.push({
x: Math.round(Math.random()*(wid-50)+100),
y:Math.round(Math.random()*floor),
r:0
});
}
// backdrop
ctx.fillStyle = "#418bbc";
ctx.fillRect(0, 0, wid, hei);
//stars
ctx.fillStyle = "white";
stars.forEach(function (s){
ctx.fillRect(s.x, s.y - s.r-2, 2, s.r/2);
ctx.fillRect(s.x - s.r-2, s.y, s.r/2, 2);
ctx.fillRect(s.x, s.y+s.r + 2, 2, s.r/2);
ctx.fillRect(s.x+s.r + 2, s.y, s.r/2, 2);
ctx. fillRect(s.x + s.r, s.y + s.r, 2, 2);
ctx. fillRect(s.x - s.r, s.y - s.r, 2, 2);
ctx. fillRect(s.x + s.r, s.y - s.r, 2, 2);
ctx. fillRect(s.x - s.r, s.y + s.r, 2, 2);
});
//ground
ctx.fillStyle = "#2F4F4F";
ctx.fillRect(0, floor, wid, hei-floor);
ctx.save();
ctx.translate(trans, 0);
//pillars
ctx.fillStyle = pPat;
ctx.strokeStyle = "#ccc";
ctx.lineWidth = 2;
for (var i = 0; i < pillars.length; i++){
var pill = pillars[i];
ctx.fillRect(pill.x, pill.y, pill.w, pill.h);
ctx.strokeRect(pill.x, pill.y, pill.w, pill.h);
}
// stripe
ctx.fillStyle = gPat;
ctx.fillRect(-trans, floor+2, wid, 15);
ctx.restore();
//rainbowwwwws
rainbows.forEach(function(r){
["red","orange","blue","green","blue","indigo"].forEach(function(color, i){
ctx.fillStyle = color;
ctx.fillRect(r.x - speed, r.y-9 + i*3, speed+1, 3);
});
});
//player
ctx.save();
ctx.translate(player.x, player.y);
ctx.rotate(player.v*Math.PI/18);
ctx.drawImage(sprite, - 17, - 10);
ctx.restore();
ctx.fillStyle = "#97FFFF";
ctx.fillRect(0, floor, wid, 2);
ctx.fillStyle = "#2F4F4F";
ctx.fillRect(0, floor+1, wid, 1);
ctx.fillStyle = "#97FFFF";
ctx.fillRect(0, floor+17, wid, 2);
ctx.fillStyle = "#2F4F4F";
ctx.fillRect(0, floor+17, wid, 1);
//score
ctx.font = "bold 30px monospace";
var hScore = "best:" + (score > high ? score : high),
sWid = ctx.measureText(hScore).width,
sY = 50;
ctx.fillStyle = "black";
ctx.fillText(score, 12, floor + sY + 2);
ctx.fillText(hScore, wid - sWid - 10, floor + sY + 2);
ctx.fillStyle = "white";
ctx.fillText(score, 10, floor + sY);
ctx.fillText(hScore, wid - sWid - 12, floor + sY);
}
function adjust() {
if (trans%pillSpace === 0){
var h;
pillars.push({
x: -trans + wid,
y: 0,
w: pillWid,
h: (h = Math.random() * (floor - 300) + 100)
});
pillars.push({
x: -trans + wid,
y: h + pillGap,
w: pillWid,
h: floor - h - pillGap
});
}
pillars = pillars.filter(function(pill){
return -trans < pill.x + pill.w;
});
player.v += gravity;
if (player.v > termVel){
player.v = termVel;
}
player.y += player.v;
if (player.y < player.r) {
player.y = player.r;
player.v = 0;
}
for(var i = 0; i < pillars.length; i++){
var pill = pillars[i];
if (pill.x + trans < player.x + player.r &&
pill.x + pill.w + trans > player.x - player.r){
if (player.y - player.r > pill.y &&
player.y - player.r < pill.y + pill.h){
colider = true
running = false;
render();
break;
}
if (player.y + player.r < pill.y + pill.h &&
player.y + player.r > pill.y){
colider = true
running = false;
render();
break;
}
if (!pill.passed && i%2 == 1){
score++;
pill.passed = true;
}
}
}
if (player.y + player.r - player.v > floor) {
player.y = floor - player.r;
running = false;
colider = true;
render();
}
}
document.onmousedown = function () {
if (running) {
player.v = thrust;
} else if (!colider) {
running = true;
} else {
if (score > high){
localStorage.setItem("high", score);
}
init();
}
};
</script>
</head>
<body>
<canvas id="stage" width="400" height="600"></canvas>
</body>
Your calling document.getElementById('stage') before #stage exists in the DOM.
Javascript is run in the order that it is loaded into the page. So, you could either move the Javascript to the bottom of your HTML document, or us an onload event listener.
In detail, as the page loads, things at the top of the page are pulled in and parsed first. When a <script> tag is encountered, the browser automatically runs the Javascript immediately -- before it has reached the body of the page. Your CodePen was likely set to run the code after the page had loaded completely, but when you moved it all to it's own page you were now running it before load.

javascript - change speed of animation

I have a piece of code. But my problem is.. I have no idea where i can change the animation speed. I've tried to edit last line into animate('fast'); but without success..how can i solve it?
I know it is mainy javascript but so far I didnt find such code which will be better in jquery
$('#kim-jestesmy').waypoint(function(direction) {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var circles = [];
createCircle(100,100,'78', function() {
createCircle(270,100,'460', function() {
createCircle(440,100,'20', function() {
createCircle(610,100,'15', null);
});
});
});
function createCircle(x,y,text,callback) {
var radius = 75;
var endPercent = 101;
var curPerc = 0;
var counterClockwise = false;
var circ = Math.PI * 2;
var quart = Math.PI / 2;
context.lineWidth = 10;
context.strokeStyle = '#E60086';
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
function doText(context,x,y,text) {
context.lineWidth = 1;
context.fillStyle = "#919191";
context.lineStyle = "#919191";
context.font = "60px NillandBold";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText(text, x, y);
}
function animate(current) {
context.lineWidth = 10;
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.arc(x, y, radius, -(quart), ((circ) * current) - quart, false);
context.stroke();
curPerc++;
if (circles.length) {
for (var i=0; i<circles.length; i++) {
context.lineWidth = 10;
context.beginPath();
context.arc(circles[i].x, circles[i].y, radius, -(quart), ((circ) * circles[i].curr) - quart, false);
context.stroke();
doText(context,circles[i].x,circles[i].y,circles[i].text);
}
}
if (curPerc < endPercent) {
requestAnimationFrame(function () {
animate(curPerc / 100)
});
}else{
var circle = {x:x,y:y,curr:current,text:text};
circles.push(circle);
doText(context,x,y,text);
if (callback) callback.call();
}
}
animate();
}
});
Since you're not throttling the fps of your animation, each frame is being rendered as fast as possible with this code. If you want it to be faster, the simplest answer is to drop frames by incrementing the curPerc variable by more than one:
function animate(current) {
context.lineWidth = 10;
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.arc(x, y, radius, -(quart), ((circ) * current) - quart, false);
context.stroke();
curPerc += 2;
...
The above code will complete twice as quickly. If curPerc does not divide 100 evenly (100%curPerc != 0), then change the variable endPercent accordingly.

HTML5 Canvas - Grinding to a halt

I am doing some work with HTML canvases. Unfortunately I have ran into a very weird problem. At some point during development of the code the web page started to hang the browser. There were no tight loops apart from the requestAnimFrame shim so I took it back to basics and have found a very odd thing.
The code below will animate a circle across the screen. This works perfectly fine. If I comment out the code to draw the circle (marked in the code) it then grinds the browser to a halt. What is happening?
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function animate(lastTime, myCircle) {
//return;
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// update
var date = new Date();
var time = date.getTime();
var timeDiff = time - lastTime;
var linearSpeed = 100;
// pixels / second
var linearDistEachFrame = linearSpeed * timeDiff / 1000;
var currentX = myCircle.x;
if(currentX < canvas.width - myCircle.width - myCircle.borderWidth / 2) {
var newX = currentX + linearDistEachFrame;
myCircle.x = newX;
}
lastTime = time;
// clear
drawGrid();
//draw a circle
context.beginPath();
context.fillStyle = "#8ED6FF";
context.arc(myCircle.x, myCircle.y, myCircle.width, 0, Math.PI*2, true);
context.closePath();
context.fill();
context.lineWidth = myCircle.borderWidth;
context.strokeStyle = "black";
context.stroke();
// request new frame
requestAnimFrame(function() {
animate(lastTime, myCircle);
});
}
$(document).ready(function() {
var myCircle = {
x: 50,
y: 50,
width: 30,
height: 50,
borderWidth: 2
};
//drawGrid();
var date = new Date();
var time = date.getTime();
animate(time, myCircle);
});
function drawGrid(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.lineWidth = 1;
for (var x = 0; x <= canvas.width; x += 40) {
context.moveTo(0 + x, 0);
context.lineTo(0 + x, canvas.height);
}
for (var x = 0; x <= canvas.height; x += 40) {
context.moveTo(0, 0 + x);
context.lineTo(canvas.width, 0 + x);
}
context.strokeStyle = "#ddd";
context.stroke();
}
And my canvas is declared like so:
<canvas id="myCanvas" width="700" height="400"></canvas>
Turns out that the reason it worked when I draw the circle was because that code contained a closePath function. Adding that to the drawGrid function below fixes the issue.
function drawGrid(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.lineWidth = 1;
context.beginPath();
for (var x = 0; x <= canvas.width; x += 40) {
context.moveTo(0 + x, 0);
context.lineTo(0 + x, canvas.height);
}
for (var x = 0; x <= canvas.height; x += 40) {
context.moveTo(0, 0 + x);
context.lineTo(canvas.width, 0 + x);
}
context.closePath();
context.strokeStyle = "#ddd";
context.stroke();
}

Categories