How do I pass javascript events from one element to another? - javascript

Setting up the stage:
I have 2 layers one on top of the other. The bottom layer contains links (simple images), The top layer contains advanced tooltip like hovers for the bottom layer. These tooltips can be large (they can overlap onto other links easily, and almost always overlap the link they are tooltipping).
My question:
I'd like my mouseover events to occur on the bottom layer, and then on mouseover display the tooltip in the upper layer. This way as you move off of the bottom link the tooltip in the upper layer goes away, and the tooltip for the new link can show up.
How do I take the events from the top layer and pass them to the layer below instead? So that the top layer is event transparent.
Example HTML:
jQuery(document).ready(function(){
jQuery('div.tile').click(function(){
jQuery('#log').html(this.id + " clicked");
return false;
});
jQuery('div#top').click(function(){
jQuery('#log').html('Top clicked');
return false;
});
});
.tile { width: 100px; height: 100px; position: absolute; }
.tile:hover, over:hover {border: 1px solid black;}
.over { width: 100px; height: 100px; position: absolute; display:none}
.stack, #sandwich { width: 400px; height: 400px; position: absolute; }
#tile1 {top: 50px; left: 50px;}
#tile2 {top: 75px; left: 10px;}
#tile3 {top: 150px; left: 310px;}
#tile4 {top: 250px; left: 250px;}
#tile5 {top: 150px; left: 150px;}
#over1 {top: 55px; left: 55px;}
#over2 {top: 80px; left: 15px;}
#over3 {top: 155px; left: 315px;}
#over4 {top: 255px; left: 255px;}
#over5 {top: 155px; left: 155px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<div id="sandwich">
<div class="stack" id="bottom">
<div class="tile" id="tile1">1</div>
<div class="tile" id="tile2">2</div>
<div class="tile" id="tile3">3</div>
<div class="tile" id="tile4">4</div>
<div class="tile" id="tile5">5</div>
</div>
<div class="stack" id="top">
<div class="over" id="over1">Tooltip for 1</div>
<div class="over" id="over2">Tooltip for 2</div>
<div class="over" id="over3">Tooltip for 3</div>
<div class="over" id="over4">Tooltip for 4</div>
<div class="over" id="over5">Tooltip for 5</div>
</div>
</div>
<div id="log"></div>
With the example javascript I've verified that the events work like normal, and only top is clicked. But I basically want the "over" items to be event transparent.

For people stumbling on this nine years later (like I did) the best way to do this now is with the CSS pointer-events property... simply set it to 'none' for your element(s) and behold the magic. No JS required.
https://caniuse.com/#search=pointer-events

Hope I understand the OP, but you can replicate the event on any selector after the original event has occurred: http://jsfiddle.net/Cr9Kt/1/
In the linked sample, I take the event on the top layer and create a similar event fired on the bottom layer. You can take this further with any individual clicking of each element(as opposed to top and bottom as a whole).
This is a borrowed idea from another question: Triggering a JavaScript click() event at specific coordinates

I am not quite certain that I understand what you are asking for. It sound to me a bit like a tool tip. Here is an example of how to do a tooltip this using jQuery, CSS and HTML.
http://jsbin.com/ilali3/13/edit
Hope that gets you started. If you add some more details, or modify that jsbin with more details we can iterate a bit.
I updated the example a bit to include storing tool tip information into the html element itself using jQuery. This is a bit cleaner.
Bob

This may seem overly complex and inelegant...it fakes your functionality.. but it works ;)
$(document).ready(function(){
var tileData = new Array();
// get coordinate data for each tile
$('div.tile').each(function(){
var tileInfo = {};
tileInfo.id = this.id;
tileInfo.text = $(this).text();
tileInfo.width = $(this).outerWidth();
tileInfo.height = $(this).outerHeight();
tileInfo.position = $(this).position();
tileInfo.coords = {};
tileInfo.coords.top = tileInfo.position.top;
tileInfo.coords.right = tileInfo.position.left + tileInfo.width;
tileInfo.coords.bottom = tileInfo.position.top + tileInfo.height;
tileInfo.coords.left = tileInfo.position.left;
tileData.push(tileInfo);
});
$('div.tile').click(function(){
$('#log').html(this.id + " clicked");
return false;
})
$('div#top').click(function(event){
$('#log').html('Top clicked');
// try to find tile under your mouse click
for(i=0; i<tileData.length;i++){
if(
event.pageX >= tileData[i].coords.left &&
event.pageX <= tileData[i].coords.right &&
event.pageY >= tileData[i].coords.top &&
event.pageY <= tileData[i].coords.bottom
) {
// found a tile! trigger its click event handler
$('#' + tileData[i].id).click();
}
}
return false;
});
});
Try it here: http://jsfiddle.net/neopreneur/vzq4z/1/

Related

How to detect elements using "position: absolute"?

I'm trying to position an element exactly in the same "X" coordinate of another element.
There are many solutions in stackoverflow to get the position using something like this:
var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);
My problem is that when I try to apply the value on "element.style.left" of elements that are inside other elements positioned as "absolute", the element position becomes larger because the "left: 0" is the beginning of the absolute element and not "left: 0" of the document.
The more "nested" elements exist using "absolute", the greater the difference.
Is there any way to detect elements using "position: absolute" so that I can offset the actual value to be positioned by discounting the "left" of each element with "absolute"?
This is the problem:
<span class="dropdown-label">Some menu</span>
<nav class="dropdown-menu">
<a class="item">Email</a>
<a class="item">Twitter</a>
<a class="item">Tumblr Blog</a>
<span class="dropdown-label">Another menu</span>
<nav class="dropdown-menu">
<a class="item">Foo</a>
<a class="item">Bar</a>
<a class="item">I'm Batman</a>
<span class="dropdown-label">Yet another menu</span>
<nav id="finales" class="power-dropdown">
<a class="item">Foo</a>
<a class="item">Bar</a>
<a class="item">I'm Robin</a>
</nav>
</nav>
</nav>
Each dropdown needs to be positioned with the "lef" of its respective label, but we have dropdowns inside other dropdowns and each dropdown is positioned absolutely.
I know I can avoid the problem by using a "container" for each dropdown positioned as "relative" and so I do not need to dynamically set the "left" to anything.
The problem is that the HTML gets more verbose, which I'd like to avoid, plus I'd like to have control of how the dropdown appears to prevent it from being drawn off the screen.
But it seems like I've run into a problem that's impossible to solve, since I can not find anywhere a way to detect elements using "absolute" to be positioned.
Is there anything similar to "element.position" that gives me this information?
You asked for a way to detect position: absolute on elements.
Use window.getComputedStyle(element).position.
function findAbsoluteElementsFromList(list){
var ret = [];
for (var i = 0; i < list.length; i++)
if (window.getComputedStyle(list[i]).position === 'absolute')
ret.push(list[i]);
return ret;
}
console.log(findAbsoluteElementsFromList(document.querySelectorAll('div')));
.div {
width: 100px;
height: 100px;
position: absolute;
top: 0;
transform: translateY(50%);
}
#a {
position: relative;
left: 0;
background-color: #f00;
}
#b {
left: 25px;
background-color: #0f0;
}
#c {
left: 50px;
background-color: #00f;
}
<div class="div" id="a">
<div class="div" id="b">
<div class="div" id="c"></div>
</div>
</div>
Same function can be used to get all other CSS values.
What's the difference between Window.getComputedStyle and Element.getBoundingClientRect()? Read here.
Why can't you just use element.style.position? Read here.

What is the appropriate way to add a click event in place of a hover event added to pictures in an org chart?

I have been tasked to take some pre-existing code which has a float event on an org chart. When you hover over an individual on the org chart a picture pops up and displays all the employees under them.
They don't like that and would like it changed to a click event. I've listed the code for the float event but what would be an example of taking the contentFloating and making it a click event? Looking for the proper syntax please.
}
.orgContainer .contentStable .contentFloating img {
height: 720px;
width: 960px;
}
/* Float content */
.orgContainer .contentFloating {
border: 2px solid black;
display: none;
position: fixed;
}
.orgContainer .contentStable:hover .contentFloating {
display: block;
top: 7%;
left: 15%;
}
<div class="contentStable">
<img title="Scott Plemmons Director Supplier Quality Compliance" src="/sites/scm/utas_supp_qual/Home_Pictures/scott_plemmons.jpg" />
<p>
Scott Plemmons<br/> Director
<br/> Supplier Quality
</p>
<div class="contentFloating">
<img src="/sites/scm/utas_supp_qual/Home_Pictures/Org_Charts/Scott_Plemmons_Chart.jpg" />
</div>
</div>
This is an example of how to add a click event handler to a dom element, and then make another div appear when you click on it.
html
<div class="orgchart">click for details</div>
<div id="details">details</div>
css
#details {
position:absolute;
}
javascript
let elements = document.getElementsByClassName("orgchart");
for(var i = 0; i < elements.length; i++)
{
elements[i].addEventListener("click", function(e){
// get the position of the element that was clicked
let clickedItem = e.target;
var rect = clickedItem.getBoundingClientRect();
// set the details div to that position and fill it with content
let details = document.getElementById("details");
details.innerHTML = "Joe Average";
details.style.left = (rect.left + 10) + "px";
details.style.top = (rect.top + 20) + "px";
});
}
Check a jsfiddle example here

make div appear on mouse over

I am trying to make a div .description that appears where the mouse is as it hovers over an element.
So far, I have this code for making the div appear in a fixed location:
$('.tooltip').mouseover(function(e) {
// var to link tooltips and hand to description
var target = $(this).attr('data-show');
// hide current description if showing
if ($('.description').is(':visible')) {
$('.description').fadeOut(0);
};
e.stopPropagation();
$('#' + target).fadeIn(400);
});
$('body').mouseover(function(){
$('.description').fadeOut(0);
});
It works fine, but instead of just have .description appear, I need it to appear where the mouse hovers.
I tried adding this function:
function divPosition (event){
// pass mouse position to description div css
$(".description").css({top: event.clientY, left: event.clientX- 200});
};
but it didn't work. I also tried adding the line within the function but i'm not sure how to pass the event argument.
Please see my JSfiddle: https://jsfiddle.net/bns4zp1q/2/
You can listen to the mousemove event, and use your divPosition function.
https://jsfiddle.net/agbuLop1/
$('.tooltip').mousemove(divPosition);
function divPosition (event){
// pass mouse position to description div css
$(".description").css({top: event.clientY, left: event.clientX- 200});
};
Does the description really have to follow the mouse movement or just appear at hovered circle? Here is a quick and dirty example without javascript:
https://jsfiddle.net/k9jpqom2/1/
(new) HTML:
<div class="tooltip-container">
<div class="image" id="machine1">
<img src="http://axevilw.sellamachine.com/EnhFiles/advert/182/Machine.jpg/Machine.jpg">
<div class="tooltip" id="tooltip1" data-show="description1">1
<div class="description-container">
<div class="description" id="description1">
LED Strip Lighting
</div>
</div>
</div>
</div>
</div>
(additional) CSS
.description-container {
width:1px;height:1px;position:relative;
}
#tooltip1:hover .description {
display:block;
width:10em;
position:absolute;
left:-4em;
height:auto;
}
.tooltip{
width:5%;
height: 6%;
}
If you don't want to edit the HTML you can try something like this:
https://jsfiddle.net/g2p5g2r4/2/
.tooltip .description-container {
width:1px;
height:1px;
}
#tooltip1:hover + .description-container #description1 {
display:block;
width:10em;
position:absolute;
height:auto;
top: 36%;
left: 25%;
}
#tooltip1 {
top: 31%;
}
You will have to fine tune the position of #description1, #description2, etc...

Run Jquery only when an element is in the viewport

I'm trying to perform the Jquery function below when the element becomes visible in the viewport rather than on the page load. What would I need to change to allow that to happen? I'm using an external JS file to perform the Jquery, so keep that in mind.
Here's a piece of the HTML that is associated with the Jquery function -
<div class="skillbar clearfix " data-percent="70%">
<div class="skillbar-title" style="background: #FF704D;">
<span>Illustrator</span></div>
<div class="skillbar-bar" style="background: #FF704D;"></div>
<div class="skill-bar-percent">70%</div>
</div>
jQuery(document).ready(function(){
jQuery('.skillbar').each(function(){
jQuery(this).find('.skillbar-bar').animate({
width:jQuery(this).attr('data-percent')
},4000);
});
});
I once came across such problem and what I used is waypoints small library.
all you need is to include this library and do:
var waypoint = new Waypoint({
element: document.getElementById('waypoint'),
handler: function(direction) {
console.log('Element is in viewport');
}
})
Using CSS3 transitions instead of jQuery animations might be more performant and simpler. a cheap and nasty way of pushing it out of screen to demonstarate the effect.
There's a couple of things you'll need to do - firstly if you only want the animation to trigger when it's in the viewport then you'll need to check if anything is in the viewport on scroll. Then only update the bars width when it comes into view. If you want the effect to repeat every time it comes into viewport you'll need to set .skillbar-bar's width back to 0 if it's out of the viewport (just add an else statement to the viewport checking if)
I've added a 1000px margin-top and 400px margin-bottom in my example to .skillbar as a cheap and nasty way of demonstrating the effect
(function($){
$(document).ready(function(){
var $els = $('.skillbar'); // Note this must be moved to within event handler if dynamically adding elements - I've placed it for performance reasons
var $window = $(window);
$window.on('scroll', function(){
$els.each(function(){ // Iterate over all skillbars
var $this = $(this);
if($window.scrollTop() > $this.offset().top - $window.height()){ // Check if it's in viewport
$this.find('.skillbar-bar').css({'width' : $this.attr('data-percent')}); // Update the view with percentage
}
});
});
});
}(jQuery));
.skillbar{
margin-top: 1000px;
margin-bottom: 400px;
position: relative
}
.skillbar-bar{
transition: width 4s;
position: absolute;
height: 20px;
}
.skill-bar-percent{
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Scroll down 1000px :)
<div class="skillbar clearfix " data-percent="70%">
<div class="skillbar-title">
<span>Illustrator</span></div>
<div class="skillbar-bar" style="background: #FF704D; width: 20%"></div>
<div class="skill-bar-percent">70%</div>
</div>
This might work for you.
var el = $('.yourElement'),
offset = el.offset(),
scrollTop = $(window).scrollTop();
//Check for scroll position
if ((scrollTop > offset.top)) {
// Code..
}

jquery drag image

i want to make a draggable image in jquery.
first of all my experience with jquery is 0. having said that let me describe what i want to achieve. i have fixed width/height div. and the image contained inside the div is large in size. so i want the image to be draggable inside that div so that the user can see the entire image.
can someone help. pls be a little elaborate about the procedure considering my jquery fluency.
You can use the following;
$(function() {
$("#draggable").draggable();
});
.container {
margin-top: 50px;
cursor: move;
}
#screen {
overflow: hidden;
width: 200px;
height: 200px;
clear: both;
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="container">
<div id="screen">
<img src="https://picsum.photos/200/200" class="drag-image" id="draggable" />
</div>
</div>
You want the jQuery Draggable UI tool. The code for this, as with all jQuery, is very simple:
$(document).ready(function(){
$("#draggable").draggable();
});
Will create a draggable object from a standard html tag (the IMG in your case). And for limiting it's mobility to a specific region, you would look into its containment option.
Update: "What is '#draggable' and 'ready'"?
'#draggable' represents the element that you want to be able to drag. The hash (#) symbol represents an ID. When you add your image tags, may give give it an id like the following:
<img src="myimage.jpg" id="draggable" />
That will make the javascript above make your image draggable, because it has the '#draggable' id that the jQuery is looking for.
'.ready()' is the method that is automagically raised by your browser once the page is finished loading. Developers are encouraged by the jQuery group to place all jQuery code within this method to ensure all of the elements on the page are completely loaded prior to any jQuery code attempts to manipulate them.
to limit to a region for this example, containment is not much of a help.
I have implemented this for vertical only scroll, needs enhancement for horizontal limit:
stop: function(event, ui) {
var helper = ui.helper, pos = ui.position;
var h = -(helper.outerHeight() - $(helper).parent().outerHeight());
if (pos.top >= 0) {
helper.animate({ top: 0 });
} else if (pos.top <= h) {
helper.animate({ top: h });
}
}
$('#dragMe').draggable({ containment: 'body' });
This code will make it posible to drag the div with the ID of dragMe where ever you want inside the body of the document. You can also write a class or id as containment.
$('#dragMe').draggable({ containment: '#container' });
This code will make the div dragMe able to be draggable inside of the id container.
Hope this helps otherwise you should be able to find your answer here http://jqueryui.com/demos/draggable/
Expanding on the answer from PH. this will provide an elastic bounceback whenever the image is dragged to the point the underlying container is exposed:
stop: function(event, ui) {
var helper = ui.helper, pos = ui.position;
var h = -(helper.outerHeight() - $(helper).parent().outerHeight());
var w = -(helper.outerWidth() - $(helper).parent().outerWidth());
if (pos.top <= h) {
helper.animate({ top: h });
} else if (pos.top > 0) {
helper.animate({ top: 0 });
}
if (pos.left <= w) {
helper.animate({ left: w });
} else if (pos.left > 0) {
helper.animate({ left: 0 });
}
}

Categories

Resources