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!
Related
I have a canvas and I want users to be able to drag graphic elements around it. Thus, I don't want the canvas itself to drag, but I want to handle dragstart, drag, and drop events when the mouse does those things.
I'm using Angular 2, so I have:
<!-- editor.component.html -->
<div #rendererContainer
draggable="true"
(dragstart)="onDragStart($event)"
(drag)="onDrag($event)"
(dragover)="onDrag($event)"
(drop)="onDragEnd($event)"
(dragend)="onDragEnd($event)">
</div>
Then in editor.component.ts:
onDragStart(event) {
console.log(`starting`);
event.preventDefault();
}
onDrag(event) {
console.log('dragging');
event.preventDefault();
}
onDragEnd(event) {
console.log('drag end');
event.preventDefault();
}
When I try dragging something, I get starting printed in the console, but that's it. How do I get the other drag events to fire? Do I have to roll my own dragging from mousedown/move/up events?
Stand-alone example on stackblitz. I want "dragging" the div around to fire dragstart/drag/drop events, but it only fires the starting one.
You do not have to use event.preventDefault(). This is only necessary if you want to use pure JS.
Try this Stackblitz: https://stackblitz.com/edit/angular-x7umar
Also refer to the MDN implementation guide to choose the right events for your purposes: https://developer.mozilla.org/en-US/docs/Web/Events/drag
Further steps
If you want to modify the dragged element, simply implement some CSS adjustments inside your dragstart and dragend handler of the event.target:
onDragStart(event: DragEvent) {
console.log(`starting`, event);
// Hide dragged element
event.target.style.opacity = 0;
}
onDragEnd(event: DragEvent) {
console.log('drag end', event);
// Show dragged element again
event.target.style.opacity = 1;
}
With event.target you have the complete manipulable DOM element of the dragged element.
try with
(dragover)="onDragOver($event)"
(dragleave)="onDragLeave($event)"
Component
onDragOver(event) {
// do something
event.preventDefault();
}
onDragLeave(event) {
// do something
event.preventDefault();
}
I want to disable the click on an entity after it's been clicked once by the raycaster. The entity opens up a panel so I don't want it to show more than once
This really depends whether or not you're using raycaster="objects: ...;". This is usually the recommended approach so your raycaster isn't interacting with every entity in the scene causing a drop in performance.
This can be done many ways, but one of the most common is to use a class selector like .clickable and then remove that class upon click. Then remove the event listener if it is no longer needed.
Cursor Raycaster:
<a-cursor raycaster="objects: .clickable;"></a-cursor>
Component:
AFRAME.registerComponent('click-once', {
init: function () {
var self = this;
var scene = self.el.sceneEl;
var raycaster = scene.querySelector('[cursor]').components.raycaster;
// Define function to be executed on click.
var clickHandler = function (e) {
// Log clicks.
console.log('clicked');
// Remove "clickable" class from entity.
self.el.classList.remove('clickable');
// Refresh raycaster object list to reflect changes.
raycaster.refreshObjects();
// Remove event listener since no longer needed.
self.el.removeEventListener('click', clickHandler);
};
// Add event listener for click.
self.el.addEventListener('click', clickHandler);
}
});
EDIT: This can be simplified even further if data-xxxx attributes or components are used as selectors, rather than classes/ids. E.g.: data-clickable
By default, A-Frame's raycaster automatically refreshes when entities and attributes/components (not classes) are added/removed, so there is no need to use raycaster.refreshObjects() in this case. https://aframe.io/docs/master/components/raycaster.html#properties_autorefresh
HTML:
<a-entity cursor raycaster="objects: [data-clickable];"></a-entity>
JS:
self.el.removeAttribute('data-clickable');
Demo of the code in action: https://codepen.io/dansinni/pen/MGKGZq
EDIT: If you are using <a-cursor> rather than <a-entity cursor="...", then you may need to use the following var raycaster assignment:
var raycaster = scene.querySelector('a-cursor').components.raycaster;
Or, if you are attaching the raycaster component explicitly:
var raycaster = scene.querySelector('[raycaster]').components.raycaster;
Hope this helps.
In my simple application i need to hide original cursor stage.cursor = 'none'; stage.enableMouseOver(), than i replace it with my own image
Than i register listener on stagemousemove event:
myBitmap.x = stage.mouseX;
myBitmap.y = stage.mouseY;
After this action i loose access to listen mouse events on other stage objects:
//nothing happen on mouse over
someBitmap.on('mouseover', function() { console.log(1) });
Is there any possible solutions, expect check every time hitTests on my objects inside stage mouse events?
Fixed by setting up cursor: none in my css rules and removing stage.cursor = 'none'from js. Thanks #Andew for example.
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/
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.