making a class of shapes that know how to draw themselves - javascript

I would like to know how to get this to work. The argument
g of the function draw is to be the graphics context of a JavaScript canvas object.
What I want is to be able to say is
var c = document.getElementById("canvas");
var g = c.getContext("2d");
b = new Ball(300,200, 50, "red");
b.draw(g)
and have a red ball paint at the center (300,200) of radius 50px.
Here is the code for the class.
class Ball
{
constructor(x, y, radius, color)
{
this.x = x;
this.y = y;
this.radius = radius
this.color=color;
}
draw(g)
{
console.log(g.fillStyle);
g.fillStyle = this.color;
g.beginPath()
//g.arc(this.x, this.y, this.r, 0, 2*Math.PI);
//correct is below.....
g.arc(this.x, this.y, this.radius, 0, 2*Math.PI);
g.fill();
}
}
Thank you for any help you can supply. Please note I have enabled ECMA6 in my browser. The console is not raising any error messages.

You've got a type-o in draw(). Change this.r to this.radius to match the constructed variable.

Related

HTML Canvas, how to add a border to the circle that is drawn

I've created a class for my player, a circle, in a a canvas game to be drawn and would like to add a solid border so that I can use RGBA to add some extra styling in my game.
Looking at the MDN articles here:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeStyle
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors
I should be able to use strokeStyle to create a border but it's not giving me the intended result of a white circle with a blue border, just a white circle.
Is it that border isn't a correct variable? or something else I'm missing?
class Player {
constructor(x, y, radius, color, border) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.border = border;
}
draw() {
context.beginPath();
context.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
context.fillStyle = this.color;
context.strokeStyle = this.border;
context.fill();
}
}
let newPlayer1 = new Player(canvas.width / 2, canvas.height / 2, 10, "white", "blue");
function init() {
newPlayer1 = new Player(canvas.width / 2, canvas.height / 2, 10, "white", "blue");
}
You also need context.stroke(); to draw the stroke (the "border of the circle").

Rectangle is not moving

I am trying to code a rectangle moving but it is not working and I do not understand why. I created a class for the rectangle and gave the parameters value. Then I drew the rectangle. I am trying to add the value of 5 to the rectangle's x but nothing is happening.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var width = 50;
class Rectangle{
constructor(x, y){
this.x = x;
this.y = y;
}
draw(){
ctx.beginPath();
ctx.rect(this.x, this.y, width, height);
ctx.fillStyle = "0095DD";
ctx.fill();
ctx.closePath();
}
}
function movingRectangle(){
var rect = new Rectangle(canvas.width/2 - width/2, 300);
rect.draw();
rect.x += 5;
}
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
movingRectangle();
}
var interval = setInterval(draw, 10);
You're recreating rect on each movingRectangle() call, effectively resetting its position to the initial value.
Move this:
var rect = new Rectangle(canvas.width/2 - width/2, 300);
Out of the movingRectangle() function - you only need to create the Rectangle instance once.
I managed to do a short example, based in your code, and leaving the Rectangle constructor outside:
function movingRectangle(){
let x = rect ? rect.x + 5 : canvas.width/2 - width/2;
if (!rect)
rect = new Rectangle(x, 300);
rect.x = x;
rect.draw();
}
https://jsfiddle.net/nicoavn/vc254q0a/4/

What is the best way to remove/delete a function object once instantiated/drawn to canvas?

The snippet code below shows a single function object called "Circle" being drawn to a canvas element. I know how to remove the visual aspect of the circle from the screen. I can simply change its opacity over time with c.globalAlpha=0.0; based on event.listener 's or 'object collision', However if I visually undraw said circle; it still is there and being computed on, its still taking up browser resources as it invisibly bounces to and fro on my canvas element.
So my question is: What is the best way to remove/delete a function object once instantiated/drawn to canvas? =>(so that it is truly removed and not invisibly bouncing in the browser)
let canvas = document.getElementById('myCanvas');
let c = canvas.getContext('2d');
function Circle(x, y, arc, dx, dy, radius){
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.arc = arc;
this.cCnt = 0;
this.radius = radius;
this.draw = function() {
c.beginPath();
//context.arc(x,y,r,sAngle,eAngle,counterclockwise);
c.arc(this.x, this.y, this.radius, this.arc, Math.PI * 2, false); //
c.globalAlpha=1;
c.strokeStyle = 'pink';
c.stroke();
}
this.update = function() {
if (this.x + this.radius > canvas.width || this.x - this.radius < 0){
this.dx = -this.dx;
}
if (this.y + this.radius > canvas.height || this.y - this.radius < 0){
this.dy = -this.dy;
}
this.x += this.dx;
this.y += this.dy;
this.draw();
}
}
var circle = new Circle(2, 2, 0, 1, 1, 2); // x, y, arc, xVel, yVel, radius
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, canvas.width, canvas.height)
circle.update();
}
animate();
body {
background-color: black;
margin: 0;
}
<canvas id="myCanvas" width="200" height="60" style="background-color: white">
A lot of canvas libraries solve this problem by keeping an array of objects that are in the canvas scene. Every time the animate() function is called, it loops through the list of objects and calls update() for each one (I'm using the names you're using for simplicity).
This allows you to control what is in the scene by adding or removing objects from the array. Once objects are removed from the array, they will no longer be updated (and will get trash collected if there are no other references hanging around).
Here's an example:
const sceneObjects = [];
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, canvas.width, canvas.height);
// Update every object in the scene
sceneObjects.forEach(obj => obj.update());
}
// Elsewhere...
function foo() {
// Remove an object
sceneObjects.pop();
// Add a different object
sceneObjects.push(new Circle(2, 2, 0, 1, 1, 2));
}
It's not uncommon to take this a step further by creating a Scene or Canvas class/object that keeps the list of scene objects and gives an interface for other parts of the program to use (for example, Scene.add(myNewCircle) or Scene.remove(myOldCircle)).

how to make modular, oo "animations" with canvas / JavaScript?

I come from a flash animation background, and am learning to create animations with HTML5 <canvas> and plain JavaScript.
In flash, you can draw a movieclip and link it to an actionScript class file. This makes each movieclip somewhat OO / modular and allows you to more easily call and reference them in your app.
As JS has no native class support, and drawing with Canvas seems more rudimentary than in Flash, what is an example of a way to structure your javascript for a large/complex canvas animation?
You can use a pseudo-class approach by using objects.
For example, if you want to lets say move a box across the canvas you define the box as an object and update it for each frame:
Live demo
function ooRect(x, y, w, h, color, dx, dy) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = color;
this.dx = dx;
this.dy = dy;
}
Now ooRect is an object which you can update to move around and change color etc.
You can extend it with methods which makes it self-contained update-wise so it updates itself per frame:
function ooRect(x, y, w, h, color, dx, dy) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = color;
this.dx = dx;
this.dy = dy;
this.update = function(ctx) {
this.x += this.dx;
this.y += this.dy;
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
You can now have a "host" routine (or another special object) to update all your objects stored in the array:
var objects = [
new ooRect(10, 20, 50, 70, 'blue', 2, 3),
new ooRect(200, 300, 50, 70, 'red', -3, 2) /// etc.
];
(function loop() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); /// clear canvas
for(var i = 0, o; o = objects[i++];) /// update all objects
o.update(ctx);
requestAnimationFrame(loop); /// next frame
})();
Now it is a matter of implementing different types of shape objects with its properties and methods.
If you plan to use a lot of objects you can prototype them as that allow the browser to share code-base memory:
function ooRect(x, y, w, h, color, dx, dy) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = color;
this.dx = dx;
this.dy = dy;
}
ooRect.prototype.update = function(ctx) {
this.x += this.dx;
this.y += this.dy;
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
Go with requirejs which is JavaScript file and module loader.
http://requirejs.org/

How to use Prototypal Pattern to make an html5 rectangle for reuse

I'm trying to understand Prototypal Inheritance using the Prototypal pattern by making a rectangle object and an instance of the rectangle. Seems easy, but I'm not getting it. The RectanglePrototype's method is not drawing the rectangle onto the canvas. If I use the same function as the method it works. Where am I going wrong? Also, I understand that I will need to make an initialization function, but I'm thinking I can do that later after I get the first basic steps down.
javascript:
window.onload = function () {
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var RectanglePrototype = {
// Properties
x: 0,
y: 0,
width: 100,
height: 100,
color: "white",
// Method
get:function (x, y, width, height, color) {
context.translate(0 , 0);
context.beginPath();
context.rect(x, y, width, height);
context.fillStyle = color;
context.fill();
return this.x, this.y, this.width, this.height, this.color;
}
};
console.log(RectanglePrototype.get);
// Instance of RectanglePrototype
var rectangle1 = Object.create(RectanglePrototype);
rectangle1.x = 200;
rectangle1.y = 100;
rectangle1.width = 300;
rectangle1.height = 150;
rectangle1.color = '#DBE89B';
// Draw Rectangle Function
function rect(x, y, width, height, color) {
context.translate(0 , 0);
context.beginPath();
context.rect(x, y, width, height); // yLoc-canvas.height = -300
context.fillStyle = color;
context.fill();
};
rect(0, 450, 50, 50, '#F7F694');
}
</script>
Prototypes are extensions of objects that result from a constructor. Method lookups go through the object properties before looking into prototype.
I proper JS design, you would only add the non-function properties in your constructor.
//Your constructor
function Rectangle(){
// Properties
this.x = 0;
this.y = 0;
this.width = 100;
this.height = 100;
this.color = 'red';
}
And then put the methods in your prototype:
//I prefer the term 'draw'
Rectangle.prototype.draw = function(ctx){
ctx.save();
ctx.beginPath();
ctx.rect(this.x, this.y, this.width, this.height);
ctx.fillStyle = this.color;
ctx.fill();
ctx.restore();
};
Then, to use in your project:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
//List of your shapes to draw on the canvas
var shapes = [];
//Instance of Rectangle
var rectangle1 = new Rectangle();
rectangle1.x = 200;
rectangle1.y = 100;
rectangle1.width = 300;
rectangle1.height = 150;
rectangle1.color = '#DBE89B';
shapes.push(rectangle1);
//Draw your shapes
function draw(){
window.requestAnimationFrame(draw); //See MDN for proper usage, but always request next fram at the start of your draw loop!
for(var i = 0; i<shapes.length; i++){
shapes[i].draw(context);
}
}
This is the 'proper' way of drawing to the canvas. For anything larger scale, please look into existing engines that do a looooot of hard work for you and have thought of everything so you don't have to. I have worked on such engines.

Categories

Resources