How to implement click event and drag event in HTML Canvas - html

I have created a business tool using html canvas.
It contains numerous elements that can be dragged and dropped. I have coded this functionality myself basically saying (pseudocode):
if(mouseIsDown && mouseInBoundsOfIcon){
icon.grabbed = true;
}
if(icon.grabbed){
icon.x = mouseX;
icon.y = mouseY;
}
Now I would like some of these icons to implement an onClick event as well, making them both clickable and 'drag & droppable'.
The problem is the mousedown event gets fired as soon as I click down on a mouse button (obviously). I'm thinking I could use a short timer, when mousedown fires and mouseInBoundsOfIcon==true, I can start it, when it hits 0.5 seconds for example icon.grabbed = true, else if the button is released it counts as a click?
I'm not sure how to go about this. Any suggestions?

There are at least 2 common ways of differentiating between clicks and drag-starts.
Both these methods involve taking a measurement during mousedown and comparing it to another measurement taken in either mouseup or mousemove.
Measure the distance the mouse moves. For example, if it moves more than 5 pixels before mouseup it's a drag.
Measure the time between mousedown and mouseup. For example, if mouseup occurs within 200ms of mousedown, then it's a click.
Helpful Hint: Let mousedown default to drag-start rather than click. Start dragging on mousedown. If you later determine the user intended a click then put the icon back at its starting position so they don't have slightly nudged icons when intending clicks.

Related

How to remove and then activate an addListener?

I need to remove a certain event and then activate it.
What happens is as follows:
I have a polygon and with the "mouseover" event opens the InfoWindow, and with the "mouseout" event the InfoWindow closes.
So far so good, the problem is when I'm doing the "drag" event in polygon, "InfoWindow stays in the same place and does not follow the polygon.
So I need to close InfoWindow so the polygon is in the "drag" event, and activate only another time.
How do I do this?
The event namespace has everything you need, such as clearListeners and removeListener methods.
The Polygon class has a dragStart, a drag and a dragEnd event.
Therefore you should be able to:
Add your listeners
Listen for a drag or the start of a drag
Close the infowindow / remove your listeners
Listen for the end of a drag
Add your listeners back
I hope this makes sense.
As a side/personal note and speaking in terms of user experience, I am quite convinced that opening/closing stuff based on mouse movements is not a great idea... but that's just me maybe.

Move mouse out of bounds Actionscript 3

My problem is really simple
I´ve an artifact with a mouse inside. When you use it it simulates moving the mouse cursor indefinitely to the right.
Of course when i run my project at some point the mouse will reach the right side of the movieclip and the Mouse_Move event wont work anymore
I need a way make my actionscript to recongnise mouse movement even if im out of bounds
(It´s a mobile aplication so using full screen wont work)
In other words i need a Mouse-Motion Listener!
Though it is not possible to track mouse movements outside of flash with only ActionScript, you could capture the mouse position with javascript in the browser and pass it to your SWF.
See this blog as an example. http://www.nelsond8.com/?p=515
You cannot track the mouse position or actions when it moves outside of the stage.
You can however track when the mouse actually leaves the stage using Event.MOUSE_LEAVE:
function mouseLeave(e:Event):void
{
trace("Mouse left the stage.");
}
stage.addEventListener(Event.MOUSE_LEAVE, mouseLeave);
From here you can decide what the most appropriate course of action will be for your application - adding some 'pause' functionality is pretty common.
Tip: MouseEvent.MOUSE_MOVE is what you should use to detect when the mouse re-enters the stage.

How to handle mouseEvent transparently in AS3?

I have a DisplayObject docked at the top of my interface that displays debug information (frames per second, etc.) and is translucent with an alpha of 60%.
I would like to interact with items under this surface, such that when the mouse rolls over it, it dims to 10% alpha, and mouse events pass through it to the underlying objects.
Normally, I have this debug info panel's mouseEnabled and mouseChildren properties set to false, so objects under it receive mouse events.
The problem is that in order to hide it when the mouse rolls over it, it needs to have mouseEnabled set to true. However, if mouseEnabled is true, the mouse events are not picked up by objects underneath it.
As far as I know, I can't selectively enable mouseEvents, so it's either going to receive them all or none of them. That means that I'd have to handle and forward ALL events, if I took that approach.
I really wish the mouseEnabled property had a "peek" mode or something, so that it could receive the events if it is on top, but also allow them to pass through to objects underneath.
If a DisplayObject has mouseEnabled=true it means that its events will be sent to its container not to whateve is underneath the object. So this solution will not work. The best solution would be to reroute events from it manually using getObjectsUnderPoint as described here.
I've been using this approach for years in multi-touch apps. With multiple touch points I don't see any processor overhead. And you got only one cursor.
I feel your pain. Unfortunately, I don't know of a way to enable/disable specific mouse events. You could get creative with the solution though. For instance, maybe try adding a MOUSE_MOVE listener to your stage and track the coordinates of the mouse. Then, if the stageX,stageY of the mouse is in the area of your panel, set the visibility. You might also be able to use getObjectsUnderPoint() to determine which objects are under the mouse. But, my guess is that it would get a little intense on the processor to run that on each frame iteration.
I believe you are looking for mouseEnabled = false
But another last ditch attempt you can do is on mouse over move it to the other side of the screen.
One approach you can take, although not ideal, is to add an enter frame listener and check the mouse position every frame. something along the lines of:
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
private function onEnterFrame(e:Event):void {
if(mouseX > width || mouseY > height){
//hide stats
}
}
I'm assuming you have this display hierarchy:
Debug Window
Debug Control 1
Debug Control 2
...
Overlay
Why not make the overlay a mask on DebugWindow and have your mouseEvents attached to DebugWindow itself? See this page for some inspiration: http://blog.shaperstudio.com/2010/11/as3-inverse-mask/
I had this same problem.. i made function to check is mouse over certain object:
public function isMouseOverObject(mPos: Point, pObject:DisplayObject, pContainer:DisplayObjectContainer) {
var under_objects:Array = pContainer.getObjectsUnderPoint(mPos);
var is_under:Boolean = false;
for (var i:int = 0; i < under_objects.length; i++) {
if (under_objects[i] == pObject) {
is_under = true;
break;
}
}
return is_under;
}

html 5 addEventListener issue with refreshing Canvas element

I am having an issue getting addEventListener to trigger properly with my canvas element.
Issue:
When I add addEventLister onto my canvas element it automatically forces to animation refresh rate to run at the same time the event listener is being triggered.
Basically I have "setInterval(draw, 500);" which updates the canvas every 500 milliseconds. Without the event listener it will constantly refresh at it's intended rate; however, when I add an action listener it force-refreshes canvas and causes all animations to speed up.
In the source code you will find two functions drawCircle and drawCircleTest which is specifically designed for testing the refresh issue.
hmm, for some reason the source code doesn't want to paste properly
Source Code: http://home.insightbb.com/~epyonxl1/html5_test.htm
Thanks in advance for taking a look!!!
Because you're calling draw on the mouseover event as soon as you move the mouse onto the canvas the next time the setInterval draw() is called the mouseover draw() calls have increased the value of testNum1 by more the number of mouseover events called. I've appended testNum1 to the end of the "Console" output here http://jsfiddle.net/uM5VC/ so you can see the affect (oddly this doesn't work properly in chrome. The link below does).
The solution is to use a different function for the mouseover event that sets the clientHeight and clientWidth to variables declared outside the scope of draw. See http://jsfiddle.net/aMdRm/3/
I've added these variables before any of the functions
var clientX, clientY;
and this function to set them
function changeCoords(e){
clientX = e.clientX;
clientY = e.clientY;
}
the mouseover event now use changeCoords and the draw event references clientX and clientY as opposed to e.clientX and e.clientY.

'glasspane' for as3 to intercept events to everything on stage?

Is there something like the java 'glasspane' in as3?
The glass pane is useful when you want to be able to catch events or paint over an area that already contains one or more components. For example, you can deactivate mouse events for a multi-component region by having the glass pane intercept the events. Or you can display an image over multiple components using the glass pane. http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html
Why do this? While some animations are underway in flash, I want to prevent any mouseevents from firing. I could remove all listeners systematically, then re-add them after the animation, but if there is something like a glasspane, it might be an easier way to achieve the same effect.
My current thinking is to:
add a sprite to the stage
stretch to width and height of the stage,
give the sprite the highest z-order,
grab all events on this sprite, and stop their propagation?
if you set
enabled=false;
mouseChildren=false;
on to the top most DisplayObject it should disable all mouse events for your app. I've used it and it works a treat.
For a more specific approach, e.g. only block clicks but let mouse down etc. through I use this approach. It uses a 'clickBlocker' stage event handler during capture phase, stopping propagation to any other object.
public function blockClicks():void{
if(!stage) return;
stage.addEventListener(MouseEvent.CLICK, clickBlocker, true); //useCapture!
}
private function clickBlocker(event:MouseEvent):void{
trace("Me (the stage) gets the "+event.type+" first, and I block it #"+event.stageX+"/"+event.stageY);
event.stopImmediatePropagation();
}