Canvas unable to find context when requestAnimationFrame is called - ES6 [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
I am experimenting with class based code. I create a class for the canvas and pass a component to it which is then rendered. The problem is that when the browser requests the animation frame the context is lost, and becomes undefined. I am looking for an explanation of why this is the case.
I am not concerned with best practice just with figuring out why the context is lost.
I have attached a link to the example on codepen.
http://codepen.io/BrianDGLS/pen/BoJorM?editors=001
Here is the JS code:
class Canvas {
constructor() {
this.canvas = document.getElementById('canvas');
this.context = this.canvas.getContext('2d');
this.width = this.canvas.width = window.innerHeight;
this.height = this.canvas.height = window.innerWidth;
this.components = [];
}
draw() {
this.context.clearRect(0, 0, this.width, this.height);
this.context.globalCompositeOperation = 'hard-light';
this.components.map(_ => _.render());
window.requestAnimationFrame(this.draw);
}
listeners() {
window.addEventListener('resize', () => {
this.width = this.canvas.width = window.innerHeight;
this.height = this.canvas.height = window.innerWidth;
}, false);
}
init() {
this.listeners();
this.draw();
}
}
class Utils {
randomNum(max, min) {
return Math.floor(max * Math.random()) + min;
}
color(opacity) {
return `hsla(${this.randomNum(360, 1)}, 70%, 60%, ${opacity})`;
}
}
const utils = new Utils();
const _canvas = new Canvas();
class Stars {
constructor(_) {
this.total = _.total;
this.spawn = [];
this.z = 300;
this.canvas = _.canvas;
this.xw = this.canvas.width * this.z;
this.xh = this.canvas.height * this.z;
}
create() {
while (this.spawn.length < this.total) {
this.spawn.push({
pos: [this.xw * Math.random() - this.canvas.width / 2 * this.z, this.xh * Math.random() - this.canvas.height / 2 * this.z, this.z],
vel: [0, 0, -2],
r: utils.randomNum(500, 100),
color: utils.color(1)
});
}
}
draw() {
for (let i = 0; i < this.spawn.length; ++i) {
let t = this.spawn[i];
let x = t.pos[0] / t.pos[2];
let y = t.pos[1] / t.pos[2];
if (x < -this.canvas.width / 2 || x > this.canvas.width / 2 || y < -this.canvas.height / 2 || y > this.canvas.height / 2 || t.pos[2] < 0) {
this.spawn.splice(i, 1);
--i;
continue;
}
this.canvas.context.beginPath();
this.canvas.context.fillStyle = t.color;
this.canvas.context.arc(x, y, t.r / t.pos[2], 0, Math.PI * 2, false);
t.pos[0] += t.vel[0];
t.pos[1] += t.vel[1];
t.pos[2] += t.vel[2];
this.canvas.context.fill();
}
}
render() {
this.create();
this.canvas.context.save();
this.canvas.context.translate(this.canvas.width / 2, this.canvas.height / 2);
this.draw();
this.canvas.context.restore();
}
}
_canvas.components.push(new Stars({
canvas: _canvas,
total: 200
}));

When you invoke draw() via window.requestAnimationFrame(this.draw) the scope in draw() is bound to window instead of Canvas. Try binding the scope explicitly like this:
window.requestAnimationFrame(this.draw.bind(this));

Related

Flickering Canvas [duplicate]

This question already has answers here:
Flickering images in canvas animation
(2 answers)
Closed last month.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const global = {
hornets: [],
};
class Hornet {
constructor(x, y) {
this.x = x;
this.y = y;
this.radians = 0;
this.velocity = 0.05;
}
draw() {
const hornet = new Image();
hornet.src = "./hornet.png";
ctx.drawImage(hornet, this.x, this.y);
}
move() {
this.radians += this.velocity;
this.x -= Math.cos(this.radians) * 4;
this.y -= Math.sin(this.radians) * 4;
}
}
const drawNest = () => {
const nest = new Image();
nest.src = "./nest.png";
ctx.drawImage(nest, canvas.width / 2 - 40, canvas.height / 2 - 150);
};
const drawForest = () => {
const forest = new Image();
forest.src = "./forest.png";
ctx.drawImage(forest, 0, 0);
};
const initHornets = () => {
for (let i = 0; i < 22; i++) {
let ranX = Math.floor(Math.random() * 11) - Math.floor(Math.random() * 11);
let ranY = Math.floor(Math.random() * 11) - Math.floor(Math.random() * 11);
let x = canvas.width / 2 + i * ranX;
let y = canvas.height / 2 + i * ranY;
global.hornets.push(new Hornet(x, y));
}
};
initHornets();
const animate = () => {
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawForest();
drawNest();
global.hornets.forEach((hornet) => {
hornet.draw();
hornet.move();
});
requestAnimationFrame(animate);
};
window.onload = () => {
requestAnimationFrame(animate);
};
I've noticed that my canvas flickers every 5-6 seconds or so. Is this a fps issue from not utilizing delta time? Could it be using the Math.cos and Math.sin trig functions are resource intensive? Or is it something else entirely?
Check out what I mean: https://brixsta.github.io/Hornet-Nest/
Disabled Hardware Acceleration in Chrome and it fixes the White Flicker!

fillRect not showing

I am trying to code a game about snowboarding but so far, when I try to make trees (green rectangles), they aren't showing up.
Code:
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = 1000;
canvas.height = 800;
var x = canvas.width / 2,
speed = 0.1,
size = 5,
alive = 1,
keys = [];
function player() {
if (alive === 1) {
if (keys[37] || keys[65]) {
x -= 3;
}
if (keys[39] || keys[68]) {
x += 3;
}
if (x > canvas.width) {
x = canvas.width;
}
if (x < 0) {
x = 0;
}
ctx.beginPath();
ctx.fillStyle = "black"
ctx.arc(x, 100, size, 0, Math.PI * 2);
ctx.fill();
}
}
function tree() {
var treeX = Math.floor(Math.random() * (canvas.width + 1)) + 25;
var treeY;
if (treeY < 1) {
treeY = canvas.height;
} else {
treeY -= speed;
}
ctx.fillStyle = "green";
ctx.fillRect(treeX, treeY, 5, 8);
}
function update() {
requestAnimationFrame(update);
ctx.clearRect(0, 0, canvas.width, canvas.height);
player();
tree();
}
update();
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
<canvas id="canvas"></canvas>
I tried switching the order of things and using console to see where the trees are but none worked.
For player, you are tracking state outside of the function in some different variables.
For a tree to be able to update, you also have to track its state.
Here's a way you can do that:
Instead of always initializing treeX and treeY fresh in the function, pass values as arguments
After updating the tree state, return its x and y coordinates
Outside of your tree function, keep track of a list of trees.
In update, replace your list of trees with updated trees.
Here's a running example:
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 200;
var x = canvas.width / 2,
speed = 1,
size = 5,
alive = 1,
keys = [],
trees = [ tree(), tree(), tree() ];
function player() {
if (alive === 1) {
if (keys[37] || keys[65]) {
x -= 3;
}
if (keys[39] || keys[68]) {
x += 3;
}
if (x > canvas.width) {
x = canvas.width;
}
if (x < 0) {
x = 0;
}
ctx.beginPath();
ctx.fillStyle = "black"
ctx.arc(x, 100, size, 0, Math.PI * 2);
ctx.fill();
}
}
function tree(
treeX = Math.floor(Math.random() * (canvas.width + 1)),
treeY = Math.floor(Math.random() * (canvas.height + 1))
) {
if (treeY < 1) {
treeY = canvas.height;
} else {
treeY -= speed;
}
ctx.fillStyle = "green";
ctx.fillRect(treeX, treeY, 5, 8);
return [ treeX, treeY ];
}
function update() {
requestAnimationFrame(update);
ctx.clearRect(0, 0, canvas.width, canvas.height);
player();
trees = trees.map(([x, y]) => tree(x, y));
}
update();
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
* { margin: 0; }
canvas { border: 1px solid red; }
<canvas id="canvas"></canvas>

How to add css in text in jquery please give me refrence

How to add css in text in jquery I have try but no way found it please help me.
let particles = [];
let frequency = 20;
// Popolate particles
setInterval(
function () {
popolate();
}.bind(this),
frequency);
let c1 = createCanvas({ width: jQuery(window).width(), height: jQuery(window).height() });
let c2 = createCanvas({ width: jQuery(window).width(), height: jQuery(window).height() });
let c3 = createCanvas({ width: jQuery(window).width(), height: jQuery(window).height() });
let tela = c1.canvas;
let canvas = c1.context;
// jQuery("body").append(tela);
jQuery("#text").append(c3.canvas);
writeText(c2.canvas, c2.context, "Create\nPublish\nDeliver")
jQuery("#text").css("background-color", "grey");
class Particle {
constructor(canvas, options) {
let random = Math.random();
this.canvas = canvas;
this.x = options.x;
this.y = options.y;
this.s = 3 + Math.random();
this.a = 0;
this.w = jQuery(window).width();
this.h = jQuery(window).height();
this.radius = 0.5 + Math.random() * 20;
this.color = this.radius > 5 ? "#FF5E4C" : "#ED413C"; //this.randomColor()
}
randomColor() {
let colors = ["#FF5E4C", "#FFFFFF"];
return colors[this.randomIntFromInterval(0, colors.length - 1)];
}
randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
render() {
this.canvas.beginPath();
this.canvas.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
this.canvas.lineWidth = 2;
this.canvas.fillStyle = this.color;
this.canvas.fill();
this.canvas.closePath();
}
move() {
//this.swapColor()
this.x += Math.cos(this.a) * this.s;
this.y += Math.sin(this.a) * this.s;
this.a += Math.random() * 0.8 - 0.4;
if (this.x < 0 || this.x > this.w - this.radius) {
return false;
}
if (this.y < 0 || this.y > this.h - this.radius) {
return false;
}
this.render();
return true;
}}
function createCanvas(properties) {
let canvas = document.createElement('canvas');
canvas.width = properties.width;
canvas.height = properties.height;
let context = canvas.getContext('2d');
return {
canvas: canvas,
context: context };
}
function writeText(canvas, context, text) {
let size = 100;
context.font = size + "px Montserrat";
context.fillStyle = "#111111";
context.textAlign = "center";
let lineheight = 70;
let lines = text.split('\n');
for (let i = 0; i < lines.length; i++) {
context.fillText(lines[i], canvas.width / 2, canvas.height / 2 + lineheight * i - lineheight * (lines.length - 1) / 3);
}
}
function maskCanvas() {
c3.context.drawImage(c2.canvas, 0, 0, c2.canvas.width, c2.canvas.height);
c3.context.globalCompositeOperation = 'source-atop';
c3.context.drawImage(c1.canvas, 0, 0);
blur(c1.context, c1.canvas, 2);
}
function blur(ctx, canvas, amt) {
ctx.filter = `blur(jQuery{amt}px)`;
ctx.drawImage(canvas, 0, 0);
ctx.filter = 'none';
}
/*
* Function to clear layer canvas
* #num:number number of particles
*/
function popolate() {
particles.push(
new Particle(canvas, {
x: jQuery(window).width() / 2,
y: jQuery(window).height() / 2 }));
return particles.length;
}
function clear() {
canvas.globalAlpha = 0.03;
canvas.fillStyle = '#111111';
canvas.fillRect(0, 0, tela.width, tela.height);
canvas.globalAlpha = 1;
}
function update() {
clear();
particles = particles.filter(function (p) {
return p.move();
});
maskCanvas();`enter code here`
requestAnimationFrame(update.bind(this));
}
update();
// jQuery("body").append(tela);
jQuery("#text").append(c3.canvas);
writeText(c2.canvas, c2.context, "Create\nPublish\nDeliver").css("margin-left:20px");
jQuery("#text").css("background-color", "grey");
I have not found any way to add css in text please help me these
This could be a possible solution
let elementStyle = document.getElementById('text').style
elementStyle.backgroundColor = 'red'
elementStyle.marginLeft = '20px'

How to add event listener and move an object in canvas using ES6 Classes?

I'm creating a small game where you can move a star/ufo. I'm having a hard time to figure out how I should make it move. With functional programming its easy, but how do we go about doing this with ES6 utlizing classes? Do we need to bind or something? I suppose my logic is also somewhat wrong.
How can I make the circle move?
Codepen: https://codepen.io/Aurelian/pen/mGWVbq?editors=0010
'use strict';
/*
* ------------------------------------------
* *-----------------------------
* User Event
* *-----------------------------
* ------------------------------------------
*/
class UserEvent {
constructor(canvasBody) {
this.UP_ARROW = 38 || 87,
this.RIGHT_ARROW = 39 || 68,
this.DOWN_ARROW = 37 || 83,
this.LEFT_ARROW = 40 || 65,
this.keys = []
canvasBody.addEventListener('keydown', (e) => {
this.keys[e.keyCode] = true;
});
canvasBody.addEventListener('keyup', (e) => {
this.keys[e.keyCode] = false;
});
}
checkKey(key) {
return this.keys[key];
}
ufoMove() {
this.canvasBody.checkKey(this.UP_ARROW)
this.canvasBody.checkKey(this.RIGHT_ARROW)
this.canvasBodycheckKey(this.DOWN_ARROW)
this.canvasBody.checkKey(this.LEFT_ARROW)
console.log(this.canvasBody.leftArrow = this.checkKey(this.LEFT_ARROW))
if (this.UP_ARROW) {
this.x += this.x * this.velocity.x
}
}
}
/*
* ------------------------------------------
* *-----------------------------
* UFO
* *-----------------------------
* ------------------------------------------
*/
class Ufo {
constructor(x, y) {
this.x = x,
this.y = y,
this.velocity = {
x: 3,
y: 3
}
}
draw(c) {
c.save()
c.beginPath()
c.arc(this.x, this.y, 50, 0, Math.PI * 2, false)
c.fillStyle = "#fff";
c.shadowColor = "#e3eaef";
c.shadowBlur = 20;
c.fill()
c.closePath()
c.restore()
}
update(c) {
this.draw(c)
// Get the keys first
this.EventUser.ufoMove(this.c);
// this.x = this.x + this.velocity.x;
// }
}
}
/*
* ------------------------------------------
* *-----------------------------
* Canvas
* *-----------------------------
* ------------------------------------------
*/
class CanvasDisplay {
constructor() {
this.canvas = document.querySelector('canvas');
this.ctx = this.canvas.getContext('2d');
this.stageConfig = {
width: window.innerWidth,
height: window.innerHeight
};
this.canvas.width = this.stageConfig.width;
this.canvas.height = this.stageConfig.height;
this.backgroundGradient = this.ctx.createLinearGradient(0, 0, 0, this.canvas.height);
this.backgroundGradient.addColorStop(0, '#171e26');
this.backgroundGradient.addColorStop(1, '#3f586b');
this.Ufo = new Ufo(this.canvas.width / 2, this.canvas.height / 2);
this.UserEvent = new UserEvent(document.body);
}
animate() {
this.ctx.fillStyle = this.backgroundGradient;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.Ufo.update(this.ctx)
window.requestAnimationFrame(this.animate);
}
}
let canvasDisplay = new CanvasDisplay();
canvasDisplay.animate();
canvas {
display: block;
}
<canvas></canvas>
Please take a look at this code (a little bit different of what you had in mind)
let keys = {ArrowUp:false,ArrowDown:false,ArrowLeft:false,ArrowRight:false};
window.addEventListener('keydown', function(e){
keys[e.code] = true;
});
window.addEventListener('keyup', function(e){
keys[e.code] = false;
});
/*UFO*/
class Ufo {
constructor(x, y) {
this.x = x,
this.y = y,
this.velocity = {
x: 3,
y: 3
}
}
draw(c) {
c.save()
c.beginPath()
c.arc(this.x, this.y, 50, 0, Math.PI * 2, false)
c.fillStyle = "#fff";
c.shadowColor = "#e3eaef";
c.shadowBlur = 20;
c.fill()
c.closePath()
c.restore()
}
update(c) {
if(keys.ArrowUp){this.y -= this.velocity.y;}
if(keys.ArrowDown){this.y += this.velocity.y;}
if(keys.ArrowLeft){this.x -= this.velocity.x;}
if(keys.ArrowRight){this.x += this.velocity.x;}
this.draw(c);
}
}
/* Canvas*/
class CanvasDisplay {
constructor() {
this.canvas = document.querySelector('canvas');
this.ctx = this.canvas.getContext('2d');
this.cw = this.canvas.width = window.innerWidth;
this.ch = this.canvas.height = window.innerHeight;
this.ufo = new Ufo(this.cw / 2, this.ch / 2);
this.ctx.fillStyle = this.grd();
}
grd(){
let grd = this.ctx.createLinearGradient(0, 0, 0, this.ch);
grd.addColorStop(0, '#171e26');
grd.addColorStop(1, '#3f586b');
return grd;
}
animate() {
window.requestAnimationFrame(this.animate.bind(this));
this.ctx.fillRect(0,0,this.cw,this.ch);
this.ufo.update(this.ctx);
}
}
let canv= new CanvasDisplay();
canv.animate();
body {
overflow: hidden;
}
canvas {
display: block;
}
<canvas></canvas>
lease take a look at this code:

Can properties be created in Javascript any where?

If I have an array in JavaScript that starts with var stars = [] and I create a star (code below). I found this code online and am working my way through it so that I can see how it works and to modify it.
Is the this.stars = stars; just creating another internal property for this particular class?
var stars = [];
for(var i=0; i<this.stars; i++) {
stars[i] = new Star(Math.random() * this.width,
Math.random() * this.height,
Math.random() * 3+1,
(Math.random() * (this.maxVelocity - this.minVelocity))
+ this.minVelocity);
}
this.stars = stars; // <-- creating internal property
Because I do not see it here in the definition of the class. So I am not certain if it is just created on the spot or if it could be declared in this definition.
Code Here:
function Starfield() {
this.fps = 30;
this.canvas = null;
this.width = 0;
this.width = 0;
this.minVelocity = 15;
this.maxVelocity = 30;
this.stars = 9000;
this.intervalId = 0;
}
// The main function - initialises the starfield.
Starfield.prototype.initialise = function(div) {
var self = this; //sets it self to current object
// Store the div
this.containerDiv = div;
self.width = window.innerWidth;
self.height = window.innerHeight;
window.onresize = function(event) {
self.width = window.innerWidth;
self.height = window.innerHeight;
self.canvas.width = self.width;
self.canvas.height = self.height;
self.draw();
}
// Create the canvas.
var canvas = document.createElement('canvas');
div.appendChild(canvas);
this.canvas = canvas;
this.canvas.width = this.width;
this.canvas.height = this.height;
};
Starfield.prototype.start = function() {
// Create the stars.
var stars = []; //creates an array that can be used for anything but in this case a star field
//this.stars is a property in the class that contains a number of the stars
for(var i=0; i<this.stars; i++) {
stars[i] = new Star(Math.random() * this.width,
Math.random() * this.height,
Math.random() * 3+1,
(Math.random() * (this.maxVelocity - this.minVelocity)) + this.minVelocity);
}
this.stars = stars;
var self = this;
// Start the timer.
this.intervalId = setInterval(function() {
self.update();
self.draw();
}, 1000 / this.fps);
};
Starfield.prototype.stop = function() {
clearInterval(this.intervalId);
};
Starfield.prototype.update = function() {
var dt = 1 / this.fps;
for(var i=0; i < this.stars.length; i++) {
var star = this.stars[i];
star.y += dt * star.velocity;
// If the star has moved from the bottom of the screen, spawn it at the top.
if (star.y > this.height) {
this.stars[i] = new Star(Math.random() * this.width,
0,
Math.random() * 3 + 1,
(Math.random() * (this.maxVelocity + 60 - this.minVelocity)) + this.minVelocity);
}
}
};
Starfield.prototype.draw = function() {
var ctx = this.canvas.getContext("2d");
// Draw the background.
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, this.width, this.height);
// Draw stars.
ctx.fillStyle = '#ffffff';
for(var i=0; i<this.stars.length;i++) {
var star = this.stars[i];
ctx.fillRect(star.x, star.y, star.size, star.size);
}
};
//This is the class for stars -- there are 4 properties that are in this particular class
function Star(x, y, size, velocity) {
this.x = x;
this.y = y;
this.size = size;
this.velocity = velocity;
}
Yes, properties can be added at any time in JavaScript. Take a look at this example:
function Person(firstName) {
this.firstName = firstName;
}
Person.prototype.getFullName = function() {
// Notice that I haven't defined this.lastName yet
return this.firstName + ' ' + this.lastName;
};
var bob = new Person('Bob');
bob.lastName = 'Saget';
console.log(bob.getFullName()); // 'Bob Saget'
Yes, Javascript objects are dynamic. They can have new properties added/deleted at any time unless they have been sealed and their properties can be modified at any time unless they have been frozen.
You probably won't see many sealed or frozen objects in the wild.

Categories

Resources