I am finding it very difficult to create programmatic events using Hammer.js. What I would like is to have two elements, when element one is tapped, I would like to fire or trigger or emit an event on the second element as well.
My end goal is to use this technique when dragging items. Basically, hold down on an element to create a clone of it, and then emit the drag event on the clone. This would stop dragging the original element and start the drag on the new cloned element.
With that said, I've created a simple jsFiddle http://jsfiddle.net/vk3reu0w/1/. It has two div elements. What I am trying to do is have div one be tapped and an event automatically fire a tap event on div two.
var buttonOne = document.getElementById("one");
var buttonTwo = document.getElementById("two");
var mc1 = Hammer(buttonOne);
var mc2 = Hammer(buttonTwo);
mc1.on("tap", function(event) {
alert("MC1 Tapped");
console.log("MC1 Tapped");
mc2.emit("tap");
});
mc2.on("tap", function(event) {
alert("MC2 Tapped");
console.log("MC2 Tapped");
});
Any help is much appreciated. Thanks.
You should add to .emit method a second param.
mc1.on("tap", function(event) {
alert("MC1 Tapped");
console.log("MC1 Tapped");
mc2.emit("tap", event); // HERE
});
http://jsfiddle.net/Lnvgcupg/1/
You can custom your event as well.
mc1.on("tap", function(event) {
console.log("MC1 Tapped");
var customEvent = JSON.parse(JSON.stringify(event)); // Creating
customEvent.center.x = 999; // ...changing something
mc2.emit("tap", customEvent); // Emitting
});
http://jsfiddle.net/ntgrdq7n/3/
Related
I'm creating a JavaScript and JQuery "Whack-a-Mole" game, and I'm appending "mole" images at random coordinates into the gamespace every two seconds. When a mole is clicked, I would like it to hide (disappear from the screen). However, the way I have the code written now, clicking on one mole causes all mole images to be hidden. Would love to hear any thoughts on selecting and hiding only the clicked mole image, but not hiding the other mole images.
Here's my "addMole" function:
function addMole() {
xPos = randPosX();
yPos = randPosY();
$('#gamespace').append('<img src="img/mole.png" style="top:'+yPos+'px;left:'+xPos+'px" />').addClass('mole'); // insert mole into #gamespace
repeatAddMole = setTimeout("addMole()", 2000); // append moles every 2 seconds
};
And here's the game's main function:
$(document).ready(function() {
$('#start_button').click(function() {
start();
$('#timer').show(); // show timer
$('.mole').on("click", function(){
incScore();
$('img', this).hide();
});
});
Thanks!
You are adding the mole class to the #gamespace, not the image. Maybe you want this:
$('#gamespace').append($('<img src="img/mole.png" style="top:'+yPos+'px;left:'+xPos+'px" />').addClass('mole'));
Here's a demo to help you https://jsfiddle.net/bradlis7/ubar2Lzb/1/. I like to keep the functions doing what they say they are doing (addMole should not really be setting a new timer).
You can do it like this:
$('#gamespace').append('<img onclick="this.style.display=\'none\'" src="img/mole.png" style="top:'+yPos+'px;left:'+xPos+'px" />').addClass('mole'); // insert mole into #gamespace
Also the problem is cause you attach event only to created images (moles) before you clicked on start.
You can use event delegation. Use this code out of start button click handler.
$( "#gamespace" ).on( "click", "img", function( event ) {
incScore();
$(this).hide();
});
I would do it pretty much in this way:
function addMole() {
xPos = randPosX();
yPos = randPosY();
var el = $('#gamespace').append('<img src="img/mole.png" style="top:'+yPos+'px;left:'+xPos+'px" />').addClass('mole');
el.on("click", function(){
$(this).remove();
incScore();
});
repeatAddMole = setTimeout("addMole()", 2000);
};
append function returns you jQuery object of appended element, so you can attach event directly on it after it is created. If you create events before objects are created, events will not be attached to it. This way, you create element and then attach the event.
You could do it in the way mhodges wrote in his comment, but I simply don't like this way because I believe it's not that efficient.
I have a function that is called every time a user goes through a new step to bind the click event to each new item that is added to the page, and it was working fine but now it's stopped and I cannot figure out why
Below is the function (or click here for full js):
function bindClickEvents() {
console.log('bindClickEvents');
$(".wall-dropdown .item").unbind('click').on('click', function() {
console.log('Item clicked');
if ($(this).hasClass('range')) {
$(".item.range").removeClass('active');
selectedRange = $(this).data('id');
$(this).addClass('active');
selectedStyle = null;
selectedColour = null;
}
if ($(this).hasClass('style')) {
$(".item.style").removeClass('active');
selectedStyle = $(this).data('id');
$(this).addClass('active');
selectedColour = null;
}
if ($(this).hasClass('colour')) {
$(".item.colour").removeClass('active');
selectedColour = $(this).data('id');
$(this).addClass('active');
}
runFilter();
});
}
Use off with on (not unbind)
$(".wall-dropdown .item").off('click').on('click', function() {
However I suggest you simply switch to delegated event handlers (attached to a non changing ancestor element):
e.g
$(document).on("click", ".wall-dropdown .item", function()
It works by listening for the specified event to bubble-up to the connected element, then it applies the jQuery selector. Then it applies the function to the matching items that caused the event.
This way the match of .wall-dropdown .item is only done at event time so the items can exists later than event registration time.
document is the best default of no other element is closer/convenient. Do not use body for delegated events as it has a bug (to do with styling) that can stop mouse events firing. Basically, if styling causes a computed body height of 0, it stops receiving bubbled mouse events. Also as document always exists, you do not need to wrap document-based delegated handlers inside a DOM ready :)
Why don't you bind event to body like
$('body').on('click','.wall-dropdown .item',function(){...some code...})
to prevent reinitialization of event?
this code automaticaly works with each new element .wall-dropdown .item
I'm working on a card game. I have a CardSet (custom Container object) that contains Cards (custom Container objects). I'd like to create custom events like: cardMouseOver and cardMouseOut so that I can listen to these card events like this:
cardSet.on('cardMouseOver', function(event) { set the event.card highlighted or anything );
cardSet.on('cardMouseOut', function(event) { set the event.card back to normal );
In the init block of the CardSet I added listeners to each cards:
card[i].on('mouseover', function (event) {
var evt = new createjs.Event('cardMouseOver');
evt.card = event.target;
this.dispatchEvent(evt);
});
The issue is when I move the mouse over the card it fires the over and out events right after each other. If I move the mouse it keeps firing these event like a mousemove. Any idea? Please ask if I wasn't clear enough. Thanks!
I have a mousedown event listener on stage and a mousedown event listener on a shape.when I click on the shape, the mousedown event listener on stage will also fire? How to solve this?
var stage = new createjs.Stage("test");
stage.addEventListener('stagemousedown',mouseDown);
var shape = new createjs.Shape();
shape.graphics.beginStroke("#000").setStrokeStyle(8,"round").drawRect(0, 0, 100, 100);
shape.addEventListener('mousedown',smouseDown);
stage.addChild(shape);
The stagemousedown event is a special event to always capture stage mouse interaction, regardless of what is clicked. If you would like to ONLY receive that event when a child on the stage is not clicked there are other approaches.
One suggestion would be to add a stage-level child that is the size of the stage, and listen for mouse events on it. You can then check the target to see what was clicked (or not clicked)
var stage = new createjs.Stage("canvas");
var bg = new createjs.Shape();
bg.graphics.f("#ddd").dr(0,0,550,400);
var shape = new createjs.Shape().set({x:200,y:200});
shape.graphics.f("#f00").dc(0,0,100);
stage.addChild(bg, shape);
stage.update();
stage.addEventListener("mousedown", function(event){
if (event.target == bg) {
console.log("Missed Content");
} else {
console.log("Hit Content");
}
});
this is one of the ways to remove the shape object in the stage.
stage.removeChild(shape);
you can put that in a function and just call it when you want to remove the object.
please let me know if that is what you need.
There is maybe a better way, but you could check if there is no object under the mouse when you catch the "stagemousedown" event :
function mouseDown(event) {
if (stage.getObjectUnderPoint(event.stageX,event.stageY) == null) {
// ...
}
}
I think what you're looking for is stage.mouseEnabled = false:
Indicates whether to include this object when running mouse
interactions. Setting this to false for children of a Container will
cause events on the Container to not fire when that child is clicked.
Setting this property to false does not prevent the
getObjectsUnderPoint method from returning the child.
However, from the docs:
Note: In EaselJS 0.7.0, the mouseEnabled property will not work
properly with nested Containers. Please check out the latest NEXT
version in GitHub for an updated version with this issue resolved. The
fix will be provided in the next release of EaselJS.
I have a div
<div class="myDiv">
somelink
<div class="anotherDiv">somediv</div>
</div>
Now, using event delegation and the concept of bubbling I would like to intercept clicks from any of myDiv, myLink and anotherDiv.
According to best practices this could be done by listening for clicks globally (hence the term 'delegation') on the document itself
$(document).click(function(e) {
var $eventElem = $(e.target);
var bStopDefaultClickAction = false;
if ($eventElem.is('.myDiv'))
{
alert('Never alerts when clicking on myLink or anotherDiv, why????');
bStopDefaultClickAction = true;
}
return bStopDefaultClickAction;
});
See my alert question above. I was under the impression that clicks bubble. And it somewhat does because the document actually receives my click and starts delegating. But the bubbling mechanism for clicks on myLink and anotherDiv doesn't seem to work as the if-statement doesn't kick in.
Or is it like this: clicks only bubble one step, from the clicked src element to the assigned delegation object (in this case the document)? If that's the case, then I need to handle the delegation like this:
$('.myDiv').click(function(e) {
//...as before
});
But this kind of defeates the purpose of delegation as I now must have lots of 'myDiv' handlers and possibly others... it's dead easy to just have one 'document' event delegation object.
Anyone knows how this works?
You should use live event from JQuery (since 1.3), it use event delegation :
http://docs.jquery.com/Events/live
So you code will be :
$(".myDiv").live("click", function(){
alert('Alert when clicking on myLink elements. Event delegation powaa !');
});
With that, you have all the benefices of event delegation (faster, one event listener etc..), without the pain ;-)
The event target will not change. You need to mirror what jquery live does and actually check if $eventElem.closest('. myDiv') provides a match.
Try:
$(document).click(function(e) {
var $eventElem = $(e.target);
var bStopDefaultClickAction = false;
if ( $eventElem.closest('.myDiv').length )
{
alert('Never alerts when clicking on myLink or anotherDiv, why????');
bStopDefaultClickAction = true;
}
return bStopDefaultClickAction;
});
Event.target is always the element that triggered the event, so when you click on 'myLink' or 'anotherDiv' you store a reference to these objects using $(e.target); So what you do in effect is: $('.myLink').is('.myDiv') which returns false, and that's why the alert() is not executed.
If you want to use event delegation this way, you should check wheter event.target is the element or any of its children, using jQuery it could be done like this:
$(e.target).is('.myDiv, .myDiv *')
Seems to work fine to me. Try it here: http://jsbin.com/uwari
Check this out: One click handler in one page
var page = document.getElementById("contentWrapper");
page.addEventListener("click", function (e) {
var target, clickTarget, propagationFlag;
target = e.target || e.srcElement;
while (target !== page) {
clickTarget = target.getAttribute("data-clickTarget");
if (clickTarget) {
clickHandler[clickTarget](e);
propagationFlag = target.getAttribute("data-propagationFlag");
}
if (propagationFlag === "true") {
break;
}
target = target.parentNode;
}
});