GreenSock, tween function arguments - javascript

I got two functions called on mouse events:
function menuBtnOver(e){
var b = e.data;
b.setPosition(b.x, b.y+5);
}
function menuBtnOut(e){
var b = e.data;
b.setPosition(b.x, b.y-5);
}
and:
setPosition:function(x, y) {
if(!x) x = 0;
if(!y) y = 0;
this.element.css("left", x);
this.element.css("top", y);
}
element property is a jQuery object.
It is working ok but i want to animate this. How can i do this with TweenLite?
I've tried following code:
function menuBtnOver(e){
TweenLite.to(e.data, 1, {top:500});
}
As well as this:
function menuBtnOver(e){
TweenLite.to(e.data.getElement(), 1, {top:500});
}
and many other combinations but none of them worked.
Only on method which partially work is this:
function menuBtnOver(e){
TweenLite.to(e.data, 1, {y:400, onUpdate:e.data.setPosition, onUpdateParams:[e.data.x, e.data.y]});
}
But it work only on fist button when I roll over and (after any time) roll out, it moves directly to given position (without tween) and then the tween goes forever giving me error each time(at least - I couldn't get any errors or anything with other attempts).
Uncaught TypeError: Cannot read property 'css' of undefined
at: this.element.css("left", x);
Update
I figured out what is going on.
I've changed code as so:
function menuBtnOver(e){
TweenLite.to(e.data, 1, {y:400, onUpdate:e.data.setPosition, onUpdateParams:[e.data.x, e.data.y], onUpdateScope:e.data});
}
But the problem with this is that arguments to update function which I set to e.data.y/x aren't dynamic references and always stay as those exact values from menuBtnOver state. So the tween works if i change setPosition function to:
setPosition:function(x, y) {
if(!x) x = 0;
if(!y) y = 0;
this.element.css("left", this.x);
this.element.css("top", this.y);
}
But obviously this is not what I want to do.
So I have option to make something like this:
MenuButton.prototype = {
setPosition:function(x, y) {
if(!x) x = 0;
if(!y) y = 0;
this.x = x; this.y = y;
this.element.css("left", x);
this.element.css("top", y);
},
updatePosition:function(){
this.element.css("left", this.x);
this.element.css("top", this.y);
}
}
function menuBtnOver(e){
TweenLite.to(e.data, 1, {y:400, onUpdate:e.data.updatePosition, onUpdateScope:e.data});
}
Or define external update function in similar manner. The question still stays the same so is there a simple way to do this simpler. Does GS tween has any mechanic which automate this process?
Thanks to everyone for attention :)

this in setPosition is referring to that function and not the this of the onClick event.
you need to do pass this to setPosition. As in the example below, where I passed it as self in the function setPosition.
function menuBtnOver(e){
var b = e.data;
b.setPosition(this, b.x, b.y+5);
}
function menuBtnOut(e){
var b = e.data;
b.setPosition(this, b.x, b.y-5);
}
and:
setPosition:function(self, x, y) {
if(!x) x = 0;
if(!y) y = 0;
self.element.css("left", x);
self.element.css("top", y);
}
this always refernces the function in which is was called. as you can read about her. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
So you can pass this in a function as a variable.

Related

Calling function bad argument

I'm trying to write a game and I got a problem with function showing player:
function Furry() {
this.board=document.querySelectorAll('#board div');
this.x = 0;
this.y = 0;
this.direction = "right";
}
and:
showFurry=function(){
this.x = Math.floor(Math.random() * 10);
this.y = Math.floor(Math.random() * 10);
this.board[ this.position(this.furry.x , this.furry.y) ].classList.add('furry');
}
and in consol when I want to call function I got this:
Uncaught TypeError: Cannot read property 'x' of undefined
https://jsfiddle.net/mdx3w24c/
At this state after calling function showFurry and showCoin I should receive this:
Try removing the functions showFurry and showCoin. Then, make a function in the Game class that will do those things.
Game.prototype.start = function() {
this.board[this.position(this.coin.x, this.coin.y)].classList.add('coin');
this.board[this.position(this.furry.x, this.furry.y)].classList.add('furry');
};
Then when you start your game, instead of calling showFurry and showCoin you can call Game.start();
var game = new Game();
game.start();
Also your Coin constructor set random values to x & y, but the furry construct set them both to 0, then set them to random values in the showFurry function. In this fiddle, I've moved that to the constructor.

ES6 Setting Properties

I've looked into it, and it seems as though ES6 doesn't have the ability to set properties of a class, and return that class?
class MyClass {
constructor() {
this.x = 0;
this.y = 0;
}
update(value) {
// logic
this.y = value;
return value;
}
}
var x = new MyClass();
console.log(x.update(1));
With the above, x will keep y as 0, even though setting y to 1. console.log will put out 1, but y is never actually updated. Calling x.y will result in 0.
I've also attempted returning the class, yet that doesn't work either.
class MyClass {
constructor() {
this.x = 0;
this.y = 0;
}
update(value) {
// logic
this.y = value;
return this;
}
}
var x = new MyClass();
x = x.update(1);
Using console.log(x) afterwards would once again result in y being 0, and not 1.
I'm aware of set and get, but then I wouldn't be able to perform any logic within update() or return anything.
Is this intended, or am I completely doing it wrong?
I would like to note that I'm using NodeJS.
I am doing something such as:
class.js ->
module.exports = /*class MyClass{}*/ (the above MyClass code)
app.js ->
let MyClass = require('class');
let x = new MyClass();
x.update(1);
console.log(x) (this returns the same value as x before calling update())
Calling x.y will result in 0
No it does. This suggests that your // logic is flawed. If there is no extra logic, the x.y property does end up as 1.
It works!
var x =new MyClass();
console.log(x.update(1)); //1
console.log(x.y); //1

Is it possible to check if a function arguments bound correctly using Sinon.JS

Let say we have a function that returns a function and bounds arguments to it:
function A(x, y){
return function(x, y){...}.bind(this, x, y);
}
And now we want to know if function A binds arguments correctly:
var resultedFunction = A();
var spy = sinon.spy(resultedFunction);
spy();
The question - is it possible to know if arguments are bound correctly? I've tried this, but it is an empty array
spy.firstCall.args
spy.getCall(0).args
I've finally come to some trick. If the returning function will be not an anonymous then we can spy it and check arguments later:
var obj = {
B: function(){
...
},
A: function(x, y){
return this.B.bind(this, x, y);
}
}
var x = 1, y = 2;
var spy = sinon.spy(obj, "B");
var resultedFunction = obj.A(x, y);
resultedFunction();
expect(spy.firstCall.args[0]).to.equals(x)
expect(spy.firstCall.args[0]).to.equals(y)

Getting object fields and calling object functions in JavaScript

I just started fiddling around with JavaScript. Coming from Java and OO PHP things are getting weirder with every step :)
This is my introduction project to javascript in which I've set out to program multiplayer working version of Settlers of Catan. Code below is an attempt to store cube coordinates of N sized hexagonal map tiles in an array.
I've read you declare object in javascript by assigning functions to variables.
var Tile = function (x, y, z) {
this.x = x;
this.y = y;
this.z = z;
};
var Map = function () {
var grid = [];
function generate_map(radius) {
for (width = -radius; width <= radius; width++) {
var r1 = Math.max(-radius, -width - radius);
var r2 = Math.min(radius, -width + radius);
for (r = r1; r <= r2; r++) {
grid.push(new Tile(width, r, -width - r));
}
}
}
};
I've tried instantiating new Map object, calling its only function and outprinting the resulting values stores in grid[] array. But for each loop is not playing nice :( I get the unexpected identifier.
var main = function () {
var basic_map = new Map();
basic_map.generate_map(3);
for each (var tile in basic_map.grid) {
console.log(tile.x, tile.y, tile.z);
}
};
main();
I am fully aware this is one of those face palm errors, but help would nevertheless be appreciated, cheers!
Change this:
function generate_map(radius) {
...to this:
this.generate_map = function(radius) {
Edit: there are actually more issues than I at first realized.... :)
A few other tips:
First, I would recommend changing:
var Tile = function (x, y, z) {
...to simply be:
function Tile(x, y, z) {
(the same goes for Map). Your current solution works fine, but it's not very idiomatic, and until ES6 there was nothing in the spec that would cause var Tile = function to cause the resulting function's 'name' property to be set to "Tile", which is useful when it comes to debugging. I recently wrote another answer that delves a bit more into the differences between, e.g., function Foo() {} and var Foo = function() {}.
Second, you probably want to rename Map to something else. Map is a core part of ES6 now (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).
Third, even though you can create your generate_map function using this.generate_map, you may want to move it to the Map's prototype. Also, since you need to expose the grid value, you want to store it as a property, rather than a local variable scoped to the NewMapName constructor. E.g.,:
function NewMapName() {
this.grid = [];
}
NewMapName.prototype.generateMap = function(radius) {
// you can access the grid here via `this.grid`
...
};
By moving it to the prototype, that means all instances of NewMapName will share the same function reference, rather than it being created over-and-over-and-over (although maybe you really only create it once? Either way, it's more idiomatic, at a minimum). Note that I took some liberties with the "camelCasing" here (see the last point).
Fourth, your generateMap implementation is leaking some global variables (width and r, since you don't declare them with var). I would change that to this:
NewMapName.prototype.generateMap = function(radius) {
for (var width = -radius; width <= radius; width++) {
var r1 = Math.max(-radius, -width - radius);
var r2 = Math.min(radius, -width + radius);
for (var r = r1; r <= r2; r++) {
grid.push(new Tile(width, r, -width - r));
}
}
};
Fifth, your loop is kind of broken. I would refactor that as follows:
var main = function () {
var basicMap = new NewMapName();
basicMap.generateMap(3);
basicMap.grid.forEach(function(tile) {
console.log(tile.x, tile.y, tile.z);
});
};
main();
Lastly, and probably most minor, is that in JavaScript-land, camelCase is far more dominant that snake_case, so generate_map might be "better" as generateMap.

Global variable and addEventlistener

Here is the problem: I would like to have global variable X which takes value of alpha. With code below, value for X in console is always zero.
var X = 0;
window.addEventListener("deviceorientation", handleOrientation, true);
function handleOrientation(event) {
var alpha = Math.round(event.alpha);
X = alpha;
}
console.log(X);
EDIT:
I wanted to do something like
var X = 0;
window.addEventListener("deviceorientation", handleOrientation, true);
function handleOrientation(event) {
var alpha = Math.round(event.alpha);
X = alpha;
}
function f(x){ return x*x }
f(X);
Now I understand that I have to put f(X) within function handleOrientation. I guess there is not other way around?
You're using the value of X before it changes. Here's the order in which your code runs:
Create a function called handleOrientation. (Why first? Because creating the functions described by function declarations is one of the very first things done upon entry to a scope.)
Declare a variable called X. (First not only because it's at the top, but because creating variables declared with var is one of the very first things done upon entry to a scope, soon after processing function declarations.)
Assign 0 to X. (This is the first step-by-step code that runs.)
Call addEventListener on window.
Output X to the console.
(If and when the deviceorientation event is triggered on window) Update the value of X.
Instead, use the value after it changes:
var X = 0;
window.addEventListener("deviceorientation", handleOrientation, true);
function handleOrientation(event) {
var alpha = Math.round(event.alpha);
X = alpha;
console.log(X);
}
Or:
var X = 0;
window.addEventListener("deviceorientation", handleOrientation, true);
function handleOrientation(event) {
var alpha = Math.round(event.alpha);
X = alpha;
doSomethingWithX();
}
function doSomethingWithX() {
console.log(X);
}

Categories

Resources