I need to handle mouse events on a page where there are multiple irregular-shaped objects (for example, houses) are stacked on top of each other. If I use the normal way of event delegation jQuery .on(), the event source reported will always be the top most object, even if user clicked on the transparent part of the object (or image).
Example: <img> tag that contains the red triangle will always be the event source even if I click at the X position.
I can detect that mouse click is not inside the triangle. What I need is a way to "forward" the event to the green triangle below.
EDIT: My current approach is to catch the events on a big div that wraps everything, then use jQuery selector and compare coordinates to find out which object is under the mouse, then check if the mouse is in transparent part or not. It works fine, but seems to be slow and consume a lot of memory, especially with mouse move events being fired continuously.
EDIT 2:
This image was extracted from Building a game engine with jQuery, and my approach was almost identical to that. And now, this is the question:
Are you drawing complex graphics using plain HTML elements? Not sure about your exact needs, but it might make more sense to use SVG or Canvas, where catching click events on shapes becomes much easier.
Related
How can activate the drag -and-drop feature inside the canvas tag ?
As far as I know, there is no built-in drag and drop within a canvas, because a canvas is a literal context that you draw things on. Canvas-based games constantly refresh and redraw all elements.
Basically, a canvas requires a lot of manual, fine-tuned assembly of colors, though it can be performant under circumstances where you want that type of manual, decided control
When a user clicks on an object that seems to be within your canvas, you have to calculate where that mouse event's X and Y coordinates would fall, and determine which actions can be performed onclick on whichever thing is drawn there.
Normal DOM (not so in a canvas or iframe) will emit an event from the element you clicked, and will bubble up through all parent elements saying that some target element was clicked, and this fired event will have lots of data about that click event
A canvas is kinda like having a real painting: rather than an assembly of objects, there is nothing to drag, just a bunch of data about which pixels are which colors.
Normally, HTML elements have an attribute [draggable], but you would still need to manually reposition the element on mouseup or whatever, based off of the screen, or closest non-staticly placed parent. This question might be helpful: HTML5 Canvas Drag and Drop Item
You should search around instead of asking a question like this, in my opinion
I am making a javascript game and I would like to be able to add a main menu but I don't know exactley how. I am lookign up for a way to make filltext() clickable but to no avail. I have looked it up but have found no answer that suites my needs. The games protoype can be viewed here: sketchy.idreesinc.com . Does anyone know anyway to implement this? I am using javacript and HTML5's canvas element but I would prefer javascript. Thanks!
Things to know about HTML and canvas first
DOM
HTML elements are part of the DOM (the Document Object Model) which is the data structure of a webpage. DOM elements can have trigger events (like click) and event listeners react to those events.
browser
Your web browser converts the DOM elements into pixels on your screen. It also handles input and figures out what element's events to trigger if you click on the page.
canvas
The canvas element allows you to render bitmap images. You basically set the colors on a grid of pixels through some javascript calls to make pretty pictures.
what that all means
When you create a link element in HTML (the <a> tag) the browser renders the text and attaches a click listener to the element so the link actually works.
When you use javascript to draw the pixels on the canvas the browser's understanding of the DOM stops at the canvas. The browser knows about the DOM and the DOM knows about the canvas but it doesn't keep track of the individual items drawn in the canvas.
The answer
You can't actually attach an event to the text in the canvas but there are many ways to get the desired behavior of click the text, something happens.
One way would be to attach a click event to the canvas but instead of a simple event listener that always runs this event listener would need to check to see if the click happened on the text or somewhere else on the canvas.
Event listener functions get called with an Event argument which has information about the event.
Things to google
Some quick reading about these should get you started towards a working menu.
registering javascript event listeners
javascript event mouse coordinates
Perhaps the title isn't great, but I had a little trouble with the wording...
Basically, is it possible to have jQuery's hover only fire over the actual content of a png with an alpha channel.
So in the image below;
http://i.imgur.com/3kO7v.png
Only fire on the rectangle and not the alpha channel which make up the rest of the document bounds...
I've tried the obvious $('obj').hover(function(){stuff}) but this fires on the alpha channel too...
The final implementation of this will be for more complex shapes than just a rotated square, so css3 tricks are out for the primary basis, but could be used with a back-up/shim, plus I need to support IE7 and ipad,iphone,ipod....
If there is a CSS2 solution then that would be suitable too. Also any real guidance on this issue is more than welcome.
My backup for this will be to have an empty div, display block and position it over the shape and then use that. This will obviously not be ideal for the less square objects.
Any hits or tips are more than welcome.
Thank you
Yes it is possible depending on the stacking context of your elements. Keep in mind that when you do a focus over any particular element on a page, that you are actually focusing all other elements within the same stacking context.
So what you could do is either stop the event from bubbling up the stack (if the element you want to "hover" is lower in the stack that the elements you want to prevent hover effects on), or specifically put in prevent default for onhover events for all elements in the stacking context except for the one you want to actually get a hover effect.
I have an image in a HTML document with an absolutely positioned Canvas element on top of it, to allow me to draw over the image. This may seem like bad practice, but I am also using a JavaScript library that adds effects to the image when you mouse over it. For this reason, I cannot simply draw the image to the canvas.
However, having the Canvas in front breaks the JavaScript library, as the image is no longer generating mouse-over events.
Is there any way of having these two bits of functionality simultaneously?
(If needed, I can specify exactly what my problem is, but answers are more useful when they are generic.)
You can use jQuery.trigger or dispatchEvent with initMouseEvent to manually launch event on image.
Simple way to do it bind events to canvas and then pragmatically track if the cursor within the bound of image...
In the end I set the image as the css background of the canvas, then had a transparent png over the top to bind events to and track movement.
I also ended up modifying the library to my own needs, as I couldn't find another way.
I am simply looking for a way of using drag and drop without jquery or any other library. If a dragged object is dropped on another element the later element should start an event (in FF - better would be browser independent).
I know that drag and drop for JavaScript was discussed sometimes before but the previous postings didn't help me.
Although I found some examples it is not clear to me if there is a "drop" or "dragdrop" events exist but these things don't work:
<p ondrop='alert("It worked");'>Text</p>
<p ondragdrop='alert("It worked");'>Text</p>
How could this be done?
Many thanks in advance.
I agree with the other answers. A library will save you a lot of time and headache. This is coming from someone who just recently created a drag-and-drop control from scratch.
If you insist though this is what you'll need to do:
Bind a onmousedown event to the div you want to drag (div.onmousedown).
Change the div's position style to absolute (div.style.position = 'absolute')
Begin capturing mouse movement (document.onmousemove).
On mouse move update the div's position (div.style.top|left = '[location]px')
On the div's onmouseup event (or the document's) unbind all the handlers and do any other cleanup (null out position changes, etc).
Some problems a library will probably solve:
While dragging you will select text on the page (looks ugly).
Binding to events is different between browsers.
You have to calculate the size of the element being dragged if you want to show placeholders and to make it not "pop" when you begin dragging the control (since changing to absolute positioning will remove the element from flow).
You will probably want your dragged element to move fluidly so you will have to store some mouse offset when selecting the element or automatically center the element to the mouse.
If you want to drag an item in a list you'll have to write a ton more custom code for that list to accept the dragged item.
You'll have to take into consideration dragging when the window is scrolled and possibly dragging inside other elements that are positioned strangely.
I am simply looking for a way of using drag and drop without jquery or any other library.
I'm sorry, but there are no such thing as simply drag and drop without any library. You can write it all yourself, but that will be a lot of JS to make it work in all browsers.
Hmm. It's probably not that simple that you'd want to do it yourself, but I would look at Peter Michaux's FORK Javascript drag and drop library -- unlike JQuery or all those big libraries, FORK's modules are decoupled from each other, and are simple enough that you could probably look at Peter's source code and figure out the bits you need. (edit: I'd just use FORK.Drag as it's really small: 7.6KB total minified)
While I agree that library is the way to go, the answer you want is onmousedown, onmousemove, onmouseup. You have to handle those three events.
In onmousedown you'd find the target (event.target or similar in different browsers) and set draggedObject = event.target. You'd also start handling the onmousemove event.
Whenever the onmousemove event fired, you'd move the dragged element based on the difference in position since last time the onmousemove event fired.
In the onmouseup event, you'd clear your draggedObject variable and stop handling onmousemove.
It's not very crossbrowser, but it's the core of what you'd need to do for dragging and dropping.