Why are my properties losing definition? (JS) - javascript

I'm creating a drag/drop heavy page and giving each draggable element defaultTop and defaultLeft properties so that I can easily reset it to it's original position. This was fine and unremarkable until suddenly, the reset function reports their values as undefined. Since I wasn't working on these pieces when it broke (they've been working for some time) I'm not sure where I've gone wrong. Thanks for the help.
The function that creates the element is:
function makeTool(id, imgURL, defaultL, defaultT,trayname){
var a=document.createElement('img');
a.setAttribute('src', imgURL);
a.setAttribute('id',id);
a.setAttribute('class','drag');
a.intray=true;
a.tray=trayname;
a.rotation=0;
a.style.zIndex=document.getElementById(trayname).style.zIndex+1;
document.getElementById(trayname).appendChild(a);
a.defaultTop=ExtractNumber(document.getElementById(trayname).style.top)+defaultT;
a.defaultLeft=ExtractNumber(document.getElementById(trayname).style.left)+defaultL;
a.style.top=a.defaultTop+'px';
a.style.left =a.defaultLeft+'px';
a.addEventListener('touchstart', function(e) { return self.touchStart(e) }, false);
a.addEventListener('gesturestart', function(e) { return self.gestureStart(e) }, false);
a.addEventListener('touchmove', function(e) { return self.touchMove(e) }, false);
a.addEventListener('touchend', function(e) { return self.touchEnd(e) }, false);
tools.push(a);
return a;
}
and the reset function is:
function reposition(t){
console.log(t+' top: '+document.getElementById(t).defaultTop);
document.getElementById(t).style.left=document.getElementById(t).defaultLeft+'px';
document.getElementById(t).style.top=document.getElementById(t).defaultTop+'px';
}
which is where I'm getting the log of undefined

I'm not sure if thar helps, but I had a similar problem.
I was writing a object to calculate de width of my DIVs accordingly to my innerWidth:
function ScreenGrid() {
'use strict';
this.ColumnIDs = new Array();
this.Widths = new Array();
this.Dynamic = true;
this.Set = adjust;
var ColumnIDsPersist;
var WidthsPersist;
function adjust() {
//stuff
for (var i = 0; i < ColumnIDsPersist.length; i++) {
The adjust function is where de magic happends. To ensure that the DIVs would keep fitted in the screen I used the following code:
if (window.addEventListener) {
// Good browsers.
window.addEventListener('resize', react, false);
}
else if (w.attachEvent) {
// Legacy IE support.
window.attachEvent('onresize', react);
}
else {
// Old-school fallback.
window.onresize = react;
}
And this is the react function:
// Slight delay.
function react() {
// Clear the timer as window resize fires,
// so that it only calls adapt() when the
// user has finished resizing the window.
clearTimeout(timer);
// Start the timer countdown.
timer = setTimeout(adjust, 16);
// -----------------------^^
// Note: 15.6 milliseconds is lowest "safe"
// duration for setTimeout and setInterval.
//
// http://www.nczonline.net/blog/2011/12/14/timer-resolution-in-browsers
}
The problem was the every time REACT fires, o got undefined in this.ColumnIDs. After a lot o investigation i noticed that when I fired the ADJUST from SET() the object THIS was my SCREENGRID, but when I fired from REACT it becames the WINDOW, so I got undefined in this.ColumnIDs.
I solved with this code:
function ScreenGrid() {
'use strict';
this.ColumnIDs = new Array();
this.Widths = new Array();
this.Dynamic = true;
this.Set = adjust;
var ColumnIDsPersist;
var WidthsPersist;
function adjust() {
// This clearTimeout is for IE.
// Really it belongs in react(),
// but doesn't do any harm here.
clearTimeout(timer);
// Parse browser width.
var _width = window.innerWidth || window.document.documentElement.clientWidth || window.document.body.clientWidth || 0;
var _heigth = window.innerHeight || window.document.documentElement.clientHeight || window.document.body.clientHeight || 0;
var _usedWidth = 0;
var _fluidColumn = null;
//Ao chamar a função adjust novamente no evento on resize, o objeto THIS deixa de ser a função e passa a ser a janela,
//Essas vareáveis garantem a persistencia dos dados a serem utilizados.
ColumnIDsPersist = (typeof ColumnIDsPersist == 'undefined') ? this.ColumnIDs : ColumnIDsPersist;
WidthsPersist = (typeof WidthsPersist == 'undefined') ? this.Widths : WidthsPersist;
for (var i = 0; i < ColumnIDsPersist.length; i++) {
Well, that's it, I hope it helps!

Related

Phaser 2 determining which unit is active

I have 3 clickable objects. When one is clicked, this becomes the 'selected unit'.
I am trying to create some generic actions for the units such as moving to a point.
In my create function I initialize the units, when a unit is clicked on - this is supposed to become the 'selected unit' so that my movement and direction function applies to the this unit. However, the script is not able to recognize which unit intend for example I get this error:
Uncaught TypeError: Cannot read property 'velocity' of undefined.
Is there a way to use a variable to indicate selected users and pass that to the functions?
window.onload = function() {
var block_count = 0;
var block = '';
var selected_unit = '';
var unit_clicked = 0;
var tank1 = null;
var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update, render: render});
function preload () {
game.load.image('block', 'block.png');
game.load.image('tank1', 'tank.png');
game.load.image('baddie', 'tank.png');
game.load.image('mouse_btn', 'block.png');
game.input.mouse.capture = true;
}
function create () {
game.physics.startSystem(Phaser.Physics.ARCADE);
mouse_btn = game.add.sprite(30,30, 'mouse_btn');
mouse_btn.anchor.setTo(0.5, 0.5);
//T1
tank1 = game.add.sprite(30,30, 'tank1');
initialise_player(tank1);
game.physics.enable(tank1, Phaser.Physics.ARCADE);
//T2
tank2 = game.add.sprite(30,60, 'tank1');
initialise_player(tank2);
game.physics.enable(tank2, Phaser.Physics.ARCADE);
game.world.setBounds(0, 0, 2000, 2000);
game.camera.follow(tank1);
}
function update () {
if(selected_unit == '') {
mouse_btn.x = game.input.mousePointer.worldX
mouse_btn.y = game.input.mousePointer.worldY
}
if(game.input.activePointer.leftButton.isDown && block_count == 0 && unit_clicked == 0) {
game.input.activePointer.leftButton.stop(event);
block_count =1;
block = game.add.sprite(game.input.mousePointer.worldX, game.input.mousePointer.worldY, 'block');
game.physics.enable(block, Phaser.Physics.ARCADE);
block.anchor.setTo(0.5, 0.5)
lookAtObject(selected_unit, block, 0.005);
}
if(block.alive){
game.physics.arcade.moveToObject(selected_unit, block, 260, 0)
} else {
console.log(selected_unit)
selected_unit.body.velocity.x = 0;
selected_unit.body.velocity.y = 0;
}
if(game.physics.arcade.collide(selected_unit, block)) {
block_count--;
block.kill();
}
}
function render(){
//console.log(game.physics.arcade.collide(tank1, block))
}
function lookAtObject(obj, target, rotspeed){
var angle = Math.atan2(block.y - tank1.y, block.x - tank1.body.x);
tank1.rotation = angle + game.math.degToRad(90);
}
function initialise_player(tank1){
tank1.anchor.setTo(0.5, 0.5);
tank1.inputEnabled = true;
tank1.input.useHandCursor = true;
tank1.events.onInputDown.add(t1_clicked,this);
tank1.events.onInputOver.add(t1_over, this)
tank1.events.onInputOut.add(t1_out, this)
}
function t1_clicked() {
selected_unit = tank1;
}
function t1_over() {
unit_clicked = 1
}
function t1_out () {
unit_clicked = 0
}
};
The error you're getting on initial load is because in update you're making an assumption that selected_unit exists and has a body.
Update your third if to make sure selected_unit is defined.
if (selected_unit !== '') {
selected_unit.body.velocity.x = 0;
selected_unit.body.velocity.y = 0;
}
However, a better option would be to put this a few lines down, where you kill the block instead.
if(game.physics.arcade.collide(selected_unit, block)) {
selected_unit.body.velocity.x = 0;
selected_unit.body.velocity.y = 0;
block_count--;
block.kill();
}
if (block.alive); moveToObject is also expecting selected_unit to exist and have a body, which may not be the case; wrap it with a check.
if (selected_unit !== '') {
game.physics.arcade.moveToObject(selected_unit, block, 260, 0)
}
That now allows tank1 to rotate to look at the item you just placed, but it doesn't move it until it or tank2 have been clicked on.
This also points out that there are a number of tweaks you'll want to make to your code in general, since you're ignoring arguments that are being passed in. For example, t1_clicked isn't using the sprite that's been clicked on, but is instead just hard-coding tank1. lookAtObject isn't using obj or target, but again has values hard-coded in.
One other thing you may want to change is the following:
if(selected_unit == '') {
mouse_btn.x = game.input.mousePointer.worldX
mouse_btn.y = game.input.mousePointer.worldY
}
If you make that the following, you won't end up with an extra sprite hanging about on the screen.
if (block_count === 0) {
mouse_btn.x = game.input.mousePointer.worldX;
mouse_btn.y = game.input.mousePointer.worldY;
}

Javascript for loop doesn't work (adding numbers to a total)

I am using Jasmine for JS testing, and unfortunately I can't get the following test to pass.
it('should know the total game score', function() {
frame1 = new Frame;
frame2 = new Frame;
game = new Game;
frame1.score(3, 4);
frame2.score(5, 5);
expect(game.totalScore()).toEqual(17)
});
The error message I get is as follows: Error: Expected 0 to equal 17.
The code is as follows:
function Game() {
this.scorecard = []
};
Game.prototype.add = function(frame) {
this.scorecard.push(frame)
};
// Why is this not working!!???
Game.prototype.totalScore = function() {
total = 0;
for(i = 0; i < this.scorecard.length; i++)
{
total +=this.scorecard[i].rollOne + this.scorecard[i].rollTwo;
}
return total;
};
function Frame() {};
Frame.prototype.score = function(first_roll, second_roll) {
this.rollOne = first_roll;
this.rollTwo = second_roll;
return this
};
Frame.prototype.isStrike = function() {
return (this.rollOne === 10);
};
Frame.prototype.isSpare = function() {
return (this.rollOne + this.rollTwo === 10) && (this.rollOne !== 10)
};
Adding the numbers together manually seems to work e.g. total = game.scorecard[0].rollOne + this.scorecard[0].rollTwo , but the for loop (even though it looks correct) doesn't seem to work. Any help would be greatly appreciated :)
I am not pretty sure, but it seems that you are not calling the "Add" method, so no data is added to the scorecard.
You have to add the Frames to your game i guess
it('should know the total game score', function () {
frame1 = new Frame;
frame2 = new Frame;
game = new Game;
// those lines are missing
game.add(frame1);
game.add(frame2);
frame1.score(3, 4);
frame2.score(5, 5);
expect(17).toEqual(game.totalScore())
});
otherwise, the scorecard-array is empty and the total score is therefore equal to 0.
missing (so no data is added to the scorecard.)
game.Add(frame1);
game.Add(frame2);

Animation Array in JavaScript

I've come up with this little animation that uses images in an array, but it's sloppy. What I'd really like is to modularize it so that I can use multiple instances of the same function to animate different arrays depending on which key is pressed. Also, I'd like to get it so that the animation stops when the key is released, if possible. I realize that calling all of those variables globally is a big no-no, but I have no idea how to make it work otherwise! Last but not least, I'd like to figure out how to get that last bit of inline script over to the external file and have it still work correctly. Any help would be much appreciated! But please note, I'm a novice with JavaScript, so please try to be as specific/detailed as possible so I can learn from your wisdom! Thank you!
I've created a jsfiddle.
HTML:
<div id="wrapper">
<span id="jajo"><img id="my_img" src="jajo.png" /></span>
<script>element = document.getElementById("jajo"); </script>
</div><!--wrapper-->
JavaScript:
var i = 0;
var element;
var waveArray = ["wave0.png","wave1.png","wave2.png","wave3.png","wave4.png","wave5.png"];
var jumpArray = ["jump0.png","jump1.png","jump2.png","jump3.png","jump4.png","jump5.png"];
var foodArray = ["food0.png","food1.png","food2.png","food3.png","food4.png","food5.png"];
document.onkeydown = function(event) {
var keyPress = String.fromCharCode(event.keyCode);
if(keyPress == "W") { // if "w" is pressed, display wave animation
increment ();
document.onkeyup = function(event) { // if "w" is released, display default image
document.getElementById("jajo").innerHTML= "<img alt='Jajo' src='jajo.png'>";
}
} else if(keyPress == "A") { // if "a" is pressed, display jump animation
} else if(keyPress == "S") { // if "s" is pressed, display food animation
}
}
function increment (){
i++;
if(i > (waveArray.length - 1)){
i = 0;
}
setTimeout(animation,1000/30);
}
function animation() {
var img = '<img src="' + waveArray[i] + '" alt="Jajo" />';
element.innerHTML = img;
setTimeout(increment, 2000/30);
}
Demo
http://jsfiddle.net/ghQwF/4/
Module
var animation = (function() {
var delay = 1000 / 30;
var map = {}, active = [], timer;
function animate() {
for(var i=0, l=active.length; i<l; ++i) {
var data = map[active[i]];
++data.index;
data.index %= data.array.length;
data.image.src = data.array[data.index];
}
timer = setTimeout(animate, delay);
}
function begin(e) {
var key = String.fromCharCode(e.keyCode),
data = map[key];
if(!data) return;
if(!active.length) timer = setTimeout(animate, delay);
if(!~active.indexOf(key)) active.push(key);
}
function end(e) {
var key = String.fromCharCode(e.keyCode),
data = map[key];
if(!data) return;
data.image.src = data.default;
var index = active.indexOf(key);
if(!~index) return;
active.splice(index, 1);
if(!active.length) clearTimeout(timer);
}
return {
add: function(data) {
data.index = data.index || 0;
data.image = data.image || data.target.getElementsByTagName('img')[0];
data.default = data.default || data.image.src;
map[data.key] = data;
},
remove: function(key) {
delete map[key];
},
enable: function() {
document.addEventListener('keydown', begin, false);
document.addEventListener('keyup', end, false);
},
disable: function() {
document.removeEventListener('keydown', begin, false);
document.removeEventListener('keyup', end, false);
clearTimeout(timer);
active = [];
}
};
})();
Example
animation.enable();
animation.add({
key: 'W',
target: document.getElementById('jajo'),
array: [
"http://static.spoonful.com/sites/default/files/styles/square_128x128/public/crafts/fingerprint-flowers-spring-craft-photo-420x420-aformaro-01.jpg",
"http://static.spoonful.com/sites/default/files/styles/square_128x128/public/crafts/paper-flowers-spring-craft-photo-420x420-aformaro-11.jpg",
"http://static.spoonful.com/sites/default/files/styles/square_128x128/public/crafts/tissue-paper-flowers-kaboose-craft-photo-350-fs-IMG_8971_rdax_65.jpg"
]
});
animation.add({ /* ... */ });
Methods
add
Adds a new animation, with parameters:
key: key to activate animation
target: wrapper of the image (optional if image is specified)
image: image to animate (optional, defaults to first image in target)
default: default url of the image (optional, defaults to original url)
index: initial position in array (optional, defaults to 0)
array: array of images
remove
Removes the animation related with key specified.
disable
Disables animations (typing keys would have no effect), and stops current ones.
enable
Enable animations (typing keys can start animations).

I'm trying to stop snow script and clear the page after x seconds

How can I make the snow clear after a certain time. I've tried using variables and the calling a timeout which switches on to false and stops the makesnow() function but that doesn't seem to clear the page at all.
<script language="javascript">
ns6 = document.getElementById;
ns = document.layers;
ie = document.all;
/*******************[AccessCSS]***********************************/
function accessCSS(layerID) { //
if(ns6){ return document.getElementById(layerID).style;} //
else if(ie){ return document.all[layerID].style; } //
else if(ns){ return document.layers[layerID]; } //
}/***********************************************************/
/**************************[move Layer]*************************************/
function move(layer,x,y) { accessCSS(layer).left=x; accessCSS(layer).top = y; }
function browserBredde() {
if (window.innerWidth) return window.innerWidth;
else if (document.body.clientWidth) return document.body.clientWidth;
else return 1024;
}
function browserHoyde() {
if (window.innerHeight) return window.innerHeight;
else if (document.body.clientHeight) return document.body.clientHeight;
else return 800;
}
function makeDiv(objName,parentDiv,w,h,content,x,y,overfl,positionType)
{
// positionType could be 'absolute' or 'relative'
if (parentDiv==null) parentDiv='body';
var oDiv = document.createElement ("DIV");
oDiv.id = objName;
if (w) oDiv.style.width = w;
if (h) oDiv.style.height= h;
if (content) oDiv.innerHTML=content;
if (positionType==null) positionType="absolute";
oDiv.style.position = positionType;
if (x) oDiv.style.left=x; else oDiv.style.left=-2000;
if (y) oDiv.style.top=y; else oDiv.style.top=-2000;
if (overfl) oDiv.style.overflow=overfl; else oDiv.style.overflow="hidden";
eval(' document.'+parentDiv+'.appendChild (oDiv); ');
delete oDiv;
}
var snowC=0;
var x = new Array();
var y = new Array();
var speed = new Array();
var t=0;
var cC = new Array();
var ra = new Array();
function makeSnow() {
x[snowC] = Math.round(Math.random()*(browserBredde()-60));
y[snowC] = 10;
makeDiv("snow"+snowC,"body",32,32,'<img src="http://i693.photobucket.com/albums/vv296/KIBBLESGRAMMY/CAT/Orange-tabby-cat-icon.gif">');
speed[snowC] = Math.round(Math.random()*8)+1;
cC[snowC]=Math.random()*10;
ra[snowC] = Math.random()*7;
snowC++;
}
function moveSnow() {
var r = Math.round(Math.random()*100);
if (r>70 && snowC<20) makeSnow();
for (t=0;t<snowC;t++) {
y[t]+=speed[t];move("snow"+t,x[t],y[t]);
if (y[t]>browserHoyde()-50) {y[t] = 10;x[t] = Math.round(Math.random()*(browserBredde()-60));}
cC[t]+=0.01;
x[t]+=Math.cos(cC[t]*ra[t]);
}
setTimeout('moveSnow()',20);
}
moveSnow();
</script>
makeSnow just adds the snowflakes. Stopping that, as you say, does not clear anything. moveSnow handles the animation, and calls itself at a timeout. If instead of setting a timeout for the next moveSnow each time, you set it up to run in an interval just once, you would have an easier time stopping it.
window.snowAnimation = window.setInterval(moveSnow, 20);
If you add a css class to your snow flakes, it would be easier to target them for deletion.
oDiv.className = 'snowflake';
Then your clear function could look something like:
function clearSnow() {
window.clearTimeout(window.snowAnimation);
var flakes = document.getElementsByTagName('snowflake');
for(var i = 0, l = flakes.length; i < l; i++) {
document.body.removeChild(flakes[i]);
}
}
Timeout doesnt help, it helps you only to stop creating new snowdivs, however if you see makeDiv is the one which creates new divs on to the body, if you clear / display:none the divs which got created on makeDiv i hope it will clear all the divs on the screen.
You need to remove the divs that were created. It might be easier if you give them all some sort of class, like ".snowflake" as you create them (in makeDiv), then start removing them from the dom.
You will have to clear the elements created after the time you wanna stop snow falling.
Following code snippet will help you to clear the elements
if(count < 500){
setTimeout('moveSnow()',20);
}else{
var i = 0;
var elem = document.getElementById('snow'+i);
do{
elem.parentNode.removeChild(elem);
elem = document.getElementById('snow'+ ++i);
}while(elem != null)
}
count++;
you have to create a global variable count.

Internet Explorer loop bug when preloading images

I have created a JavaScript application that requires all images to be preloaded first. Everything works fine in Firefox but in Internet Explorer my loop skips the count at 19 and goes to 21. Has anyone come across this problem before and what causes it?
You can copy and paste the script below for test purposes.
var preLoad = function () {
var docImages = ["http://www.sanatural.co.za/media/images/map/rsa_prov.gif", "http://www.sanatural.co.za/media/images/map/loading.gif", "http://www.sanatural.co.za/media/images/map/loading2.gif", "http://www.sanatural.co.za/media/images/map/ec_land.gif", "http://www.sanatural.co.za/media/images/map/ec_roll.gif", "http://www.sanatural.co.za/media/images/map/ec_state.gif", "http://www.sanatural.co.za/media/images/map/fs_land.gif", "http://www.sanatural.co.za/media/images/map/fs_roll.gif", "http://www.sanatural.co.za/media/images/map/fs_state.gif", "http://www.sanatural.co.za/media/images/map/gt_land.gif", "http://www.sanatural.co.za/media/images/map/gt_roll.gif", "http://www.sanatural.co.za/media/images/map/gt_state.gif", "http://www.sanatural.co.za/media/images/map/kzn_land.gif", "http://www.sanatural.co.za/media/images/map/kzn_roll.gif", "http://www.sanatural.co.za/media/images/map/kzn_state.gif", "http://www.sanatural.co.za/media/images/map/lp_land.gif", "http://www.sanatural.co.za/media/images/map/lp_roll.gif", "http://www.sanatural.co.za/media/images/map/lp_state.gif", "http://www.sanatural.co.za/media/images/map/mp_land.gif", "http://www.sanatural.co.za/media/images/map/mp_roll.gif", "mp_state.gif", "http://www.sanatural.co.za/media/images/map/nc_land.gif", "http://www.sanatural.co.za/media/images/map/nc_roll.gif", "http://www.sanatural.co.za/media/images/map/nc_state.gif", "http://www.sanatural.co.za/media/images/map/nw_land.gif", "http://www.sanatural.co.za/media/images/map/nw_roll.gif", "http://www.sanatural.co.za/media/images/map/nw_state.gif", "http://www.sanatural.co.za/media/images/map/wc_land.gif", "http://www.sanatural.co.za/media/images/map/wc_roll.gif", "http://www.sanatural.co.za/media/images/map/wc_state.gif"],
imageFolder = [],
loaded = [],
loadedCounter = 0;
this.loadImgs = function () {
for (var i = 0; i < docImages.length; i++) {
imageFolder[i] = new Image();
imageFolder[i].src = docImages[i];
loaded[i] = false;
}
intervalId = setInterval(loadedCheck, 10); //
};
function loadedCheck() {
if (loadedCounter == imageFolder.length) { // all images have been preloaded
clearInterval(intervalId);
alert('All images have been preloaded!');
return;
}
for (var i = 0; i < imageFolder.length; i++) {
if (loaded[i] === false && imageFolder[i].complete) {
loaded[i] = true;
loadedCounter++;
alert(i); // (work fine in FF but i.e goes from 19 to 21 )
}
}
}
};
var preloadObject = new preLoad();
preloadObject.loadImgs();
The reason for this is that the item on index 20 is "mp_state.gif" - its missing the complete url.
Because of this the image isn't loaded, the .complete property is set to false, and so the loop skips this item.

Categories

Resources