Add class depending on top-position value - javascript

I have tooltips set on top of an image. When the user clicks one of these tooltips a content opens to reveal some info.
I'd like to slide open the content up or down, depending where the tooltip is positioned (absolute). So, I'm trying to get the "top"-value and if it's larger than 50, add a class and sort out the rest with CSS.
The problem is I'm always just getting the "top"-value of the first element. Now I tried to add an each function, which leaves me with what seems to be the average value of all the tooltips' top positions?
$( ".tooltip" ).each(function() {
var toppos = $(".tooltip").css("top");
if ( parseInt(toppos) >= 50 ) {
$(this).addClass('higher');
}
});
I'm either using each wrong, or each is not what I should be going for here...

Target the current tooltip instead of all tooltips:
$( ".tooltip" ).each(function() {
var toppos = $(this).css("top");// Use $(this) instead of $('.tooltip')
if ( parseInt(toppos) >= 50 ) {
$(this).addClass('higher');
}
});
You may also try offset().top instead of css('top'):
var toppos = $(this).offset().top;

Related

Find div closest to the bottom of the page

I am working on a project and I have an array of elements that are displayed one under each other.
When I press an arrow, I want to find the div closest to the bottom and scroll up to the top of that div.
This is what I have when I click the arrow:
$(".my-elements").each(function(i){
var divTopPosition = $(this).offset().top;
var scrollTop = $(window).scrollTop();
var difference = -Math.abs(scrollTop - divTopPosition);
if(/* this is the div closest to the bottom */)
{
$("body").animate({scrollTop: difference}, 2000);
return false;
}
});
if you know parent, you can use this selector:
$( "<parent>:last-child" )

How to dynamically change the position of an absolute tooltip base on the target element

I am trying to make a tooltip which basically shows a table (in my example below I used a large amount of text).
However I've wanted to change the position of the tooltip when you hover on the target element that is nearly at the corner of the screen.
Here is the Fiddle
$("strong").on("mouseover", function(){
var $this = $(this),
strongText = $this.text();
$tooltipContainer.show();
$tooltipContainer.append('<span>'+ strongText + '</span>');
}).on("mousemove", function(mousePos){...
You can change your mousemove code a little to update top position if overlap is there like below. Check demo - Fiddle
on("mousemove", function(mousePos){
var overlap = mousePos.pageY + posSrollY + $tooltipContainer.height() - $(window).height() - $(window).scrollTop();
$tooltipContainer.css({
left: mousePos.pageX,
top: mousePos.pageY + posSrollY - ( overlap > 0 && overlap )
});
})

Making nav bar effects using scroll AND click in jQuery

I want a nav to highlight (or something similar) once a user clicks on it AND when a user scrolls to the corresponding section.
However, on my computer when one clicks on any of the nav events after3, only nav event 3 changes. I'm guessing this is because after one clicks on 4 or 5, the scroll bar is already at the bottom of the page, so 4 and 5 never reach the top. The only div at the top is post 3, so my code highlights nav event 3 and ignores the click.
Is there any way I can fix this? Ive tried if statements (only highlight nav event if it's at the top AND the scrollbar isn't at the bottom or the top isn't the last item).
Here is a more accurate fiddle, using a fix below showing what I am talking about. The fix now highlights on scroll, but if you click option 5, it will not highlight.
$('.option').children('a').click(function() {
$('.option').css('background-color', '#CCCCCC;');
$(this).css('background-color', 'red');
var postId = $($(this).attr('href'));
var postLocation = postId.offset().top;
$(window).scrollTop(postLocation);
});
$(window).scroll(function() {
var scrollBar = $(this).scrollTop();
var allPosts = [];
var post = $('.content').offset();
var lastPost = allPosts.legnth-1
var windowHeight = $(window).height();
var bottomScroll = windowHeight-scrollBar;
$(".content").each(function(){
allPosts.push($(this).attr('id'));
});
i = 0;
for(i in allPosts){
var currentPost = "#"+allPosts[i];
var postPosition = $(currentPost).offset().top;
if (scrollBar >= postPosition){
$('.option').css('background-color', '#CCCCCC');
$('#nav'+allPosts[i]).css('background-color', 'red');
};
};
});
I think you've overdone your scroll() handler, to keep it simple you just needs to check if the scrollbar/scrollTop reaches the '.contents' offset top value but should not be greater than its offset().top plus its height().
$(window).scroll(function () {
var scrollBar = $(this).scrollTop();
$(".content").each(function (index) {
var elTop = $(this).offset().top;
var elHeight = $(this).height();
if (scrollBar >= elTop - 5 && scrollBar < elTop + elHeight) {
/* $(this) '.content' is the active on the vewport,
get its index to target the corresponding navigation '.option',
like this - $('.Nav li').eq(index)
*/
}
});
});
And you actually don't need to set $(window).scrollTop(postLocation); because of the default <a> tag anchoring on click, you can omit that one and it will work fine. However if you are looking to animate you need first to prevent this default behavior:
$('.option').children('a').click(function (e) {
e.preventDefault();
var postId = $($(this).attr('href'));
var postLocation = postId.offset().top;
$('html, body').animate({scrollTop:postLocation},'slow');
});
See the demo.
What you are trying to implement from scratch, although commendable, has already been done by the nice folks at Bootstrap. It is called a Scrollspy and all you need to do to implement it is include Bootstrap js and css (you also need jquery but you already have that) and make some minor changes to your html.
Scrollspy implementation steps.
And here is a demonstration. Notice only one line of js. :D
$('body').scrollspy({ target: '.navbar-example' });

How to align td text to the top of visible part of cell?

My table consists of two column: name of object and object. Name is just one word. Object can occupy several screens. I want to hold name on top of visible part of its cell. In this case when user scrolls page down he can see name of the object until the object is hidden. How can I do this? Are there plugins to do so?
It's only a couple lines of jQuery. http://jsfiddle.net/VuRvs/
Attach a handler to the window scroll event, find your "sticky" heading, position them based on the current scroll position make sure they stay inside of their parent element (the TD).
$(window).on("scroll", function() {
var y = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
$(".sticky").each(function() {
var elm = $(this);
var td = elm.parent("td");
var tdTop = td.offset().top;
var tdBot = tdTop + td.height() - elm.outerHeight();
if(y <= tdBot && y >= tdTop) {
// set a placeholder
if(td.children().length == 1)
td.append(elm.clone().removeClass("sticky").css("visibility", "hidden"));
elm.css("position", "absolute");
elm.css("top", y + "px");
}
});
});
What you are describing, is a persistant header, or a freeze pane like Excel.
Check this link, it's nicelly explained.

Getting Coordinates of an element on page scroll

I am having this problem where i have a set of 6 UL's having a common class x.Each of them consist of a specific section of the page.Now i have 6 menus that are related to each of the section.What i have to do is highlight the menu when its related section is in users view.
For this i thought that may be jQuery position(); or offset(); could have helped but they give the top and left of the element.I also tried using jQuery viewport plugin but apparently view port is big it can show more than one UL at a time hence i cant apply element specific logic here.I am not familliar to this but does anything changes of an element on scrolling?If yes then how to access it?
Please share your views.
Regards
Himanshu Sharma.
Is very easy to do it using jQuery and a dummy fixed HTML block that helps you find the current position of the viewport.
$(window).on("scroll load",function(){
var once = true;
$(".title").each(function(ele, index){
if($(this).offset().top > $("#viewport_helper").offset().top && once){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
once = false;
}
});
})
Check out a working example: http://jsfiddle.net/6c8Az/1/
You could also do something similar with the jQuery plugin, together with the :first selector:
$(window).on("scroll load",function(){
$(".title:in-viewport:first").each(function(){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
});
})
You can get the viewport's width and height via $(document).width() and $(document).height()
You can get how many pixels user scrolls via $(document).scrollTop() and $(document).scrollLeft
Combining 1 and 2, you can calculate where the viewport rectangle is
You can get the rectangle of an element using $(element).offset(), $(element).width() and $(element).height()
So the only thing left to you is to determine whether the viewport's rectangle contains (or interacts) the elements's rectangle
So the whole code may look like:
/**
* Check wether outer contains inner
* You can change this logic to matches what you need
*/
function rectContains(outer, inner) {
return outer.top <= inner.top &&
outer.bottom >= inner.bottom &&
outer.left <= inner.left &&
outer.right >= inner.right;
}
/**
* Use this function to find the menu related to <ul> element
*/
function findRelatedMenu(element) {
return $('#menu-' + element.attr('id'));
}
function whenScroll() {
var doc = $(document);
var elem = $(element);
var viewportRect = {
top: doc.scrollTop(),
left: doc.scrollLeft(),
width: doc.width(),
height: doc.height()
};
viewportRect.bottom = viewportRect.top + viewportRect.height;
viewportRect.right = viewportRect.left + viewportRect.width;
var elements = $('ul.your-class');
for (var i = 0; i < elements.length; i++) {
var elem = $(elements[i]);
var elementRect = {
top: elem.offset().top,
left: elem.offset().left,
width: elem.width(),
height: elem.height()
};
elementRect.bottom = elementRect.top + elementRect.height;
elementRect.right = elementRect.left + elementRect.width;
if (rectContains(viewportRect, elementRect)) {
findRelatedMenu(elem).addClass('highlight');
}
}
}
$(window).on('scroll', whenScroll);
Let's see if i understood well. You have a page long enough to scroll, and there is an element that when it appears in the viewport, you wanna do something with it. So the only event that's is triggered for sure on the time the element gets in the viewport is the 'scroll'. So if the element is on the page and the scroll is on the viewport, what you need to do is bind an action to the scroll event to check if the element is in the view each time the event is trigger. Pretty much like this:
$(window).scroll(function() {
check_element_position();
});
Now, in order for you to know if the element is in the viewport, you need 3 things. The offset top of that element, the size of the viewport and the scroll top of the window. Should pretty much look like this:
function check_element_position() {
var win = $(window);
var window_height = win.height();
var element = $(your_element);
var elem_offset_top = element.offset().top;
var elem_height = element.height();
var win_scroll = win.scrollTop();
var pseudo_offset = (elem_offset_top - win_scroll);
if (pseudo_offset < window_height && pseudo_offset >= 0) {
// element in view
}
else {
// elem not in view
}
}
Here, (elem_offset_top - win_scroll) represent the element position if there was no scroll. Like this, you just have to check if the element offset top is higher then the window viewport to see if it's in view or not.
Finally, you could be more precise on you calculations by adding the element height (variable already in there) because the code i just did will fire the event even if the element is visible by only 1 pixels.
Note: I just did that in five minutes so you might have to fix some of this, but this gives you a pretty darn good idea of what's going on ;)
Feel free to comment and ask questions

Categories

Resources