Increase x and y when requestanimationframe is called - javascript

I want the x and y to increase by 1 in each requestAnimationFrame, it only increases once
https://jsfiddle.net/2mzb7axu/1/
update(ctx) {
ctx.beginPath();
ctx.moveTo(this.x, this.y);
this.x++
this.y++
ctx.lineTo(this.x, this.y);
ctx.lineWidth = 5;
ctx.stroke();
}

Your animate function is initiating the Line constructor with every update call.
Try initiating the Line class on the Display constructor, something like this:
constructor() {
this.canvas = document.querySelector("#canvas");
this.ctx = this.canvas.getContext("2d");
this.width = window.innerWidth;
this.height = window.innerHeight;
this.canvas.width = this.width;
this.canvas.height = this.height;
this.animateBound = this.animate.bind(this);
this.line = new Line();
}
and within your update function, call the existing Line's instance:
animate() {
this.line.update(this.ctx);
console.log('Animate called');
requestAnimationFrame(this.animateBound);
}

Related

Call tile.draw_tile doesn’t display anything

I am trying to create a small game to learn javascript.Everything works fine except my Rect class.As a matter of fact key_click works fine when it executes some console.log, but doesn’t display anything with tile.draw_tile() (nor gives any error).Could you help me?
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let Rect = class {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
draw_tile() {
c.fillStyle = "red";
c.fillRect(this.x, this.y, this.width, this.height);
}
}
var mouse = {
x: undefined,
y: undefined,
key_move: window.addEventListener('mousemove',(event)=>{
mouse.x = event.clientX;
mouse.y= event.clientY;
}),
key_click:window.addEventListener('click',(event)=>{
tile.draw_tile();
})
}
let tile = new Rect(mouse.x, mouse.y, 30, 30);
main = function(){
mouse.key_move;
mouse.key_click;
window.requestAnimationFrame(main);
}
window.requestAnimationFrame(main);

HTML 5 Canvas - Rotate multiple objects around own origin

I'm trying to create a JavaScript object that has a method which allows a rectangle to rotate around its own origin during a rAF callback.
Things I have done:
Calculating the origin of an object within the canvas space.
Using ctx.save() and ctx.restore() - this is where my issues arise.
When I use the save() and restore() methods to push and pop the saved states within method calls for different objects it either doesn't change anything, or stops the entire animation.
The rotation in my example appears to be applied globally to the canvas (which is how the functionality is specified on MDN). I'm trying to translate around origin around multiple instances. I've spent hours on this.
Is there something going on with the inheritance mechanism in JavaScript that's not resetting my transforms for different instances of the rectangle objects in the code example?
// author: Nicholas Fazzolari
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var xCenterCanvas = innerWidth/2;
var yCenterCanvas = innerHeight/2;
// custom rectangle object
function RectangleCustom(x, y, w, h, color) {
this.w = w;
this.h = h;
this.x = x;
this.y = y;
this.color = color;
this.radians = (Math.PI/180) * 2; // change the last value to change speed
// draws a rectangle at given coordinates
this.draw = function() {
ctx.save();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
ctx.restore();
}
// rotates the rectangle around it's center relative to a given xy position
this.rotateRect = function() {
ctx.save();
ctx.translate(this.x + this.w * 0.5, this.y + this.h * 0.5);
ctx.rotate(this.radians);
ctx.translate(-this.x -this.w * 0.5, -this.y - this.h * 0.5);
//ctx.restore()
}
}
// singleton rectangles
var bkgRectangle = new RectangleCustom(0, 0, innerWidth, innerHeight, "#212121");
var redRectangle = new RectangleCustom(xCenterCanvas - 64, yCenterCanvas - 64, 128, 128, "#F44336");
// main animation loop
function mainAnimationLoop() {
// runs animation and clears the canvas each call
requestAnimationFrame(mainAnimationLoop);
ctx.clearRect(0, 0, innerWidth, innerHeight);
bkgRectangle.draw();
redRectangle.draw();
redRectangle.rotateRect();
}
mainAnimationLoop();
I have tried rotating multiple rectangles around their own origin at different positions without animation using save() and restore() - which worked.
Additionally, I have tried moving the rotate method inside of the draw method and the results were the same. My rationale was that the rotation would be applied as a function call within draw() - the rationale was clearly wrong.
Any insight towards a solution would be greatly helpful. I have included a link to the pen on codepen to see the concept in motion.
Instead of drawing the rects at (this.x, this.y) you may draw them at 0,0 and translate them to (this.x, this.y);
// author: Nicholas Fazzolari
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var xCenterCanvas = innerWidth/2;
var yCenterCanvas = innerHeight/2;
// custom rectangle object
function RectangleCustom(x, y, w, h, color) {
this.w = w;
this.h = h;
this.x = x;
this.y = y;
this.color = color;
this.radians = (Math.PI/180) * 2; // change the last value to change speed
this.rotation = 0;
// draws a rectangle at given coordinates
this.draw = function() {
this.rotation += this.radians;
ctx.save();
ctx.fillStyle = this.color;
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
ctx.fillRect(0,0, this.w, this.h);
ctx.restore();
}
this.update = function() {
// animation updates
}
}
// singleton rectangles
var bkgRectangle = new RectangleCustom(0, 0, innerWidth, innerHeight, "#212121");
var redRectangle = new RectangleCustom(xCenterCanvas - 64, yCenterCanvas - 64, 128, 128, "#F44336");
// main animation loop
function mainAnimationLoop() {
// runs animation and clears the canvas each call
requestAnimationFrame(mainAnimationLoop);
ctx.clearRect(0, 0, innerWidth, innerHeight);
bkgRectangle.draw();
redRectangle.draw();
}
mainAnimationLoop();
<canvas></canvas>

Why won't my images appear on the canvas?

I want to draw many different sized circles with the same image on them using a prototype. The problem is, the circles don't appear with the images drawn on them.
The circles are still there because they're visible when stroke is used, but the images aren't drawn. I was able to have an arc be drawn with an image in it without the prototype but as soon as I use it, it doesn't work.
No bugs appear in the console, so it is not clear to me what I'm missing.
I've tried moving the event listener outside the prototype but the circle images still did not appear.
If anyone has any insight and perhaps a solution as to why this isn't working that they can share, that would be very much appreciated.
Here is the code:
const ctx = document.getElementById('canvas').getContext('2d');
class Balls {
constructor(xPos, yPos, radius){
this.xPos = xPos;
this.yPos = yPos;
this.radius = radius;
}
}
Balls.prototype.render = function(){
const img = document.createElement('img');
img.src = 'crystal.jpg';
ctx.arc(this.xPos, this.yPos, this.radius, 0, Math.PI*2)
ctx.stroke();
ctx.clip();
img.addEventListener('onload', function(e){
ctx.drawImage(img, this.xPos - this.radius, this.yPos - this.radius,
this.radius*2, this.radius*2);
});
};
let object = new Balls(100, 100, 50);
object.render();
<canvas id='canvas'></canvas>
Here you go, i just changed 2 things here in order to make your code work.
load is used for eventlistener instead on onload.
use Arrow function in order to rely on the parent context instead of dynamic context(this).
const ctx = document.getElementById('canvas').getContext('2d');
class Balls {
constructor(xPos, yPos, radius) {
this.xPos = xPos;
this.yPos = yPos;
this.radius = radius;
}
}
Balls.prototype.render = function() {
const img = document.createElement('img');
img.src = 'https://via.placeholder.com/150.png?text=vijay'
ctx.arc(this.xPos, this.yPos, this.radius, 0, Math.PI * 2)
ctx.stroke();
ctx.clip();
img.addEventListener('load', (e) => {
ctx.drawImage(img, this.xPos - this.radius, this.yPos - this.radius,
this.radius * 2, this.radius * 2);
});
};
let object = new Balls(100, 100, 50);
object.render();
<canvas id='canvas'></canvas>
You had two issues in your code. Firstly, the onload event should be load. Secondly, this is not known inside the event listener function, so this.radius etc. are all undefined and ctx.drawImage(img, this.xPos - this.radius, this.yPos - this.radius,
this.radius*2, this.radius*2) doesn't work.
I used some variables for this.xPos, this.yPos, this.radius that can be used inside the event listener callback function.
Hope this helps!
const ctx = document.getElementById('canvas').getContext('2d');
class Balls {
constructor(xPos, yPos, radius) {
this.xPos = xPos;
this.yPos = yPos;
this.radius = radius;
}
}
Balls.prototype.render = function() {
const img = new Image();
img.src = 'https://source.unsplash.com/random';
var xPos = this.xPos, yPos = this.yPos, radius = this.radius
ctx.arc(xPos, yPos, radius, 0, Math.PI * 2)
ctx.stroke();
ctx.clip();
img.addEventListener('load', function(e) {
console.log("load")
ctx.drawImage(img, xPos - radius, yPos - radius,
radius*2, radius*2);
});
};
let object = new Balls(100, 100, 50);
object.render();
<canvas id='canvas'></canvas>
This is an alternative way you can load images which is more modular, If you are making a game an Img class will come in handy.
Off-topic -
if you want to load multiple images then you can add atotalLoadedcounter to keep track of how many images has been loaded and if thetotalLoadedcount is equal tototalImagescount then you can call a callback which will fire the animationLoop and preloads all the images.
const ctx = document.getElementById('canvas').getContext('2d');
// Img class to provide modular code
class Img {
constructor(src, x, y, size) {
this.x = x;
this.y = y;
this.size = size;
this.src = src;
this.img = new Image();
this.img.src = this.src;
this.isLoaded = false;
this.img.addEventListener('load', (e) => {
this.isLoaded = true;
this.draw();
});
}
draw() {
if (this.isLoaded) {
ctx.drawImage(this.img, this.x, this.y, this.size, this.size);
}
}
}
class Balls {
constructor(xPos, yPos, radius) {
this.xPos = xPos;
this.yPos = yPos;
this.radius = radius;
}
}
Balls.prototype.render = function() {
let imgx = this.xPos - this.radius;
let imgy = this.yPos - this.radius;
let imgr = this.radius * 2;
let url = 'https://via.placeholder.com/150.png?text=Better';
const img = new Img(url, imgx, imgy, imgr);
ctx.arc(this.xPos, this.yPos, this.radius, 0, Math.PI * 2)
ctx.stroke();
ctx.clip();
img.draw();
};
let object = new Balls(100, 100, 50);
object.render();
<canvas id='canvas'></canvas>

Deleting on a canvas

Im trying to create and delete arcs on events, to adding parts works fine and i'm saving them in arrays so i could delete them on calling an event listener by somehow that's not happening , I mean its working fine in the console as in the array values are decremented by its not updating in the canvas
Code:
<script>
var myCanvas = document.getElementById("myCanvas");
myCanvas.width = window.innerWidth;
myCanvas.height = 500;
var c = myCanvas.getContext("2d");
var myArr = [];
myCanvas.addEventListener("click", function(){
var x = event.x;
var y = event.y;
var radius = 10;
myArr.push(new CreateCircle(x, y, radius, "#34495e"));
console.log( myArr );
});
window.addEventListener('keydown', function(){
myArr.splice(0,1);
console.log(myArr);
});
function CreateCircle(x, y, radius, color) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.draw = function() {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI*2);
c.fillStyle = this.color;
c.fill();
}
this.draw();
}
</script>
Do i need to add an delete function in the constructor function and call it on keydown event , how do i go on doing it/fixing it ?
To remove the circles, you have to clear the canvas, and then redraw it with the modified array of circles.
First of all, return an object from the CreateCircle method, so you have something to work with. There's no need for instances here.
Secondly, you could clear the canvas by resetting it's width, and then redraw based on the array, like this
var myCanvas = document.getElementById("myCanvas");
myCanvas.width = window.innerWidth;
myCanvas.height = 500;
var c = myCanvas.getContext("2d");
var myArr = [];
myCanvas.addEventListener("click", function() {
var x = event.x;
var y = event.y;
var radius = 10;
myArr.push(CreateCircle(x, y, radius, "#34495e"));
});
window.addEventListener('keydown', function() {
myArr.splice(0, 1);
myCanvas.width = myCanvas.width;
myArr.forEach(function(circle) {
CreateCircle(circle.x, circle.y, circle.r, circle.c)
})
});
function CreateCircle(x, y, radius, color) {
c.beginPath();
c.arc(x, y, radius, 0, Math.PI * 2);
c.fillStyle = color;
c.fill();
return {x: x, y: y, r: radius, c: color};
}
<canvas id="myCanvas"></canvas>
You don't update canvas anywhere. You need to create some sort of "render" function which will clear previously rendered frame and then loops through circles in array and call .draw on all of them.
Tip:
context.clearRect method is useful for clearing canvas.

Javascript: I cannot draw image on the canvas

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;
}

Categories