removeEventListener undefined reference - javascript

I'm creating a large grid of divs which I plan to perform animations and effects on. I have around 90 divs creating a tiled background. Now here's the trick with this..I am creating the page to be responsive. I cannot float these divs and so they are inline-blocked with overflow hidden. So as the width of the viewport changes the amount of divs in the rows changes - essentially moving the div over and down. So I've had to dynamically populate the div text based on position(x,y). Unfortunately I am having an issue with the event listener box moving because of this.
When I try to remove the event listener I get an undefined error - even when I move it into the initial listener scope.
function menuBox(){
var allDiv = document.getElementsByTagName('div');
var menuDiv1 = document.elementFromPoint(39, 16);
var menuDiv2 = document.elementFromPoint(39, 120); //Blank Div
var menuDiv3 = document.elementFromPoint(39, 225);
var menuDiv4 = document.elementFromPoint(39, 329);
var menuDiv5 = document.elementFromPoint(39, 433);
var menuDiv6 = document.elementFromPoint(39, 538);
var menuDiv7 = document.elementFromPoint(39, 642);
var menuDiv = [
menuDiv1,
menuDiv3,
menuDiv4,
menuDiv5,
menuDiv6,
menuDiv7
]
for (var i = 0; i < allDiv.length; i++) {
allDiv[i].innerHTML = '';
// allDiv[i].removeEventListener("mouseover", menuOver, false);
// allDiv[i].removeEventListener("mouseout", menuOut, false);
};
for (var i = 0; i < menuDiv.length; i++) {
menuDiv[i].addEventListener("mouseover", function menuOver(){
TweenLite.to(this, 0.4, {backgroundColor: '#272822', color: '#fff', scale: 1.1})
}, false);
menuDiv[i].addEventListener("mouseout", function menuOut(){
TweenLite.to(this, 0.3, {backgroundColor: '#fff', color: '#000', scale: 1})
}, false);
};
menuDiv1.innerHTML = '<p>Switch<br>Menu</p>';
menuDiv3.innerHTML = '<p>Michael</p>';
menuDiv4.innerHTML = '<p>Design</p>';
menuDiv5.innerHTML = '<p>Develop</p>';
menuDiv6.innerHTML = '<p>Imaging</p>';
menuDiv7.innerHTML = '<p>Motion</p>';
console.log('menuBox function');
};
menuBox();
window.onresize = menuBox;

You should know that, to remove event handlers from DOM element, the function specified with the addEventListener() method must be an external function .
Anonymous functions, like domelement.removeEventListener("event", function(){ \\something }); will not work.
Having said that, same mistake has been done in your code, thus leading to reference type of error Uncaught ReferenceError: menuOver is not defined.
To make you code work, below are changes you should use:
for (var i = 0; i < allDiv.length; i++) {
allDiv[i].innerHTML = '';
allDiv[i].removeEventListener("mouseover", menuOver, false);
allDiv[i].removeEventListener("mouseout", menuOut, false);
};
for (var i = 0; i < menuDiv.length; i++) {
menuDiv[i].addEventListener("mouseover",menuOver, false);
menuDiv[i].addEventListener("mouseout",menuOut, false);
};
function menuOver(){
TweenLite.to(this, 0.4, {backgroundColor: '#272822', color: '#fff', scale: 1.1});
}
function menuOut(){
TweenLite.to(this, 0.3, {backgroundColor: '#fff', color: '#000', scale: 1});
}

Related

Click nested elements in JavaScript

Using only JavaScript, I want to create five nested divs. When clicking one of them, I want that only that div's background to change its color (according to an array of colors).
My problem here is that, because the divs are nested, clicking on any one of them will just color the largest one (the parent). The rest of the code is okay because if I struggle to click on a border, I can actually achieve what I want. But the idea is to work when clicking inside of the smaller div.
var currentParent = document.body;
var colors = ['red', 'black', 'green', 'pink', 'purple']
var divArray = []
for (let i = 0; i < 5; i++) {
let currentDiv = document.createElement("div")
currentDiv.style.width = `${(i * 10 + 20)}px`
currentDiv.style.height = `${(i * 10 + 20)}px`
currentDiv.position = i
currentParent.append(currentDiv)
divArray.push(currentDiv)
currentParent = currentDiv
}
for (let i = 0; i < 5; i++) {
divArray[i].onclick = function() {
this.style.backgroundColor = colors [this.position]
}
}
Each loop, a DIV larger than its parent is appended. This means that only the last div can be clicked because it covers the others.
If the sizing logic is reversed so that the DIVs become smaller each loop, the code will work as you expect.
Use event.stopPropagation(); to prevent the event from bubbling to the other elements.
var currentParent = document.body;
var colors = ['red', 'black', 'green', 'pink', 'purple']
var divArray = []
for (let i = 0; i < 5; i++) {
let currentDiv = document.createElement("div")
currentDiv.style.width = `${(60 - i * 10)}px`
currentDiv.style.height = `${(60 - i * 10)}px`
currentDiv.position = i
currentParent.append(currentDiv)
divArray.push(currentDiv)
currentParent = currentDiv
}
for (let i = 0; i < 5; i++) {
divArray[i].onclick = function(e) {
e.stopPropagation();
this.style.backgroundColor = colors [this.position]
}
}
div {
outline: 1px solid orange;
background: #FFF;
}
You need to stop event Propagation on the onclick event, like so
divArray[i].onclick = function(event) {
event.stopPropagation();
this.style.backgroundColor = colors [this.position]
}
There is also preventDefault, to prevent the default behaviors, like a link or form button for example.
var currentParent = document.body;
var colors = ['red', 'black', 'green', 'pink', 'purple']
var divArray = []
for (let i = 0; i < 5; i++) {
let currentDiv = document.createElement("div")
currentDiv.style.width = `${(i * 10 + 20)}px`
currentDiv.style.height = `${(i * 10 + 20)}px`
currentDiv.position = i
currentParent.append(currentDiv)
divArray.push(currentDiv)
currentParent = currentDiv
}
for (let i = 0; i < 5; i++) {
divArray[i].onclick = function() {
this.style.backgroundColor = colors [this.position]
}
}
div{
border: 1px solid #000;
}

Changing position of Phaser.Text when fixedToCamera

How do I go about changing the position of a Phaser.Text element when it has the attribute fixedToCamera set to true. In the below code the value of counterText.x is always reset to 45;
var game = new Phaser.Game(500, 500, 'phaser-example', { create: create, update: update});
var counter = 0;
function create() {
counterText = game.add.text(45, 45, 'Text', {
font: "26px Verdana",
fill: "#fff"
});
counterText.fixedToCamera = true;
}
function update() {
counterText.x = counter++;
}
I reckon the problem here is that when fixedToCamera is true, Text doesn't use 'position' anymore, but uses 'cameraOffset' instead. So if you modify that as you would the position, everything should work fine.

Problems with a class for virtual controls in the Phaser framework

In my game, I need some buttons that will work on mobile devices (buttons that you can press and/or hold in the game). I saw this example (note that the version of Phaser being used here is old, however, it still works) and was able to temporarily have some working buttons. Here's the source code for that example.
However, one thing bothered me about this example's code for the creation of these virtual gamepad buttons: the buttons' code wasn't DRY (Don't Repeat Yourself). You can see how these buttons keep getting created in the same fashion here over and over again:
// create our virtual game controller buttons
buttonjump = game.add.button(660, 340, 'buttonjump', null, this, 0, 1, 0, 1); //game, x, y, key, callback, callbackContext, overFrame, outFrame, downFrame, upFrame
buttonjump.anchor.setTo(0.5, 0.5);
buttonjump.fixedToCamera = true; //our buttons should stay on the same place
buttonjump.events.onInputOver.add(function(){jump=true;});
buttonjump.events.onInputOut.add(function(){jump=false;});
buttonjump.events.onInputDown.add(function(){jump=true;});
buttonjump.events.onInputUp.add(function(){jump=false;});
buttonfire = game.add.button(750, 340, 'buttonfire', null, this, 0, 1, 0, 1);
buttonfire.anchor.setTo(0.5, 0.5);
buttonfire.fixedToCamera = true;
buttonfire.events.onInputOver.add(function(){fire=true;});
buttonfire.events.onInputOut.add(function(){fire=false;});
buttonfire.events.onInputDown.add(function(){fire=true;});
buttonfire.events.onInputUp.add(function(){fire=false;});
buttonleft = game.add.button(40, 312, 'buttonhorizontal', null, this, 0, 1, 0, 1);
buttonleft.anchor.setTo(0.5, 0.5);
buttonleft.fixedToCamera = true;
buttonleft.events.onInputOver.add(function(){left=true;});
buttonleft.events.onInputOut.add(function(){left=false;});
buttonleft.events.onInputDown.add(function(){left=true;});
buttonleft.events.onInputUp.add(function(){left=false;});
buttonbottomleft = game.add.button(48, 352, 'buttondiagonal', null, this, 6, 4, 6, 4);
buttonbottomleft.anchor.setTo(0.5, 0.5);
buttonbottomleft.fixedToCamera = true;
buttonbottomleft.events.onInputOver.add(function(){left=true;duck=true;});
buttonbottomleft.events.onInputOut.add(function(){left=false;duck=false;});
buttonbottomleft.events.onInputDown.add(function(){left=true;duck=true;});
buttonbottomleft.events.onInputUp.add(function(){left=false;duck=false;});
buttonright = game.add.button(136, 312, 'buttonhorizontal', null, this, 0, 1, 0, 1);
buttonright.anchor.setTo(0.5, 0.5);
buttonright.fixedToCamera = true;
buttonright.events.onInputOver.add(function(){right=true;});
buttonright.events.onInputOut.add(function(){right=false;});
buttonright.events.onInputDown.add(function(){right=true;});
buttonright.events.onInputUp.add(function(){right=false;});
buttonbottomright = game.add.button(128, 352, 'buttondiagonal', null, this, 7, 5, 7, 5);
buttonbottomright.anchor.setTo(0.5, 0.5);
buttonbottomright.fixedToCamera = true;
buttonbottomright.events.onInputOver.add(function(){right=true;duck=true;});
buttonbottomright.events.onInputOut.add(function(){right=false;duck=false;});
buttonbottomright.events.onInputDown.add(function(){right=true;duck=true;});
buttonbottomright.events.onInputUp.add(function(){right=false;duck=false;});
buttondown = game.add.button(88, 360, 'buttonvertical', null, this, 0, 1, 0, 1);
buttondown.anchor.setTo(0.5, 0.5);
buttondown.fixedToCamera = true;
buttondown.events.onInputOver.add(function(){duck=true;});
buttondown.events.onInputOut.add(function(){duck=false;});
buttondown.events.onInputDown.add(function(){duck=true;});
buttondown.events.onInputUp.add(function(){duck=false;});
Because they were created in such a non-DRY and, what I feel to be, inefficient way, I decided that my buttons should have a gamepad button class that they all inherit from. Unfortunately, I've been running into lots of problems trying to make this button class work.
I have an example here that models what I'm trying to do in my game.
(Here's the source code for my example)
// Global constants
var GAME_WIDTH = 800;
var GAME_HEIGHT = 600;
var ORIGIN = 0;
var TEXT_X_POS = 50;
var TEXT_Y_POS = 100;
var TEXT_STYLE = { fontSize: "16px" };
var RIGHT_BUTTON_X_POS = 600;
var RIGHT_BUTTON_Y_POS = 400;
var LEFT_BUTTON_X_POS = 100;
var LEFT_BUTTON_Y_POS = 400;
var PHASER_DUDE_Y_POS = 300;
var PHASER_DUDE_GRAVITY = 300;
var PHASER_DUDE_RIGHT_VELOCITY = 100;
var PHASER_DUDE_LEFT_VELOCITY = -100;
var STOPPED = 0;
// Global variables
var background;
var rightButton;
var movingRight;
var rightButtonDown;
var leftButton;
var movingLeft;
var leftButtonDown;
var phaserDude;
var rightKey;
var leftKey;
// New instance of Phaser.Game
var game = new Phaser.Game(GAME_WIDTH, GAME_HEIGHT, Phaser.AUTO, "game", {preload: preload, create: create, update: update});
// Mobile button class
var MobileButton = function (button, movingInADirection, isTheButtonDown, pressedMethod) {
button.events.onInputOver.add(function () {
if (isTheButtonDown === true) {
movingInADirection = true;
}
});
button.events.onInputDown.add(function () {
isTheButtonDown = true;
movingInADirection = true;
});
button.events.onInputUp.add(function () {
movingInADirection = false;
});
};
function preload () {
game.load.image("background", "sprites/sky.png");
game.load.image("left arrow", "sprites/left_arrow.png");
game.load.image("right arrow", "sprites/right_arrow.png");
game.load.image("phaser dude", "sprites/phaser_dude.png");
}
function create () {
background = game.add.image(ORIGIN, ORIGIN, "background");
game.add.text(TEXT_X_POS, TEXT_Y_POS, "Use the arrow keys or the arrow buttons below to move", TEXT_STYLE);
rightButton = game.add.button(RIGHT_BUTTON_X_POS, RIGHT_BUTTON_Y_POS, "right arrow", moveRight);
leftButtonDown = game.add.button(LEFT_BUTTON_X_POS, LEFT_BUTTON_Y_POS, "left arrow", moveLeft);
phaserDude = game.add.sprite(game.world.centerX, PHASER_DUDE_Y_POS, "phaser dude");
game.physics.arcade.enable(phaserDude);
phaserDude.body.collideWorldBounds = true;
phaserDude.body.gravity.y = PHASER_DUDE_GRAVITY;
rightKey = game.input.keyboard.addKey(Phaser.Keyboard.RIGHT);
leftKey = game.input.keyboard.addKey(Phaser.Keyboard.LEFT);
}
function update () {
stopMoving();
if (leftKey.isDown || movingLeft === true) {
moveLeft();
}
if (rightKey.isDown || movingRight === true) {
moveRight();
}
}
function moveRight () {
phaserDude.body.velocity.x = PHASER_DUDE_RIGHT_VELOCITY;
}
function moveLeft () {
phaserDude.body.velocity.x = PHASER_DUDE_LEFT_VELOCITY;
}
function stopMoving () {
phaserDude.body.velocity.x = STOPPED;
}
As you can see, the arrow keys work fine for moving the sprite, but the mobile buttons do not work well; they only move the sprite for a frame, and then it stops moving again. I'm not sure why the keys work, yet the mobile buttons don't. The problem seems to be that the code in the class is not being run the way that I am thinking it should run (i.e., it seems like all of the code concerning the onInputOver, onInputDown, and onInputUp events is not being correctly run and the class is only paying attention to the method to run when a button is pressed). Can anyone figure out what the problem is with my button class?
Your problem is that the onInputDown of Phaser.Button only fires once each time the button is pressed.
What you need to do is set an isDown property on the button something like this:
button.events.onInputDown.add(function () {
button.isDown = true;
});
button.events.onInputUp.add(function () {
button.isDown = false;
});
And the in your update method check for that property:
function update () {
stopMoving();
if (leftKey.isDown || leftButton.isDown) {
moveLeft();
}

Looping through some SVG elements

I have some icons from Raphaël.js, and I would like to fade them in sequentially on page load.
Here I build the icons:
function navBar() {
var icon={/* lots of path strings */},
fill = {
fill:"#666",
stroke:"none",
opacity:0 // opacity is initially 0; would like to loop through this
},
stroke = {
stroke:"#fff",
"stroke-width":3,
"stroke-linejoin":"round",
opacity:0
};
for (var name in icon) {
var r = Raphael(0, 0, 40, 40),
s = r.path(icon[name]).attr(stroke).translate(4, 4),
Icon = r.path(icon[name]).attr(fill).translate(4, 4),
Path = document.getElementById("path"),
none = {fill: "#000", opacity: 0};
(function (icon, path, s, name) {
r.rect(0, 0, 38, 38).attr(none).hover(function () {
s.stop().animate({opacity: 1}, 200);
}, function () {
s.stop().attr({opacity: 0});
});
})(Icon, icon[name], s, name);
// Here I'm able to fade all of the icons in at the same time
(function (icon) {
Icon.animate({opacity:1},200);
})(Icon);
}
}
Rather than fade all of the icons in at the same time as I've done at the end of the script, how can I loop through them and fade them each in, one by one, with a slight delay in between?
Maybe you need to animate them after create opr. is done. Here is a simulation: http://jsfiddle.net/r75hh/
Like this or so.
// creating
var icon = new Raphael ...
...
icon.attr("rel", "icon")
// the last line in navBar()
animateIcons();
// animating
function animateIcons() {
// assuming jQuery in use
var icons = $("elementTagNameOfIcon[rel='icon']");
var i = 0;
var f = function(){
var icon = icons.get(i);
if (icon) {
$(icon).animate({opacity:1}, 200, function(){
f();
});
i++;
}
};
f();
}

using canvas kinetic in html5 to draw many text and edit them

When I click the text on a card, I want to be able to edit the text like this website:
http://www.vistaprint.com/vp/ns/studio3.aspx?pf_id=064&combo_id=120585&free_studio_gallery=true&referer=http%3a%2f%2fwww.vistaprint.com%2fvp%2fns%2fdefault.aspx%3fdr%3d1%26rd%3d1%26GNF%3d0%26GP%3d5%252f19%252f2012%2b12%253a36%253a37%2bAM%26GPS%3d2448654652%26GNF%3d1%26GPLSID%3d&rd=1
Here is my code:
$(document).ready(function () {
var Total_layers = 0;
var Text = {};
/*set up stage for drawing image*/
var stage = new Kinetic.Stage({
container: "container",
width: 600,
height: 400
});
// var Layer = {};
/*create a layer object for placing text image over it and place it over the stage*/
var layer = new Kinetic.Layer();
//Layer[Total_layers]
/*Text Property*/
var New_Text = "Company Name";
var Text_Font = "Arial";
var Text_Color = "Black";
var Text_Size = "30";
var Text_Pos_X = 200;
var Text_Pos_y = 100;
var Selected_Text = new Kinetic.Text({});
var current_layer = 0;
// var text_selected = 1;
/*Add event for them*/
//var formElement = document.getElementById("New Text");
// formElement.addEventListener('change', Text_Changed, false);
var formElement = document.getElementById("selectFontSize");
formElement.addEventListener('change', Text_Size_Changed, false);
/*This Function will be Executed when the Size of the Text in consideration is changed*/
function Text_Size_Changed(e) {
var target = e.target;
Text_Size = target.value;
Text_Pos_X = 200; //Text[Total_layers].x;
Text_Pos_Y = 100; //Text[Total_layers].y;
//DeleteLayer(Total_layers);
layer.remove(Selected_Text);
Draw_text(Total_layers);
}
/*Function to swap the Kinetic Text object and get the selected Text object to The Top*/
function swap_layers(Selected_text) {
var temp = new Kinetic.Text({});
for (var i = 1; i <= Total_layers; i++) {
if (Text[i] == Selected_text) {
temp = Text[i];
Text[i] = Text[Total_layers];
Text[Total_layers] = temp;
break;
}
}
}
/*Add different Events to the Text objects once They are instantiated*/
function add_events(dest_Text) {
dest_Text.on("mouseover", function () {
document.body.style.cursor = "pointer";
});
dest_Text.on("mouseout", function () {
document.body.style.cursor = "default";
});
dest_Text.on("click", function () {
$("#selectFontSize").change(function () {
dest_Text.setFontSize($("#selectFontSize").val());
layer.draw(); // vì gọi layer.draw nên tất cả text trong layer đó đều dc vẽ lại
});
$("#selectFontFamily").change(function () {
swap_layers(dest_Text);
//dest_Text.setFontFamily($("#selectFontFamily").val());
//layer.draw();
});
});
}
/*Draw the Text over the layer depening upon the Text_object_Number*/
function Draw_text(Text_object_Number) {
/*Set the Properties of the Topmost object that is been modified and which will be added to the layer*/
Text[Text_object_Number] = new Kinetic.Text({
x: Text_Pos_X,
y: Text_Pos_Y,
text: New_Text,
fontSize: Text_Size,
fontFamily: Text_Font,
textFill: Text_Color,
align: "center",
verticalAlign: "middle",
draggable: "true"
});
/*Adds all the Text objects onto the layer and adds the events to every Text object */
//for (var i = 1; i <= Text_object_Number; i++) {
layer.add(Text[Text_object_Number]);
add_events(Text[Text_object_Number]);
//}
stage.add(layer);
}
$("#add_text").click(function () {
Total_layers++;
Text[Total_layers] = new Kinetic.Text({
x: Text_Pos_X,
y: Text_Pos_y,
text: New_Text,
fontSize: 30,
fontFamily: Text_Font,
textFill: Text_Color,
align: "center",
verticalAlign: "middle",
draggable: "true"
});
add_events(Text[Total_layers]);
layer.add(Text[Total_layers]);
stage.add(layer);
});
/*Adding an image to the present Context*/
var imageObj = new Image();
//alert("abc");
imageObj.onload = function () {
var T_shirt = new Kinetic.Image({
x: 60,
y: 0,
image: imageObj,
width: 550,
height: 400,
name: "image"
});
layer.add(T_shirt);
stage.add(layer);
}
imageObj.src = "../../Content/Image/imagepreview1.jpg";
});
I have tried many ways, but I still can't resolve this problem.
How can I do this by using canvas kineticjs in html5?
The very best solution imho is to use a simple JavaScript prompt:
myText.on('click', function(evt) {
this.setText(prompt('New Text:'));
layer.draw(); //redraw the layer containing the textfield
});
See my answer in this thread: editable Text option in kinetic js
You can't edit the text directly on the canvas, but what you can do is change it with events. So what you need is an input form that is created next to the canvas, and you can read from the form using javascript.
<input type=text id=changeText/>
this way when you click on some text a new input tag will appear and you can type in it and the text inside of the canvas will change as you type.
mytext.on('click', function(){ ... create new input element at the side ... });
//add some jQuery
$('#changeText').onchange( mytext.setText($('$changeText').val()));

Categories