I am new to canvas and java script and have no idea why it is not working. The 2 alerts are firing but color of the canvas is not changing every 1 sec as I intended it to do.
var canvas = function(width, height, color){
this.width = width;
this.height = height;
this.color = color;
var instance = document.createElement('canvas');
document.body.appendChild(instance);
instance.width = this.width;
instance.height = this.height;
var ctx = instance.getContext('2d');
ctx.fillStyle = color;
ctx.fillRect(0, 0, this.width, this.height);
this.changeBackground = function(color){
ctx.fillStyle = color;
ctx.fillRect(0, 0, this.width, this.height);
}
this.clear = function(){
ctx.clearRect(0, 0, this.width, this.height);
}
var flag = true;
setInterval(function(){
if(flag) {
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, this.width, this.height);
alert('blue');
}
else {
ctx.fillStyle = 'green';
ctx.fillRect(0, 0, this.width, this.height);
alert('green');
}
flag = !flag;
},1000);
}
var gameCanvas = new canvas(800, 600, 'green');
The issue is this inside of setInterval is the global window object, so this.width is undefined. The easiest way to fix this is to convert the function passed to setInterval into an arrow function. Here is a fiddle
setInterval(() => {
...
},1000);
Arrow functions inherit their context, so this is still your canvas object.
Note: arrow functions are not supported in IE v11 and below. Here is the list of supported browsers.
If you can't use arrow functions, you can get the size of the canvas from the ctx with ctx.canvas.clientWidth and ctx.canvas.clientHeight Here is a fiddle
Writing setInterval( () => { instead of setInterval(function(){ could solve this issue.
Fat-arrow function or lamda function or () => will point this to your class-function instead of window variable.
Using function() inside a callback will always point this to the object that the implementation of used function came from.
In your case setInterval is a function of window global variable
if(flag) {
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, canvas.width, canvas.height);
alert('blue');
}
else {
ctx.fillStyle = 'green';
ctx.fillRect(0, 0, canvas.width, canvas.height);
alert('green');
}
this inside setInterval contexts to window. Fixing this would fix your issue.
Related
I want a ball falling, with gravity. But the background won't clear the previous circle. (the falling part isnt implemented yet) why doesnt it erase the last drawn object?
let c, ctx;
let met;
let colorArray = ["green", "yellow", "orange", "red"];
window.onload = function(){
c = document.getElementById("boom");
ctx = c.getContext("2d");
c.width = window.innerWidth - 165;
c.height = window.innerHeight;
setup();
draw();
}
function setup(){
met = new Meteor(200, 400, 10, 0, 5);
}
function draw(){
window.requestAnimationFrame(draw);
ctx.fillStyle = colorArray[Math.floor(Math.random() * colorArray.length)];
ctx.fillRect(0, 0, c.width, c.height);
met.draw();
met.fall();
};
class Meteor {
constructor(x, y, r, xSpeed, ySpeed){
this.xPos = x;
this.yPos = y;
this.radius = r;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.color = "blue";
this.acceleration = 0.5;
}
draw(){
ctx.fillStyle = this.color;
ctx.arc(this.xPos, this.yPos, this.radius, 0, 2 * Math.PI);
//ctx.fill();
ctx.stroke();
}
fall(){
this.yPos += (this.ySpeed);
}
}
Also, if you have any tips on how to make it have gravity, please don't hesitate to tell me. Ive been struggling with it for a while now.
In draw() add this before the call to met.draw():
ctx.clearRect(0, 0, window.innerWidth, window.innterHeight)
This will clear the screen every frame.
For gravity, add a dt parameter to your draw function, then pass it to met.draw() like this:
function draw(dt){
window.requestAnimationFrame(draw);
ctx.fillStyle = colorArray[Math.floor(Math.random() * colorArray.length)];
ctx.fillRect(0, 0, c.width, c.height);
ctx.clearRect(0, 0, window.innerWidth, window.innterHeight) // Clear screen here
met.draw(dt);
met.fall();
};
Then in the Meteor class, use the dt in the draw() function to calculate your y position based on velocity. Here dt will be your delta time for the calculation.
I already create my canvas on my page, however when I try to import an image on the canvas, it does not appear, here are the code I used. (the makeGameArea is a method I created to make a canvas on the webpage, the code of this method is not shown because it is so long to put it here)
Here are the following code that should have problem
var myGameArea2 = makeGameArea(700, 150, "myArea", "white");
var myContext2 = myGameArea2.getContext("2d");
var myImage = new drawImage(myContext2, "sonic.gif", 91, 97, 0, 0);
myImage.draw();
function drawImage(ctx, src, width, height, x, y){
this.image = new Image();
this.image.src = src;
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.draw = function(){
this.image.onload = function(){
ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
}
}
}
Is there anything wrong with my drawImage() method?
HTMLImage.onload will fire only once per src setting.
Here you are attaching your handler in the draw method, which I guess will be called later on. At this moment, the event will already have fired, and hence will never be called, since it won't fire again unless you reset its src.
Fixed code block:
function drawImage(ctx, src, width, height, x, y){
this.image = new Image();
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.draw = function(){
ctx.drawImage(this.image, this.x, this.y, this.width, this.height));
};
// if you want it to draw as soon as possible
this.image.onload = this.draw.bind(this);
this.image.src = src;
}
I have no idea what is wrong. This is being made on a completely new site, so there are no cache problems, and the javascript console isn't returning errors. The canvas spans over the whole page, and is tagged properly. Here is the script:
<script type = "text/javascript">
var game = document.getElementById("game");
var context = game.getContext("2d");
var gamePieces = []
function gamePiece(width, height, color, x, y){
this.width = width;
this.height = height;
this.x = x;
this.y = y;
update = function(){
context.fillStyle = color;
context.fillRect(this.x, this.y, this.height, this.width);
}
gamePieces[gamePieces.length] = this
}
var p1 = gamePiece(50, 50, "blue", 0, 0);
function update(){
context.clearRect(0, 0, game.width, game.height);
for(var i = 0; i < gamePieces.length; i++){
gamePieces[i].update();
}
}
</script>
Nevermind. I figured it out.
Everything is running smoothly, I just needed to add another context.fillstyle and context.fillRect() statement. derpyderp.
I've tried googling the answer to this but i'm just going around in circles....
If I clear the rect (using clearRect) then the image doesn't redraw after.
However, if I don't clear the images just stack.
What I want it to clear the current image and then draw with new one.
What am I missing?
Does it have something to do with the image Load ?
Sorry if this is a question repeat, I couldn't find the exact answer to this- and I tried what others suggested but results were poor.
http://jsfiddle.net/bxeuhh4h/
function clear() {
var canvasTemp = document.getElementById(imgSection);
var ctxTemp = canvasTemp.getContext("2d");
ctxTemp.clearRect(0, 0, 500, 500);
}
function fillColorOrPattern(imgSection,currentcolor){
if ((oldcolor !== currentcolor) || (oldxImgToBeFilled !== xImgToBeFilled)){
clear();
}
imgFill.onload = function () {
imgToBeFilled.onload = function () {
if ((oldcolor !== currentcolor) || (oldxImgToBeFilled !== xImgToBeFilled)){
fill(imgSection,currentcolor)
}
};
imgToBeFilled.src = xImgToBeFilled;
}
imgFill.src = xImgFill;
}
function fill(imgSection,currentcolor){
canvas = document.getElementById(imgSection);
ctx = canvas.getContext("2d");
ctx.drawImage(imgToBeFilled, 0, 0);
ctx.globalCompositeOperation = "source-atop";
console.log(isItColorOrPattern);
if (isItColorOrPattern == "color"){
ctx.rect(0, 0, canvas.width, canvas.height);
console.log("currentcolor: " + currentcolor);
ctx.fillStyle = getColor(currentcolor);
console.log(getColor(currentcolor));
ctx.fill();
}else{
var pattern = ctx.createPattern(imgFill, 'repeat');
console.log("canvas.width: " + canvas.width);
console.log("xImgFill: " + xImgFill);
console.log(canvas.getContext);
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = pattern;
ctx.fill();
}
ctx.globalAlpha = .10;
ctx.drawImage(imgToBeFilled, 0, 0);
ctx.drawImage(imgToBeFilled, 0, 0);
ctx.drawImage(imgToBeFilled, 0, 0);
oldcolor = currentcolor;
oldxImgToBeFilled = xImgToBeFilled;
}
$(window).load(function(){
imgToBeFilled = new Image();
imgFill = new Image();
fillColorOrPattern(imgSection,currentcolor);
}
You need to add a beginPath() in there. rect() will accumulate rectangles to the path, clearRect() won't clear those. Also reset comp. mode and alpha as they are sticky.
You could avoid beginPath() if you use fillRect() instead of rect() + fill() (added example below) as fillRect() does not add to the path.
function fill(imgSection,currentcolor){
// these should really be initialized outside the loop
canvas = document.getElementById(imgSection);
ctx = canvas.getContext("2d");
// clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// clear path
ctx.beginPath();
// use default comp. mode
ctx.globalCompositeOperation = "source-over";
// reset alpha
ctx.globalAlpha = 1;
ctx.drawImage(imgToBeFilled, 0, 0);
ctx.globalCompositeOperation = "source-atop";
if (isItColorOrPattern === "color"){
// rect() accumulates on path
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = getColor(currentcolor);
ctx.fill();
// instead of rect() + fill() you could have used:
// fillRect() does not accumulate on path
// fillRect(0, 0, canvas.width, canvas.height);
}
else {
var pattern = ctx.createPattern(imgFill, 'repeat');
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = pattern;
ctx.fill();
}
ctx.globalAlpha = .1;
ctx.drawImage(imgToBeFilled, 0, 0);
ctx.drawImage(imgToBeFilled, 0, 0);
ctx.drawImage(imgToBeFilled, 0, 0);
oldcolor = currentcolor;
oldxImgToBeFilled = xImgToBeFilled;
}
Canvas workflow goes like this:
Draw some things on the canvas.
Calculate changes to the position of those things.
Clear the canvas.
Redraw all the things in their new positions.
Canvas does not "remember" where it drew your things so you cannot directly order your things to move.
But you can save the definition of your things in javascript object:
var myCircle={
centerX:50,
centerY:50,
radius:25,
fill:'blue'
}
Then you can "move" your things using the javascript objects:
myCircle.centerX += 5;
And then redraw the things at their new positions. Putting the redraw code in a function makes redrawing easier:
function redraw(){
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// redraw one or more things based on their javascript objects
ctx.beginPath();
ctx.arc( myCircle.centerX, myCircle.centerY, myCircle.radius, 0, Math.PI*2 );
ctx.closePath();
ctx.fillStyle=myCircle.fill;
ctx.fill();
}
Putting it all together:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var myCircle={
centerX:50,
centerY:50,
radius:25,
fill:'blue'
}
redraw();
document.getElementById('move').addEventListener('click',function(){
myCircle.centerX+=5;
redraw();
});
function redraw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
ctx.arc( myCircle.centerX, myCircle.centerY, myCircle.radius, 0, Math.PI*2 );
ctx.closePath();
ctx.fillStyle=myCircle.fill;
ctx.fill();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<button id=move>Move</button>
<br>
<canvas id="canvas" width=300 height=300></canvas>
Can somebody explain me why this code doesn't work? It's supposed to draw two paddles and a ball (rectangular) in a canvas so far. I'm new in JavaScript, and I'm following this YouTube tutorial, but I got stuck almost at the very beginning. Besides not knowing why it doesn't draw all the elements of the game I also don't understand the meaning of the var = loop function inside the main function. Help please!!
var WIDTH=700;
var HEIGHT=500;
var pi=Math.PI;
var canvas;
var ctx;
var keystate;
var player;
var ai;
var ball;
player = {
x: null,
y: null,
width: 20,
height: 100,
update: function(){},
draw: function (){
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
ai = {
x: null,
y: null,
width: 20,
height: 100,
update: function(){},
draw: function (){
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
ball = {
x: null,
y: null,
side: 20,
update: function(){},
draw: function (){
ctx.fillRect(this.x, this.y, this.side, this.side);
}
}
function main(){
canvas = document.createElement("canvas");
canvas.width = WIDTH;
canvas.height = HEIGHT;
ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
init();
var loop = function(){
update();
draw();
window.requestAnimationFrame(loop,canvas);
};
window.requestAnimationFrame(loop,canvas);
}
function init(){
player.x = player.width;
player.y = (HEIGHT - player.height)/2;
ai.x = WIDTH - (player.width + ai.width);
ai.y = (HEIGHT - ai.height)/2;
ball.x = (HEIGHT - ball.side)/2;
ball.y = (HEIGHT - ball.side)/2;
}
function update(){
ball.update();
player.update();
ai.update();
}
function draw(){
ctx.fillRect(0,0,WIDTH,HEIGHT);
ctx.fillStyle = "#fff";
ball.draw();
player.draw();
ai.draw();
}
main();
</script>
You are drawing everything in white.
That's why you see nothing. The background is white and the shapes you draw are as well.
Try
function draw(){
ctx.fillStyle = "#fff";
ctx.fillRect(0,0,WIDTH,HEIGHT);
ctx.save();
ctx.fillStyle = "#000"
ball.draw();
player.draw();
ai.draw();
ctx.restore();
}