simple requestAnimationFrame not working JavaScript - javascript

I am currently trying to understand animation using JavaScript and HTML5.
From what I have gathered after researching on the internet, requestAnimationFrame repeatedly calls a method.
I have created a plane, and created a method which will move the plane in a diagonal line. However, it there seems to be no animation.
I'm fairly new to this so it could be just me not quite getting the concept. I don't think it is to do with my browser as I have tried it on both chrome and internet explorer, and they should be up to date as I only installed them a few months ago as this is a new laptop.
Here is my main class, it should include all relevent code:
/*global window, document, alert, Vector, Moth, Matrix, Plane, SceneGraphNode*/
function onLoad() {
var mainCanvas, mainContext, planePosition, plane;
// this function will initialise our variables
function initialiseCanvasContext() {
// Find the canvas element using its id attribute.
mainCanvas = document.getElementById('mainCanvas');
// if it couldn't be found
if (!mainCanvas) {
// make a message box pop up with the error.
alert('Error: I cannot find the canvas element!');
return;
}
// Get the 2D canvas context.
mainContext = mainCanvas.getContext('2d');
if (!mainContext) {
alert('Error: failed to get context!');
return;
}
planePosition = new Vector(0, 0, 0);
plane = new Plane(planePosition);
}
function translate(pPosition) {
var matrix = Matrix.createTranslation(pPosition);
matrix.transform(mainContext);
}
function scale(pPosition) {
var matrix = Matrix.createScale(pPosition);
matrix.transform(mainContext);
}
function rotate(pPosition) {
var matrix = Matrix.createRotation(pPosition);
matrix.transform(mainContext);
}
function drawPlane() {
scaleVector = new Vector(0.25, 0.25, 0);
scale(scaleVector);
translate(new Vector(0, 0));
rotate(0);
plane.draw(mainContext);
}
function drawMoth() {
var moth, mothPosition;
mothPosition = new Vector(mainCanvas.width / 2, mainCanvas.height / 2, 0);
moth = new Moth(mothPosition);
moth.draw(mainContext);
}
function drawPlane() {
plane = new Plane(planePosition);
scale(new Vector(0.25, 0.25, 0));
plane.draw(mainContext);
}
function animatePlane() {
translate(planePosition.add(new Vector(100, 100, 0)));
drawPlane();
window.requestAnimationFrame(animatePlane);
}
initialiseCanvasContext();
drawMoth();
animatePlane();
}
window.addEventListener('load', onLoad, false);
Please let me know if you think it would help to see any associated methods. I have also attached the result.

A lot of things are undefined here (the Matrix and Vector objects and their methods). Please include the code if you have it, otherwise keep reading.
It seems you've got a bit of a gap in your Object-Oriented JS knowledge. I'm guessing you know a good chunk of this, but it will be worth your time to solidify your knowledge of the following:
Know how to make a new object. Understand what an object is.
Understand how to make a constructor function.
Understand that using the new keyword simply calls an object's constructor function.
Understand inheritance. The this keyword vs. prototypical inheritance.
Understand encapsulation.
Understand the Canvas API
Add comments to your code. If other people are going to read you're code, please add comments. It helps. All you really need is a single comment per function explaining what it does. Explaining what the input parameters are is useful to.
Here are some resources to get you started (and perhaps finished):
Read this (and it's two prerequisites): http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/
Check out the built-in Canvas methods: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API
Here are the code structures that were missing
function Vector(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
var Matrix = {
createTranslation: function() {
},
createRotation: function() {
},
createScale: function() {
},
transform: function() {
}
};
function Plane(position) {
this.add = function() {
this.draw = function() {
};
};
}
function Moth(position) {
this.draw = function() {
};
}
I know this doesn't answer your question and I'm likely about to be downvoted to hell, but I can't really help you until you understand what you're doing a bit better. Good luck!

Related

How to mock a nested method?

I'm learning more about Jasmine Unit Testing and I've ran into something that I can't figure out. I'm new to both JavaScript and Unit Testing. I've tried to look for examples about nested methods and mocking them, but I'm still unable to have a successful test. I'm making a game with PhaserJS (HTML5 Game Library) and I've written successful tests so far. This is an example of my successful test.
function createGameScreenBorder(gameState) {
var border = gameState.game.add.graphics();
}
This is my test block.
it("create gamescreen background border", function() {
gameState.game = {
add: jasmine.createSpyObj('add', ['graphics'])
};
createGameScreenBorder(gameState);
expect(gameState.game.add.graphics).toHaveBeenCalled();
});
Now the above code works, it doesn't do much. What I want is to draw a rectangle which is a method part of the graphics method.
function createGameScreenBorder(gameState) {
var border = gameState.game.add.graphics();
// drawRect: x, y width, length
border.drawRect(0, 0, 0, 0);
}
This is my test block.
it("create gamescreen background border", function() {
gameState.game = {
add: {
graphics: jasmine.createSpyObj('graphics', ['drawRect'])
}
}
createGameScreenBorder(gameState);
expect(gameState.game.add.graphics).toHaveBeenCalled();
expect(gameState.game.add.graphics().lineStyle).toHaveBeenCalledWith(0,0,0,0);
});
I want to be able to make sure that drawRect() is called with my parameters, but I am confused as to how to do it.
Thank you!
The gameState.game.add.graphics() returns an object that has a drawRect() method on it.
First you want to check if the gameState.game.add.graphics() was called - this is already done. Then check if the drawRect() was called on the object returned from this method. To do that, set up your spy to return an object that also has a spy on it.
it("create gamescreen background border", function() {
let resultObject = {
drawRect: jasmine.createSpy()
};
gameState.game.add = {
graphics: jasmine.createSpy().and.callFake(() => {
return resultObject;
})
};
createGameScreenBorder(gameState);
expect(gameState.game.add.graphics).toHaveBeenCalled();
expect(resultObject.drawRect).toHaveBeenCalledWith(0, 0, 0, 0);
});

Javascript: using one function on multiple elements

I'm new to JavaScript and I'm having trouble figuring out how to resize multiple elements with one function for my rhythm game. This is for my CSP class and theres no use of jQuery sadly. I'm also limited to the commands that the program (AppLab) I'm using has provided. My goal right now is to make an "animation" of a circle growing to its desired size to indicate that it should be clicked. I need these elements to appear while another one is in the process growing and so on.
I'm aware that my code probably sucks so if there is also a way to simplify or improve it I would love to know.
This is my current program code and the hitIndicator function is the one I'm having the most trouble with:
var circleSizeW = 0;
var circleSizeL = 0;
var score = 0;
hitCircle("hitcircle", 300, 6, 206);
hitCircle("image2", 300, 6, 682);
function circleEffects(circleid, whentohit) {
setTimeout(function() {
onEvent(circleid, "click", function() {
playSound("47 (1).mp3", false);
hideElement(circleid);
});
}, whentohit);
}
function hitIndicator(circleid, growthRate) {
var xPos = getXPosition(circleid);
var yPos = getYPosition(circleid);
var t = setInterval(function() {
circleSizeW = circleSizeW + growthRate;
circleSizeL = circleSizeL + growthRate;
xPos = xPos - (growthRate/2);
yPos = yPos - (growthRate/2);
showElement(circleid);
setSize(circleid, circleSizeW, circleSizeL);
setPosition(circleid, xPos, yPos);
if (circleSizeW >= 60) {
clearInterval(t);
circleSizeW = 0;
circleSizeL = 0;
}
}, 50);
}
function scoreSystem(circleid, whentohit) {
setTimeout(function() {
onEvent(circleid, "click", function() {
score = score + 100;
setText("scoreTrack", score);
});
}, whentohit);
}
function hitCircle(circleid, whentohit, growthRate, appearancetime) {
setTimeout(function() {
console.log("hitcircle");
circleEffects(circleid, whentohit);
hitIndicator(circleid, growthRate);
scoreSystem(circleid, whentohit);
}, appearancetime);
My code is nowhere near completion either so there are still many things that needs to be done.
I'm not sure how to have multiple circles running that function at similar times because when I try to fix the errors/change the values of the functions' parameters they sometimes loop twice, infinitely loop, or receive the changed values of the previous circle while the previous circle is still growing.
I am also fairly new with Javascript, but I have a fairly good idea of what should be done here.
I would write an object constructor for instantiating circles.
Scroll down this page to see how to make object constructors.
Then for your circle object add a hitindicator method.
This page covers methods.
Then set up a function that will retrieve and loop through every instantiated circle object and run .hitindicator on each circle. Best way to do this, might be to add every instantiated circle to a circle array, then just loop through the array?
Then have an update() function that calls the function in step 3, and have update() called every "frame" with setInterval.
The pages linked should give you enough information to figure it out from here.

Simple ball animation HTML5 using requestAnimationFrame

I am just starting trying to make some animation using HTML5 and JavaScript.
Currently I have created a JavaScript class for the ball. It has an update function which should update the position of the ball and a draw function which should draw it:
/*global Vector*/
var Ball = (function () {
function Ball(pPostion) {
this.setPosition(pPostion);
}
Ball.prototype.getPosition = function () {
return this.mPosition;
};
Ball.prototype.setPosition = function (pPosition) {
this.mPosition = pPosition;
};
Ball.prototype.draw = function (pContext) {
pContext.save();
pContext.beginPath();
pContext.arc(100, 100, 20, 0, Math.PI * 2, true);
pContext.closePath();
pContext.fillStyle = '#ff0000';
pContext.stroke();
pContext.restore();
};
Ball.prototype.update = function () {
this.getPosition().add(new Vector(10, 0));
};
return Ball;
}());
In the my main section I have created the following method:
function ballGameLoop() {
ball.draw(mainContext);
ball.update();
requestAnimationFrame(ballGameLoop);
}
And when called, it does draw the ball but it doesn't seem to move at all. I don't have a specific type of way I want the ball to be animated, just any kind of movement would be good. Can anyone give any advice on where I may be going wrong?
From the looks of it, it seems you are just drawing an arc at the same coordinates over and over again (center at (100,100)).
Incorporating your Ball's position into this would be the way to make the render location dependent on the object's position. From what it seems, something along the lines of the following would give movement:
Ball.prototype.draw = function (pContext) {
var coordinates = this.getPosition();
pContext.save();
pContext.beginPath();
pContext.arc(coordinates.X, coordinates.Y, 20, 0, Math.PI * 2, true);
pContext.closePath();
pContext.fillStyle = '#ff0000';
pContext.stroke();
pContext.restore();
};
I'm of course assuming on how you setup the Vector object, so I'm guessing x and y can be accessed by (Vector).X and (Vector).Y respectively.
anyway just my approach at it.

p5.js creating a new Vector error

So i'm trying to rewrite some of main proccessing sketches to p5.js, but (there is always a but..) i have a problem with creating Vecotrs. I think i'm lacking some simple java script uderstanding here.
So i use the example provided with p5.js, and my code looks like that:
var location ;
function setup() {
createCanvas(1000, 1000);
background(0);
location = new Vector(0, 0);
//location = createVector(0, 0);
//location = new p5.Vector(0, 0);
}
function draw() {
ellipse(location.x, location.y, 80, 80);
}
function Vector (x,y) {
this.x = x;
this.y = x;
}
I tryied 3 ways of creating vectors, the one right now, with creating custom "class" Vector, and those 2 commented out. And if i try it out, i have page not found and address bar is changed to "address to my index.html/p5.Vector%20Object%20:%20[0,%200,%200]".
I really have now idea what is wrong.
The variable name was the culprit. I was actualy accessing window.location . Simple name change did the trick.

HTML Canvas Unit testing

How can I unit-test Javascript that draws on an HTML canvas? Drawing on the canvas should be checked.
I wrote an example for unit-testing canvas and other image-y types with Jasmine and js-imagediff.
Jasmine Canvas Unit Testing
I find this to be better than making sure specific methods on a mock Canvas have been invoked because different series of methods may produce the same method. Typically, I will create a canvas with the expected value or use a known-stable version of the code to test a development version against.
As discussed in the question comments it's important to check that certain functions have been invoked with suitable parameters. pcjuzer proposed the usage of proxy pattern. The following example (RightJS code) shows one way to do this:
var Context = new Class({
initialize: function($canvasElem) {
this._ctx = $canvasElem._.getContext('2d');
this._calls = []; // names/args of recorded calls
this._initMethods();
},
_initMethods: function() {
// define methods to test here
// no way to introspect so we have to do some extra work :(
var methods = {
fill: function() {
this._ctx.fill();
},
lineTo: function(x, y) {
this._ctx.lineTo(x, y);
},
moveTo: function(x, y) {
this._ctx.moveTo(x, y);
},
stroke: function() {
this._ctx.stroke();
}
// and so on
};
// attach methods to the class itself
var scope = this;
var addMethod = function(name, method) {
scope[methodName] = function() {
scope.record(name, arguments);
method.apply(scope, arguments);
};
}
for(var methodName in methods) {
var method = methods[methodName];
addMethod(methodName, method);
}
},
assign: function(k, v) {
this._ctx[k] = v;
},
record: function(methodName, args) {
this._calls.push({name: methodName, args: args});
},
getCalls: function() {
return this._calls;
}
// TODO: expand API as needed
});
// Usage
var ctx = new Context($('myCanvas'));
ctx.moveTo(34, 54);
ctx.lineTo(63, 12);
ctx.assign('strokeStyle', "#FF00FF");
ctx.stroke();
var calls = ctx.getCalls();
console.log(calls);
You can find a functional demo here.
I have used a similar pattern to implement some features missing from the API. You might need to hack it a bit to fit your purposes. Good luck!
I make really simple canvases and test them with mocha. I do it similarly to Juho Vepsäläinen but mine looks a little simpler. I wrote it in ec2015.
CanvasMock class:
import ContextMock from './ContextMock.js'
export default class {
constructor (width, height)
{
this.mock = [];
this.width = width;
this.height = height;
this.context = new ContextMock(this.mock);
}
getContext (string)
{
this.mock.push('[getContext ' + string + ']')
return this.context
}
}
ContextMock class:
export default class {
constructor(mock)
{
this.mock = mock
}
beginPath()
{
this.mock.push('[beginPath]')
}
moveTo(x, y)
{
this.mock.push('[moveTo ' + x + ', ' + y + ']')
}
lineTo(x, y)
{
this.mock.push('[lineTo ' + x + ', ' + y + ']')
}
stroke()
{
this.mock.push('[stroke]')
}
}
some mocha tests that evaluates the functionality of the mock itself:
describe('CanvasMock and ContextMock', ()=> {
it('should be able to return width and height', ()=> {
let canvas = new CanvasMock(500,600)
assert.equal(canvas.width, 500)
assert.equal(canvas.height, 600)
})
it('should be able to update mock for getContext', ()=> {
let canvas = new CanvasMock(500,600)
let ctx = canvas.getContext('2d')
assert.equal(canvas.mock, '[getContext 2d]')
})
})
A mocha tests that evaluates the functionality of a function that returns a canvas:
import Myfunction from 'MyFunction.js'
describe('MyFuntion', ()=> {
it('should be able to return correct canvas', ()=> {
let testCanvas = new CanvasMock(500,600)
let ctx = testCanvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(0,0)
ctx.lineTo(8,8)
ctx.stroke()
assert.deepEqual(MyFunction(new CanvasMock(500,600), 8, 8), canvas.mock, [ '[getContext 2d]', '[beginPath]', '[moveTo 0, 0]', [lineTo 8, 8]', '[stroke]' ])
})
so in this example myfunction takes the canvas you passed in as an argument ( Myfunction(new CanvasMock(500,600), 8, 8) ) and writes a line on it from 0,0 to whatever you pass in as the arguments ( Myfunction(new CanvasMock(500,600),** 8, 8**) ) and then returns the edited canvas.
so when you use the function in real life you can pass in an actual canvas, not a canvas mock and then it will run those same methods but do actual canvas things.
read about mocks here
Since the "shapes" and "lines" drawn on a canvas are not actual objects (it's like ink on paper), it would be very hard (impossible?) to do a normal unit test on that.
The best you can do with standard canvas it analyze the pixel data (from the putImageData/getImageData. Like what bedraw was saying).
Now, I haven't tried this yet, but it might be more what you need. Cake is a library for the canvas. It's using alot of the putImageData/getImageData. This example might help with what you are trying to do with a test.
Hope that helps answer your question.
I've been looking at canvas testing recently and I've now thought about a page that allows comparing the canvas to a "known good" image version of what the canvas should look like. This would make a visual comparison quick and easy.
And maybe have a button that, assuming the output is OK, updates the image version on the server (by sending the toDataUrl() output to it). This new version can then be used for future comparisons.
Not exactly (at all) automated - but it does make comparing the output of your code easy.
Edit:
Now I've made this:
The left chart is the real canvas whilst the right is an image stored in a database of what it should look like (taken from when I know the code is working). There'll be lots of these to test all (eventually) aspects of my code.
From a developer's point of view the canvas is almost write-only because once drawn it's difficult to programmatically get something useful back. Sure one can do a point by point recognition but that's too tedious and such tests are hard to be written and maintained.
It's better to intercept the calls made to a canvas object and investigate those. Here are a few options:
Create a wrapper object that records all the calls. Juho Vepsäläinen posted a such example.
If possible use a library like frabric.js that offers a higher level of abstraction for drawing. The "drawings" are JS objects that can be inspected directly or converted to SVG which is easier to inspect and test.
Use Canteen to intercept all the function calls and attribute changes of a canvas object. This is similar with option 1.
Use Canteen with rabbit which offers you a few Jasmine custom matchers for size and alignment and a function getBBox() that can be used to determine the size and the position of the stuff being drawn on the canvas.

Categories

Resources