How to detecting a click under an overlapping element? - javascript

I have two HTML documents, b.html contains c.html using an iframe.
On b.html I need to draw some DIV (in my example id=selector), which partially cover content of c.html visualized in the iframe.
I need to get the ID of a DOM element corresponding to the mouse coordinate under the DIV selector.
At the moment Using document.elementFromPoint() directly in in c.html works partially, as when the mouse it is on DIV selector I cannot identify the underling DOM element in c.html (in this example DIV c).
I would need to know:
Is it possible to select element under another, using document.elementFromPoint() or any other means?
What could be a possible alternatively solution possibly using DOM and native API?
Example here (Please look at the console in Chrome):
http://jsfiddle.net/s94cnckm/5/
----------------------------------------------- b.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>B</title>
<script type="text/javascript">
window.app = {
start: function () {
}
};
</script>
<style>
#selector {
position: absolute;
top: 150px;
left: 150px;
width: 250px;
height: 250px;
-webkit-box-shadow: 0px 0px 0px 5px yellow;
-moz-box-shadow: 0px 0px 0px 5px yellow;
box-shadow: 0px 0px 0px 5px yellow;
}
#iframe {
width: 500px;
height: 500px;
border: none;
}
</style>
</head>
<body onload="app.start();">
<div id="selector">SELECTOR</div>
<iframe id="iframe" src="c.html"></iframe>
</body>
</html>
----------------------------------------------- c.html
<html lang="en">
<head>
<meta charset="utf-8" />
<title>C</title>
<script type="text/javascript">
window.app = {
start: function () {
document.querySelector('body').addEventListener('mousemove', function (event) {
//console.log(event.pageX, event.pageY, event.target.id);
var item = document.elementFromPoint(event.pageX, event.pageY);
console.log(item.id);
}.bind(this));
}
};
</script>
<style>
body {
background-color: lightslategray;
}
#a {
position: absolute;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
background-color: green;
z-index: 2;
}
#b {
position: absolute;
top: 100px;
left: 100px;
width: 100px;
height: 100px;
background-color: #ffd800;
z-index: 1;
}
</style>
</head>
<body onload="app.start();">
<h1>Content</h1>
<div id="a">a</div>
<div id="b">b</div>
</body>
</html>

A possible soltion is the usage of pointer-events.
The CSS property pointer-events allows authors to control under what
circumstances (if any) a particular graphic element can become the
target of mouse events. When this property is unspecified, the same
characteristics of the visiblePainted value apply to SVG content.
When you apply
#selector {
/* ... */
pointer-events: none;
}
All content of #selector and the element itself are no more interactive. Content may not be selected and events like :hover or click are not applicable.
Here is the demo with the above css: http://jsfiddle.net/s94cnckm/6/

Another possible solution, is to capture the document coordinates of a mouse event fired on the masking item(DIV.selector), momentarily hide that masking item, and then ask the document what is under that coordinate position (using document.elementFromPoint(x,y)) before showing the masking item again.
The support for document.elementFromPoint() cover also old version of IE.
Unfortunately pointer-events has limited support for older version of IE.
Here a working example:
http://jsfiddle.net/s94cnckm/14/
document.getElementById('iframe').contentDocument.addEventListener('click', function (event) {
alert(event.target.id);
}.bind(this));
document.getElementById('selector').addEventListener('click', function (event) {
var selector = document.getElementById('selector');
selector.style.display = 'none';
var item = document.getElementById('iframe').contentDocument.elementFromPoint(event.pageX, event.pageY);
selector.style.display = '';
alert(item.id);
}.bind(this));
Regarding the use of pointer-events I link to mention some related article, included a work around for older version of IE.
How to make Internet Explorer emulate pointer-events:none?
https://css-tricks.com/almanac/properties/p/pointer-events/
http://davidwalsh.name/pointer-events
http://robertnyman.com/2010/03/22/css-pointer-events-to-allow-clicks-on-underlying-elements/
This solution was inspired by this article:
http://www.vinylfox.com/forwarding-mouse-events-through-layers/

Related

Why isn't fadeIn() working?

My HTML Code is :
<!DOCTYPE html>
<html>
<head>
<title>Furry Friends Campaign</title>
<link rel="stylesheet" type="text/css" href="styles/my_style.css">
</head>
<body>
<div id="clickMe">Show me the the Furry Friend of the Day</div>
<div id="picframe">
<img src="images/furry_friend.jpg" alt="Our Furry Friend">
</div>
<script type="text/javascript" src="scripts/jquery-3.1.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
$("#clickMe").click(function()
{
$("img").fadeIn(1000);
$("#picframe").slideToggle("slow");
});
});
</script>
</body>
</html>
The accompanying CSS looks like:
#clickMe {
background: #D8B36E;
padding: 20px;
text-align: center;
width: 205px;
display: block;
border: 2px solid #000;
}
#picframe {
background: #D8B36E;
padding: 20px;
width: 205px;
display: none;
border: 2px solid #000;
}
The slideToggle works perfectly, but for some reason, the image doesn't fade in. I've tried setting the duration to longer periods, but that yields the same results. Can someone point out what's wrong with this code? I'm using the latest version of Chrome.
UPDATE: I tried running the example code of the book I was using, which uses jquery-1.6.2.min.js and using that version of jQuery, the code works perfectly. Is this some error on jQuery's part? Or is the new way that things will be done now?
Since jQuery 1.8, fadeIn no longer initially hides the image, so trying to fade in an image which is visible or doesn't have display set to none won't lead to anything.
To fade in, you should hide it first. Initially it's not hidden, since children don't inherit display CSS property, and you have set it to none only on #picframe, the parent of img. Just add $("img").hide(); on ready. This will make it work.
Since it looks like you need to fade it in / out with each click, you could do the following instead of $("img").fadeIn(1000):
if($("img").is(":hidden")) $("img").fadeIn(1000);
else $("img").fadeOut(1000);
Demo below.
#clickMe {
background: #D8B36E;
padding: 20px;
text-align: center;
width: 205px;
display: block;
border: 2px solid #000;
}
#picframe {
background: #D8B36E;
padding: 20px;
width: 205px;
display: none;
border: 2px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<div id="clickMe">Show me the the Furry Friend of the Day</div>
<div id="picframe">
<img src="images/furry_friend.jpg" alt="Our Furry Friend">
</div>
<script type="text/javascript" src="scripts/jquery-3.1.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
//$("img").hide();
$("#clickMe").click(function() {
$("img").fadeIn(1000);
$("#picframe").slideToggle("slow");
});
});
</script>
Somehow, img didn't inherit the display:none in #picframe div. Here's the fix: https://jsfiddle.net/69rLha7e/1/
There is a "timing" consideration while playing with multiple animations a time.
In this CodePen, I used diferent timing for fadeIn, fadeOut and toggleSlide.
And you have to check the display state in order to decide to fade in or out.
$(document).ready(function(){
$("#clickMe").click(function(){
console.log( $("img").css("display") ) ;
if( $("img").css("display")=="inline" ){
$("img").fadeOut(400);
}else{
$("img").fadeIn(800);
}
$("#picframe").slideToggle(400);
});
});

IFrame Resizable, but not Draggable with JQuery

I have an iframe displaying "iframetarget.html" (for now just a blank red page for testing purposes). I want to be able to resize it, as well as drag it around without constraint. I used JQuery to make it resizable, and this worked. Then, I added .draggable, and it fails to work. Can you see what I'm doing wrong?
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<style>
#iframe {
width: 100%;
height: 100%;
border: none;
background: #eee ;
z-index: 1;
}
#resizable {
width: 100px;
height: 100px;
background: #fff;
border: 1px solid #ccc;
z-index: 9;
}
</style>
<script>
$(function() {
$('#resizable').resizable({
start: function(event, ui) {
$('iframe').css('pointer-events','none');
},
stop: function(event, ui) {
$('iframe').css('pointer-events','auto');
}
});
});
</script>
<script>
$(function() {
$('#resizable').draggable();
});
</script>
</head>
<body>
<div id="resizable">
<iframe src="iframetarget.html" id="iframe">
</div>
</body>
I'm guessing the click is going to the page in the iframe instead of being caught by your div. Resizable automatically add handles so that's why it works. You can add a handle to your draggable or simply put a border. For testing purpose, you'll see that your actual code works if you change your css to:
#iframe {
width: 100%;
height: 100%;
border: solid 10px black;
background: #eee ;
z-index: 1;
}
Then click on the border and it'll drag.
Or you add a small div that works as a handle:
http://api.jqueryui.com/draggable/#option-handle
I had a familiar problem, dragging iFrames with jQueryUi (I've used a dialog and it was only possible to drag it holding the title bar). My solution was using ajax. Try that other way of "including another page":
function loadiframe(){
var xmlhttp;
if (window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}else{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
document.getElementById("resizable").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","iframetarget.html",true);
xmlhttp.send();
}
If you run loadiframe(); the content of iframetarget will be load to the #resizable element. Be careful using HTML, CSS and JavaScript in both pages, an iFrame just displays the other page in your one, but this will get the source code of iframetarget.html an add it into the div. You won't need HTML-declaration, html-, head- and body-tags in the iframetarget-file.

How to put img in front of svg tag

I'm using snap.svg
I have index.html
<!Doctype>
<html>
<head>
<title>MAP_TEST</title>
<meta charset="utf-8">
<script type = "text/javascript" src = "JS/jquery.js"></script>
<script type = "text/javascript" src = "JS/init.js"></script>
<script type = "text/javascript" src = "JS/snap.svg.js"></script>
</head>
<body>
<div class="comm_cont">
<div id = "svgborder">
<svg id = 'svgmain'></svg>
</div>
</div>
</body>
</html>
And init.js
$( document ).ready(function() {
var s = Snap("#svgmain");
var g = s.group();
Snap.load("SVGFILES/3k1e-test.svg",function(lf)
{
g.append(lf);
//trying to load picture... Scale button in future
$('<img />', {
src: 'PNG/plus.png',
width: '30px',
height: '30px',
id: 'buttoninrk'
}).appendTo($('.comm_cont'));
//this button must be on picture
//but in front of the picture svg element
//And i can't click the button
});
});
I played with z-indexes of #svgborder and #buttoninkr but it didn't help me.
How to put button in front of svg element?
#buttoninkr, #svgborder
{
position: absolute;
}
#svgborder
{
border:5px solid black;
z-index: 0;
margin-left:auto;
border-radius: 5px;
display: inline-block;
}
#buttoninkr
{
z-index: 1;
}
Added css code with z-indexes.
There is a reason why i'm not using svg buttons instead jquery image button.
Ok, as you can see #svgmain in front of plus.png
http://jsfiddle.net/3wcq9aad/1/
Any ideas?
Solved
#svgborders
{
position: absolute;
background-color: #535364;
border:5px solid black;
z-index: 0;
margin-left:auto;
border-radius: 5px;
display: inline-block;
}
#buttoninrk, #buttondekr, #home_btn
{
position: inherit;
top:0;
margin:10px;
z-index: 1;
}
#buttoninrk
{
right:0px;
}
#buttondekr
{
right:60px
}
EDIT: It wasn't the position of the div that made the difference, but simply adding a width and height. So the original HTML works fine as long as you add a width and height to svgborder in the CSS:
http://jsfiddle.net/3wcq9aad/4/
(Note that sometimes, the position of an element within a document can make a difference to how z-index works.)
If you put the svgborder div before the svg, then z-index will work, but you'll need to know the width and height of your SVG and set it on the svgborder div.
<body>
<div class="comm_cont">
<div id="svgborder"></div>
<svg id='svgmain'></svg>
</div>
</body>
#svgborder
{
z-index: 2;
width:330px;
height:150px;
...
}
Fiddle: http://jsfiddle.net/3wcq9aad/3/
svg does not support z-index
Use element position instead:
$('element').css('position', 'absolute');
Is there a way in jQuery to bring a div to front?

my overlay is not being centered using css

<head>
<title>Overlay test</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css">
#overlay {
position: absolute;
background-color: #ccffcc;
display: none;
height: 200px;
margin: 0 auto;
width: 200px;
}
</style>
<script type="text/javascript">
//<![CDATA[
function hide() {
document.getElementById("overlay").style.display = "none";
}
function show() {
document.getElementById("overlay").style.display = "block";
}
//]]>
</script>
so when the user clicks it runs show() which places the css box on top. However i want it to be centered in the browser. I've set the margin: 0 auto; which should be doing the trick shouldnt it?
I'm just trying to create an overlay function without using jquery because it seems to be incompatible with my schools cms templates.
Thanks
Margin: 0 auto won't work on position absolute elements, they exist in their own little world, outside of normal flow. So in order to pull this off, you need to do an extra step. The CSS dead centre technique will work here.
Try setting the top and left attributes on your overlay.
Use % to set top and left position. Set css attribute top:10%; Left 40%;

The drag doesn't work when it has a siblings img in IE

I'm trying to make a drag box with a sibling img and the 'move-obj' can be dragged.It runs correctly in other browser but IE(8,9,10). In IE, just while you hover the border can you drag the 'move-obj', but if you remove the tag 'img' it work correctly.I found that if I add a background-color to the 'move-obj',it will run correctly too, but it isn't what I want. Can somebody give me some advice?Here is the codepen
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.wrap{
position: relative;
width: 100%;
height: 100%;
background-color: #f0f0f0;
padding: 10%;
}
.wrap-inside{
position: relative;
width: 500px;
height: 500px;
border: 1px solid #ddd;
}
.move-obj{
cursor: move;
position: absolute;
width: 100px;
height: 100px;
border: 1px solid blue;
}
.bg{
width: 500px;
height: 500px;
position: absolute;
}
</style>
</head>
<body>
<div class="wrap">
<img class="bg" src="https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcTE2qkLv64zdI4z5uIbE1oSMmI0AiQcbwbhAYAyI0cF2Dwg88tb" alt="">
<div class="wrap-inside">
<div class="move-obj"></div>
</div>
</div>
</body>
</html>
If I understand you correctly if and only if you are hovering over the mov-obj div you want to be able to move around the https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcTE2qkLv64zdI4z5uIbE1oSMmI0AiQcbwbhAYAyI0cF2Dwg88tb image, right?
If this is what you want, look into either using jQuery and selecting the div on a hover event
$(.mov-obj).hover(function(event) {
//change the x and y coordinates of the image dynamically here of the image
//you can use the event.pageX and event.pageY (I think) to get how much/many pixels have been moved since the hover happened
}
or you can use pure JavaScript
document.getElementsByClassName("mov-obj").addEventListener("mouseenter", function( event ) {
//do something to change the img position dynamically
}, false);
//also do it for the mouseleave event
document.getElementsByClassName("mov-obj").addEventListener("mouseleave", function( event ) {
//do something to change the img position dynamically
}, false);
maybe set a flag letting you know that the mouseenter has happened, but not the mouseleave event
and then if and only if the mouse is inside the div add a click event to the div
while the click is pressed and the mouseleave event hasn't been triggered dynamically relocate the image depending on how much the mouse pointer has moved
(you can add a click event like this fyi)
document.getElementsByClassName("mov-obj").addEventListener("click", function( event ) {
//do something to change the img position dynamically
}, false);
or with jQuery
$(.mov-obj).click(function(event) {
//do something
}
hope this helps
Edit, just paste this code into a browser and try it out:
Note: this only works if you don't move the mouse outside of the div's width and height that you are wanting to move. I'll let you figure out how to fix that part if the mouse goes outside the div what happens
<DOCTYPE html>
<html>
<head>
</head>
<body>
<style>
#div1 {
border: 2px orange solid;
width: 500px;
height: 500px;
}
#div2 {
border: 2px purple solid;
width: 250px;
height: 250px;
position: absolute;
}
</style>
<div id="div1">
<div id="div2">
</div>
</div>
<script type="text/javascript">
// add event listeners to div
var div2 = document.getElementById("div2");
div2.addEventListener("mousedown", getOriginalPosition, false);
div2.addEventListener("mouseup", changeLocation, false);
var helperX;
var helperY;
function getOriginalPosition(event) {
//use these to help with the calculation later
helperX = event.offsetX;
helperY = event.offsetY;
}
var end_xPosition;
var end_yPosition;
function changeLocation(event) {
end_xPosition = event.pageX;
end_yPosition = event.pageY;
div2.style.left = end_xPosition - helperX;
div2.style.top = end_yPosition - helperY;
}
</script>
</body>
</html>

Categories