Javascript detect elements in front of elements - javascript

How can one know if an element is in front of another element, if the overlaying element is transparent? The purpose for this is if you're artificially clicking a page element by its ID, and you're ensuring there's no overlay on top of the element that would make confirm the click as synthetic (as a normal user would have to click on the overlay).
Case 1: The overlay is a child of the clickable element To Detect it: Ensure there's no children of the clickable element that look unusual.
Case 2: The overlay has an absolute position and a higher z-index to overlay the clickable element
To Detect it: No clue! Unless you iterate through the bounding rectangles and z-index of every element in the DOM or go through the entire DOM looking for particular style attributes. That is expensive.
So, given the number of ways an element can be made to overlay another element, how can a user script detect elements overlaying elements? I suspect a very verbose method of going through the entire DOM could be avoided.

It turns out there's two ways to do this, and by this I mean two ways to find out if any given element is the top most element regardless of opacity.
Adapted from this blog post post and using their code (with some modifications) it's possible to see the top most element at any given mouse position. I modified their code to look for the computed style zIndex of any elements at a position. The downside to this approach is it's computationally costly in that you're looking at the positions of every element in the DOM more or less.
This stack question about checking whether an element is really visible on screen received an answer that linked to a browser method document.elementFromPoint which when given some screen coordinates returns the top most element, regardless of opacity but in accordance with its display style. It appears as though that function is supported in at least Firefox and Chrome.
In the end, there's two solutions to choose from, with the latter likely being the best solution in terms of reliability and cost.

Related

Bring an element in front of others that have the same z-index

The user can press a button to create new divs on the screen. Each div is the same and has the same z-index. Newer elements display in front of older elements. The user has the ability to drag around the elements. I would like it so that when a user drags an element, that element is now permanently in front of the other elements (until a different one is created/dragged).
Is it possible to do this without keeping track of z-index somewhere in JS and increment it on creation/click? I'd like to avoid this if possible. Is there some way I can use jQuery or something to make a clicked element act as if it was recently created (which I guess is just determined by position in the DOM?)
I assume you are doing something like
container.appendChild(newDiv)
Now, when you click and drag an element, you can move it to the front.
var parent = recentlyClicked.parentElement // or container
parent.insertBefore(recentlyClicked, parent.firstChild)
This inserts your desired div as the first child of its parent, which will move to the top.
Edit: it appears that elements later in the DOM are the ones that are shown on top. In that case, you'll probably want to append the child instead.
recentlyClicked.parentElement.appendChild(recentlyClicked)
On click you could add a class to the element where the CSS targeting that class has a slightly higher z-index. This is probably the cleanest way to do it (no keeping track of z-indexes, just toggling the existence of that class on mouse down & mouse up.
Another idea (not sure if it'd work, but might be fun to try) would be to add a tabindex="0" to all the elements. They can now receive focus. Then in your CSS add a ":focus" state selector targeting those elements. Increase their z-index with that. I don't recall if the focus happens on mouse down or after a full click. It might bring along other side effects line outlines on the element you don't want. And mess with the usability of the tab key on your website. I'd probably not use this unless it's somehow really much simpler in a non-production circumstance.

XHTML strict: positioning of div/img does not work as intended

after several days of researching and trying I want to see if you can help me.
I have a graph (coord) and students should mark the extrema of the graph. I have to use JavaScript for this and work in XHTML 1.0 Strict//EN. The idea was that the student clicks on the position on the graph where he/she thinks an extremum lies, this triggers a JavaScript function (addPoint) which adds an img into the same div in which the graph lies (coordDiv) and gives it the position where the student clicked. For an example visit http://ourresidence.net/JavaScript/ where you should be able to view both the site code and the JavaScript code.
As far as I understood, the positioning has to be absolute. static and fixed are incompatible with the desired behaviour and relative would be very difficult because 1. I don't know where the next "ordinary" positioning would be and 2. it would get more complicated with a student deleting a point. So, absolute it is.
Then the positioning should be absolute relative to the div coordDiv and after some time I even figured out how to give the div a concrete dimension (through it's a bit static, the approach with adjustCoordDiv() in klausur.js hasn't work out). However, if I resize the bounderies of the browser, the div and the graph wanders (since they are centered) but the point does not. That needs to be fixed.
And reading how mixed up the acknowledgement of zooming is in different browsers by now I've already completely given up handling zooming in the exercise, but if you come with a solution for that too, my praise would know no end.
Positioning is relative to some containing element in HTML that is positioned itself. If there isn't any such element, positioning is relative to document's body (as in your case). Positioning basically means to have applied some other position in CSS than static.
So you basically need to subordinate your click points to the DIV containing the whole coordinate system (as you do now ). That div should have
position:relative
without any repositioning to position it and to start a new "local coordinate system" for using
position:absolute
on any subordinated element.
On clicking, coordinates of that click need to be converted from global coordinate space to local one. This might be achieved iterating from clicked element to document element using properties offsetParent, offsetTop and offsetLeft of each passed element.

Performance with infinite scroll or a lot of dom elements?

I have a question on a big # of dom elmenets and performance.
Let's say I have 6000 dom elements on a page and the number of the elements can be increased as a user interact with the page (user scrolls to create a new dom element) like twitter.
To improve the performance of the page, I can think of only two things.
set display to none to invisible items to avoid reflow
remove invisible items from the dom then re-add them as needed.
Are they any other ways of improving a page with a lot of dom elements?
We had to deal with a similar problem on FoldingText. As the document grew larger, more line elements and associated span elements were created. The browser engine just seemed to choke, and so a better solution needed to be found.
Here's what we did, may or may not be useful for your purposes:
Visualize the entire page as a long document, and the browser viewport as the lens for a specific part of the long document. You really only have to show the part within the lens.
So the first part is to calculate the visible view port. (This depends on how your elements are placed, absolute / fixed / default)
var top = document.scrollTop;
var width = window.innerWidth;
var height = window.innerHeight;
Some more resources to find a more cross-browser based viewport:
How to get the browser viewport dimensions?
Cross-browser method for detecting the scrollTop of the browser window
Second, you need a data structure to know which elements are visible in that area
We already had a balanced binary search tree in place for text editing, so we extended it to manage line heights too, so this part for us was relatively easy. I don't think you'll need a complex data structure for managing your element heights; a simple array or object might do fine. Just make sure you can query heights and dimensions easily on it. Now, how would you get the height data for all your elements. A very simple (but computationally expensive for large amounts of elements!)
var boundingRect = element.getBoundingClientRect()
I'm talking in terms of pure javascript, but if you're using jQuery $.offset, $.position, and methods listed here would be quite helpful.
Again, using a data structure is important only as a cache, but if you want, you could do it on the fly (though as I've stated these operations are expensive). Also, beware of changing css styles and calling these methods. These functions force redraw, so you'll see a performance issue.
Lastly, just replace the elements offscreen with a single, say <div> element with calculated height
Now, you have heights for all the elements stored in your Data structure, query all the elements that lie before the visible viewport.
Create a <div> with css height set (in pixels) to the sum of the element heights
Mark it with a class name so that you know its a filler div
Remove all the elements from the dom that this div covers
insert this newly created div instead
Repeat for elements that lie after the visible viewport.
Look for scroll and resize events. On each scroll, you will need to go back to your data structure, remove the filler divs, create elements that were previously removed from screen, and accordingly add new filler divs.
:) It's a long, complex method, but for large documents it increased our performance by a large margin.
tl;dr
I'm not sure I explained it properly, but the gist of this method is:
Know the vertical dimensions of your elements
Know the scrolled view port
Represent all off-screen elements with a single div (height equal to the sum of all element heights it covers for)
You will need two divs in total at any given time, one for elements above the visible viewport, one for elements below.
Keep track of the view port by listening for scroll and resize events. Recreate the divs and visible elements accordingly
No experience myself with this, but there are some great tips here: http://engineering.linkedin.com/linkedin-ipad-5-techniques-smooth-infinite-scrolling-html5
I had a look at Facebook and they don't seem to do anything in particular on Firefox. As you scroll down, the DOM elements at the top of the page don't change. Firefox's memory usage climbs to about 500 meg before Facebook doesn't allow you to scroll further.
Twitter appears to be the same as Facebook.
Google Maps is a different story - map tiles out of view are removed from the DOM (although not immediately).
It's 2019. The question is really old, but I think it is still relevant and interesting and maybe something changed as of today, as we all now also tend to use React JS.
I noticed that Facebook's timeline seems to use clusters of content which is hidden with display: none !important as soon as the cluster goes out of view, so all the previously rendered elements of the DOM are kept in the DOM, it's just that those out of view are hidden with display: none !important.
Also, the overall height of the hidden cluster is set to the parent div of the hidden cluster.
Here are some screenshots I've made:
As of 2019, what do you think about this approach? Also, for those who use React, how could it be implemented in React? It would be great to receive your opinions and thoughts regarding this tricky topic.
Thank you for the attention!

jQuery Hover Over Image Content Only and Not Alpha

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.

Why isn't z-index working as I'd expect it to here?

A requirement for a current project of mine involves "highlighting" an HTML element in the context of a page. That is, I need to provide some sort of visual effect that decreases the brightness of the surrounding page while leaving the element at full brightness.
To achieve this, I'm trying the following approach:
Determining the highest z-index value of any element on the page (using JavaScript).
Creating an element to function as a "backdrop" on top of the page. This is just a <div> with a translucent gray background image, sized to 100% of the width and height of the <body> element, with position: fixed. I set its z-index to 1 greater than the highest z-index I've found on the page, with the intent that it will overlay every other element on the page.
Change the z-index of the "highlighted" element to 1 greater than the backdrop. The intent is to allow it to sit on top of the backdrop, which in turn sits on top of the rest of the page.
I got it working on a quick test page:
http://troy.onespot.com/static/stack_overflow/z_index_test.html
but when I tried to set it up on a few actual Web pages, it didn't work in all cases. For example:
http://troy.onespot.com/static/stack_overflow/z_index.html
Here, I've inserted two "dummy" elements on a copy of a Jacksonville.com article page, both with a class of test (if you're looking at the page source, they're at lines 169 & 859).
I also added some JavaScript (using jQuery) at the very end of the page that functions as I've described above.
The first <div class="test"> does function as I'd expect it to. However, the second one does not - it seems to still be stuck beneath the "backdrop" element, despite having a higher z-index.
I think this may have something to do with stacking contexts, but after reading through the relevant W3C docs (http://www.w3.org/TR/CSS21/visuren.html#z-index & http://www.w3.org/TR/CSS21/zindex.html), I still can't fathom why this is happening. I'd appreciate anyone more familiar with z-index and stacking order than I to take a look at my examples and let me know if anything looks suspicious.
Please note that I've only tested these examples in Firefox v3.6.
Thanks very much for any help!
The problem is that the second test div is inside a bunch of other HTML elements, one of which must be creating a new stacking context (it may be the #wl-wrapper-tier-1 div). Basically, a new stacking context is created whenever an element is positioned and has a z-index other than auto, see this MDC article for more info on stacking contexts.
Ultimately this means you can't achieve your desired effect reliably with this method. I think you're probably better off composing 4 divs to surround the target element.
If the element that you're highlighting is inside a different element (stacking context) with a z-index lower than the backdrop, it will not appear higher than the backdrop, since the element's z-index only controls stacking order within that parent.
The only good solution is to clone the highlighted element and add the clone to the <body> tag.
Beware of inherited CSS styles, which would be lost.

Categories

Resources