I am working on a tooltip plugin with the following options:
Mouse = True|False. Tooltip position relative to Mouse or Element;
Static = True|False. Follow mouse when option Mouse = true.
I have a JSFiddle example in: http://jsfiddle.net/mdmoura/RPUX6/
THE PROBLEM:
When I place the mouse over the last tooltips of the list the position is wrong.
This happens every time I have scrolled the page ... I have no idea why.
The part of the code which sets the position is:
$(this).each(function (e) {
// SOME CODE
$this.mouseenter(function (e) {
var $tooltip =
$("<div>")
.attr("class", options.class)
.html(options.content !== '' ? (typeof options.content === 'string' ? options.content : options.content($this, $tooltip)) : tooltip.title)
.appendTo('body');
$this.attr('title', '');
var position = [0, 0];
if (options.mouse) {
position = [e.clientX + options.offset[0], e.clientY + options.offset[1]];
} else {
var coordinates = $this[0].getBoundingClientRect();
position = [
(function () {
if (options.offset[0] < 0)
return coordinates.left - Math.abs(options.offset[0]) - $tooltip.outerWidth();
else if (options.offset[0] === 0)
return coordinates.left - (($tooltip.outerWidth() - $this.outerWidth()) / 2);
else
return coordinates.left + $this.outerWidth() + options.offset[0];
})(),
(function () {
if (options.offset[1] < 0)
return coordinates.top - Math.abs(options.offset[1]) - $tooltip.outerHeight();
else if (options.offset[1] === 0)
return coordinates.top - (($tooltip.outerHeight() - $this.outerHeight()) / 2);
else
return coordinates.top + $this.outerHeight() + options.offset[1];
})()
];
}
$tooltip.css({ left: position[0] + 'px', top: position[1] + 'px' });
You can also see the code and the demo in http://jsfiddle.net/mdmoura/RPUX6/.
Thank You!
You need to account for scrollTop and scrollLeft of the window.
Basic idea:
var win = $(window);
$tooltip.css( {
left: position[0] + win.scrollLeft() + 'px',
top: position[1] + win.scrollTop() + 'px'
});
Add scrollTop by
document.body.scrollTop
And you will be good to go..
In your code make these changes
function () {
if (options.offset[1] < 0)
return coordinates.top - Math.abs(options.offset[1]) - $tooltip.outerHeight()+document.body.scrollTop;
else if (options.offset[1] === 0)
return coordinates.top - (($tooltip.outerHeight() - $this.outerHeight()) / 2)+document.body.scrollTop;
else
return coordinates.top + $this.outerHeight() + options.offset[1]+document.body.scrollTop;
})
Related
I am currently working on a Parallax Effect using jQuery. For that I am using a JS Class.
When I was first testing the code I thought everything was working fine. However I just found out that the parallax_container divs are behaving differently based on how fast the user is scolling. I am pretty sure that this happens because the window.scroll function just is not accurate enough to use it in this case. Thats why I changed the code and added the setInterval function the change the scrollTop Variable as often as possible, but this didn't change my problem.
Did I take the wrong approach, or is there a clever way to get the scroll Postion in a "linear" way no matter how fast the user scrolls ?
I added the part of the code that seems important to me, but i can post more if needed.
Codepen Example
jQuery(document).ready(function () {
jQuery("." + elemCssClass).addClass("parallax_container");
jQuery("." + elemCssClass).css("position", "relative");
jQuery(".parallax_container").each(function (index) {
jQuery(this).attr('id', 'parallax_' + (index + 1));
});
var lastScrollTop = 0;
var scrollDirect;
var initialTop = parseInt(jQuery("." + elemCssClass).css("top"));
var scr;
setInterval(function () {
scr = jQuery(window).scrollTop()
}, 0.00005);
jQuery(window).scroll(function () {
if (mediaQuery.matches) {
return;
}
if (scr > lastScrollTop) {
scrollDirect = "down"
} else {
scrollDirect = "up"
}
lastScrollTop = st;
var elem = document.querySelector("." + elemParentCssClass);
var visible = ctrl.isInViewport(elem);
if (visible) {
if (scr === 0) {
jQuery("." + elemCssClass).css('top', initialTop);
}
var diff = scr - initY;
var ratio = jQuery("." + elemCssClass).css('top');
// Hier wird der Speed der im VC eingestellt ist angewendet.
// Es wird gechekct ob nach oben oder unten gescrolled wird und entweder + oder - gerechnet
if (scrollDirect === "up") {
jQuery("." + elemCssClass).css({
top: "+=" + elemSpeed + 'px'
});
}
if (scrollDirect === "down") {
jQuery("." + elemCssClass).css({
top: "-=" + elemSpeed + 'px'
});
}
}
else {
jQuery("." + elemCssClass).css('top', 0);
}
var initY = jQuery("." + elemParentCssClass).offset().top
var height = jQuery("." + elemParentCssClass).height()
var endY = initY + jQuery("." + elemParentCssClass).height()
}) //window.scroll()
}) // document.ready()
I have image I am scrolling within a div.
It make sure the image is visible I am using
var isVisible = (
threshold.top >= -39 &&
threshold.bottom <= (window.innerHeight || document.documentElement.clientHeight)
);
What I am trying to do now is make sure that once the element is visible it is able to completely finish scrolling before going out of the view port.
I am thinking I can do this by effecting the speed value based on the the distance of the element from the top on the window. But I am having a very hard time doing this.
I am using .getBoundingClientRect() to get the distance the element is from the top of the viewport:
var threshold = document.getElementById('page-feature').getBoundingClientRect();
var thresholdY = threshold.top;
Below is my code so far:
function scrollImageInViewport() {
var threshold = document.getElementById('page-feature').getBoundingClientRect();
var thresholdY = threshold.top;
var isVisible = (
threshold.top >= -39 &&
threshold.bottom <= (window.innerHeight || document.documentElement.clientHeight)
);
if (isVisible && window.innerWidth > 550) {
scrollDir(thresholdY);
}
}
function scrollUp(thresholdY) {
if (thresholdCounter < maxScrollNegative) {
return;
} else {
pageScroll.setAttribute('style', '-webkit-transform:translate3d(0,' + (--thresholdCounter *speed) + 'px,0); -ms-transform:translate3d(0,' + (--thresholdCounter *speed) + 'px,0); transform:translate3d(0,' + (--thresholdCounter *speed) + 'px,0);');
}
};
function scrollDown(thresholdY) {
if (thresholdCounter > maxScrollPositive) {
return;
} else {
pageScroll.setAttribute('style', '-webkit-transform:translate3d(0,' + (++thresholdCounter *speed) + 'px,0); -ms-transform:translate3d(0,' + (++thresholdCounter *speed) + 'px,0); transform:translate3d(0,' + (++thresholdCounter *speed) + 'px,0);');
}
};
function scrollToTop(){
initScroll();
pageScroll.setAttribute('style', 'transform:translate3d(0,0,0);');
thresholdCounter = 0;
};
function scrollDir(thresholdY) {
var scroll = window.scrollY;
if(scroll > position) {
distanceFromTop(thresholdY);
scrollUp(thresholdY);
} else if (scroll < position ){
scrollDown(thresholdY);
}
position = scroll;
};
function distanceFromTop(thresholdY) {
if (thresholdY > 0) {
`enter code here`//set speed as distance from top /px of not shown content
speed = (scrollImageHeight - scrollVisibleHeight) / thresholdY;
}
};
function initScroll(){
position = window.scrollY;
pageScroll = document.getElementById('page-scroll');
scrollImageHeight = pageScroll.offsetHeight; //total height of scroll image
pagePanel = document.getElementById("pagePanel");
pageStyle = window.getComputedStyle(pagePanel,"");
size = pageStyle.getPropertyValue("height");
scrollVisibleHeight = parseInt(size, 10);//visible height of scroll image
scrollImageEnd = scrollImageHeight - scrollVisibleHeight;
maxScrollNegative = -scrollImageEnd / speed;
}
var speed;
var thresholdCounter = 0;
var maxScrollPositive = 0;
var position,
pageScroll,
scrollImageHeight,
pagePanel,
pageStyle,
size,
scrollVisibleHeight,
scrollImageEnd,
maxScrollNegative;
window.addEventListener('resize', scrollToTop);
document.addEventListener('scroll', scrollImageInViewport);
window.addEventListener('load', initScroll);
This is what I ended up with:
var featurePage = document.getElementById('page-feature')
var pageScroll = document.getElementById('page-scroll');
var startP, // where animation needs to begin
endP, // where animation needs to end
diff; // visible element size
function getElementOffset(){ //init
var de = document.documentElement;
var box = featurePage.getBoundingClientRect();
var top = box.top + window.pageYOffset - de.clientTop;
var bottom = box.bottom + window.pageYOffset - de.clientTop;
var winHight = window.innerHeight;
diff = bottom - top;
var elPadding = (winHight - diff);
startP = top - elPadding;
endP = bottom - elPadding;
scrollImage()
}
function scrollImage(){
var scrollImageHeight = pageScroll.offsetHeight;
var scrollPos = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
var s1 = scrollPos - startP;
var realPos = -s1/diff;
var lengthLeft = scrollImageHeight - (diff)
if ( realPos < 0.09 && realPos > -1){
pageScroll.setAttribute('style', '-webkit-transform:translate3d(0,' + (realPos * lengthLeft) + 'px,0); -ms-transform:translate3d(0,' + (realPos *lengthLeft) + 'px,0); transform:translate3d(0,' + (realPos *lengthLeft) + 'px,0);');
}
}
window.addEventListener('resize', getElementOffset);
document.addEventListener('scroll', getElementOffset);
I have the following code and I am trying to turn off the function when window resize is run, currently it just keeps running on window.resize.
function headerParallax(x) {
if (x ==="true"){
$(window).scroll(function() {
// Store scrollTop in variable
var scrollPos = $(window).scrollTop();
// var viewportHeight = $(window).height();
console.log(scrollPos + 'bgbottle1');
var bouncePos = ((-1 * (scrollPos - 75) * 1.5) + scrollPos).toFixed(2);
var bouncePos1 = ((-1 * (scrollPos - 150) * 1.25) + scrollPos).toFixed(2);
$(".bottle1").css({ 'background-position': "right " + bouncePos + 'px'});
if (scrollPos > 150){
$(".bottle2").css({ 'background-position': "left " + bouncePos1 + 'px'});
}
});
}else if(x === "false"){
alert("no");
}
}
$(window).resize(function(){
if ($(window).width() < 1200){
window.requestAnimationFrame(headerParallax("false"));
}
});
if ($(window).width() > 1200){
window.requestAnimationFrame(headerParallax("true"));
}
You can try something like this:
var _preflag = -1;
var _unbindScroll = function(){};
// it will be fired only once (when flag is changed)
function headerParallax(flag){
if (flag === _preflag){
return;
}
_preflag = flag;
if (flag){
// TODO adjust the UI for true
window.requestAnimationFrame(theCalculatedValue);
_unbindScroll(); // It's duplicate work to unbind scroll here, but there's no harm calling it :)
$(window).on('scroll', _onscroll);
// update the ubind scroll so that anyone can ubind it safely
_unbindScroll = function(){
$(window).off('scroll', _onscroll);
_unbindScroll = function(){};
};
} else {
// TODO adjust the UI for false
window.requestAnimationFrame(theCalculatedValue);
_unbindScroll(); // unbind scrolling, this is what you want, right?
}
function _onscroll(){
// TODO
}
}
function resize(){
// this will be fired multipe times, need to check it in sub functions to take it once
headerParallax($(window).width() < 1200);
}
$(window).resize(resize);
resize();
In our site www.mydubaitrip.com I have a script that resizes the background image base on the browser width. My problem is whenever I try to press Ctrl+F5 or if I navigate to hotel page and back to home page, the background image doesn't resize correctly and my layout looks messed up. But if I try to press F5 again it will now adjust accordingly. I cannot figure out what is the problem.
Here's the script that I used.
var minWidth = 1024;
var minHeight = 844;
var winRatio = new Array();
var imgReady = new Array();
var orientation = 90;
var debounceId;
var isiPad = navigator.userAgent.match(/iPad/i) != null;
if (isiPad) {
var minWidth = 980;
}
var readyToRotate = false;
var readyToResize = true;
var miniContentWrapperHeight = 444;
// BACKGROUND TRANSITION
var theTimer;
var currBanner = -1;
var totalBanner = 0;
var timeWaiting = parseInt(500);
var timeTextTransIn = parseInt(1000);
var timeTextTransOut = parseInt(1000);
var timeTransCross = parseInt(2000);
var timeTransInit = parseInt(0);
var timeTransInterval = parseInt(7000);
var transitioning = false;
$("#homePageMainPanel").css({ "backgroundColor": "black" });
var hybridMode = true;
if (($.browser.mozilla && $.browser.version == "5.0") ||
$.browser.msie && $.browser.version == "9.0") {
//hybridMode = false;
}
//$("html").css({ "overflow": "hidden" });
function updateOrientation() {
// scroll and hide address bar for iPhone landscape
setTimeout(function() { window.scrollTo(0, 1) }, timeWaiting);
if (window.orientation != undefined)
orientation = Math.abs(window.orientation);
resizeBackground();
}
$(window).load(function() {
resizeBackground();
if (!($.browser.msie && $.browser.version == "6.0")) {
var lang = $('meta[name="language"]').attr("content");
if ((lang == "ar") || (lang == "ir")) {
$(".carouselShadow").css('background', 'url(/media/images/fg_ar_text_bg.png) no-repeat');
}
else {
$(".carouselShadow").css('background', 'url(/media/images/fg_text_bg.png) no-repeat');
}
}
});
$(document).ready(function() {
if (typeof BackgroundInfo != 'undefined' && BackgroundInfo.length > 0) {
$("#carousel").append("<img src=\"" + BackgroundInfo[0].Src + "\" alt=\"" + BackgroundInfo[0].Alt + "\" />");
}
if ($(window).height() > $(document).height() - $("#bottomLayer").height()) {
$("#bottomLayer").css({ 'position': 'absolute', "top": parseInt($(window).height() - $("#bottomLayer").height()) });
$("#carousel img").height($(window).height() - $("#bottomLayer").height());
//alert($("#bottomLayer").offset().bottom);
$(".bookPanel").css({ 'position': 'relative', "bottom": parseInt($(".bookPanel").height() - $("#carousel").height() + 28) });
$(".carouselShadow").css({ 'position': 'relative', "bottom": parseInt($(".carouselShadow").height() - $("#carousel").height()+20) });
setTimeout(function() {
$("#bottomLayer").css({ "position": "relative", "top": parseInt($(window).height() - $("#bottomLayer").height()) });
}, 500);
setTimeout(function() {
$(".bookPanel").css({ "position": "relative", "bottom": parseInt($(".bookPanel").height() - $("#carousel").height() + 28) });
}, 500);
setTimeout(function() {
$(".carouselShadow").css({ "position": "relative", "bottom": parseInt($(".carouselShadow").height() - $("#carousel").height()+20) });
}, 500);
}
//in case the navigation height is longer than prefixed minheight, adjust minheight=navigation height
var homepageHeight = $("#homePageMainPanel").height() + $("#bottomLayer").height();
if (homepageHeight > minHeight)
minHeight = homepageHeight;
//this is only for mobile safari on ipad/iphone
window.onorientationchange = function() {
window.scrollTo(0, 1); // to prevent jumpy and blinky page transitions
updateOrientation();
}
$(window)
.resize(function() {
if (readyToResize) {
clearTimeout(debounceId);
debounceId = setTimeout(resizeEvent, 500);
}
})
.load(function() {
// scroll and hide address bar for iPhone landscape
setTimeout(function() { window.scrollTo(0, 1) }, timeWaiting);
});
initRotateBanner();
});
var winWidth = $(window).width();
var winHeight = $(window).height();
var winNewWidth = -1;
var winNewHeight = -1;
function resizeEvent() {
// JL: Hack to prevent IE 7,8 to have infinite loop when window.resize event
winNewWidth = $(window).width();
winNewHeight = $(window).height();
if (winWidth != winNewWidth || winHeight != winNewHeight) {
clearTimeout(debounceId);
resizeBackground();
}
winWidth = winNewWidth;
winHeight = winNewHeight;
}
function initRotateBanner() {
$('#carousel img').eq(0).one('load', function() {
if (readyToRotate = true) {
if (typeof BackgroundInfo != 'undefined' && BackgroundInfo.length > 0) {
$.each(BackgroundInfo, function(i, v) {
if (i > 0) {
$("#carousel").append("<img src=\"" + BackgroundInfo[i].Src + "\" alt=\"" + BackgroundInfo[i].Alt + "\" />");
}
});
initBackgroundImageReady();
}
imgReady[0] = true;
window.setTimeout("rotateBanner('init')", timeTransInit);
}
//$('#background').children("img").show();
//$('#background').children("img").css({ 'opacity': '1' });
resizeBackground();
}).each(function() {
// $(this).load();
});
/// assign each background text accordingly
var index = 0;
$('.carouselContentContainer').each(function() {
$(this).attr('id', 'text_box_' + index);
index++;
});
}
function initBackgroundImageReady() {
$('#carousel').children("img").each(function() {
//assign each background id accordingly
$(this).attr('id', 'img_box_' + totalBanner);
// flag correspondingly when bg images is loaded
imgReady[totalBanner] = false;
$(this).one('load', function(event) {
var id = $(this).attr('id');
var idArr = new Array();
idArr = id.split('_');
var index = idArr[idArr.length - 1];
//console.log(index + "loaded");
imgReady[index] = true;
resizeBackground();
});
//$(this).load();
totalBanner++;
});
}
function resizeBackground() {
readyToResize = false;
$('html').css({ 'overflow': 'hidden' });
$("#carousel").children("img").each(function() {
var oriWidth = $(this).width('');
var oriHeight = $(this).height('');
var bgWidth = $(window).width();
if (bgWidth < minWidth)
bgWidth = minWidth;
var bgHeight = bgWidth / oriWidth * oriHeight;
if (oriHeight < bgWrapperHeight)
bgWrapperHeight = oriHeight;
$(this).css({ 'position': 'absolute', 'width': bgWidth, 'height': bgHeight });
});
//start with window height & width
var bgWrapperHeight = $(window).height();
var bgWrapperWidth = $(window).width();
// if vertical scrollbar exists, accommodate the scrollbar width (16px)
if ($.browser.webkit == true) {
////$("#log").prepend(document.body.scrollHeight + " : " + document.body.clientHeight + "<br />");
if (document.body.scrollHeight < document.body.clientHeight)
bgWrapperWidth = $(window).width() - 16; // accomdate the scroll bar width (16px)
else
bgWrapperWidth = $(window).width();
}
else {
////$("#log").prepend($(document).height() + " : " + $(window).height() + "<br />");
if ($(window).height() < $(document).height())
bgWrapperWidth = $(window).width() - 17; //
else
bgWrapperWidth = $(window).width();
}
// for screen size > min height (hp-navigation) but < min background image size, adjust to fit without scroller
if (bgWrapperHeight + $('#bottomLayer').height() > $(window).height()) {
bgWrapperHeight = $(window).height() - $('#bottomLayer').height();
}
//wrapper height should not go lower than navigation height
if (bgWrapperHeight < $('#bookPanel').height())
bgWrapperHeight = $('#bookPanel').height();
//wrapper width should not go lower than min width
if (bgWrapperWidth < minWidth)
bgWrapperWidth = minWidth;
// set #hp-content-wrapper height
$('#homePageMainPanel').css({ 'height': bgWrapperHeight, 'width': bgWrapperWidth });
$('#carousel').css({ 'height': bgWrapperHeight, 'width': bgWrapperWidth });
$('#bottomLayer').css({ 'width': bgWrapperWidth });
$('html').css({ 'overflow': 'auto' });
//TODO: better way to center align bg image!
//var nn = 0;
// vertically middle align background
$("#carousel").children("img").each(function() {
// IF document height (minus footer height) is more than background image,
// Expand Background Image Vertically!
if (($(document).height() - $('#bottomLayer').height()) >= $(this).height()) {
var newHeight = $(document).height() - $('#bottomLayer').height();
var newWidth = Math.round((newHeight / $(this).height()) * $(this).width());
var offsetX = ((bgWrapperWidth - newWidth) / 2);
$(this).css({ 'position': 'absolute', 'left': offsetX, 'width': newWidth, 'height': newHeight });
// $("#log").prepend($(document).height() + " : " + $('#footer').height() + "<br />");
// Reset back the image top position to 0;
$(this).css({ 'position': 'absolute', 'top': 0 });
}
else { //TODO: figure out what contributes to offset??
var newWidth = $(document).width();
var newHeight = Math.round((newWidth / $(this).width()) * $(this).height());
var offsetX = ((bgWrapperWidth - newWidth) / 2);
// Reset back the image left position to 0;
$(this).css({ 'position': 'absolute', 'left': 0, 'width': newWidth, 'height': newHeight });
// $(this).css({ 'position': 'absolute', 'left': 0, 'width': '100%', 'height': '' });
if (bgWrapperHeight > $('#bottomLayer').position().top) {
var offsetY = ((bgWrapperHeight - $(this).height()) / 2);
$(this).css({ 'top': offsetY });
}
else {
var offsetY = (($('#bottomLayer').position().top - $(this).height()) / 2);
$(this).css({ 'top': offsetY });
}
}
});
//$(".bookPanel").css({ 'position': 'absolute', "top": parseInt($("#carousel").height()) });
$('#bottomLayer').css({ 'position': 'absolute', 'top': $("#carousel").height() });
$(".bookPanel").css({ "bottom": parseInt($(".bookPanel").height() - $("#carousel").height() + 28) });
$(".carouselShadow").css({ 'position': 'relative', "bottom": parseInt($(".carouselShadow").height() - $("#carousel").height()) });
//when having vertical scroll bar
//known issue: does not work for IE screen onresize, only works onload
if ($(window).height() != $(document).height()) {
//$("#roomreservations").html($(window).width() + ":" + $(document).width() + ":" + minWidth);
if ($(document).width() == minWidth && ($(window).width() != $(document).width())) {
//show horizontal scrollbar (by default)
}
else {
//otherwise hide horizontal scrollbar
$('html').css({ 'overflow-x': 'hidden' });
}
}
setTimeout('checkWidth(' + bgWrapperWidth + ')', 500);
readyToResize = true;
}
function checkWidth(bgWrapperWidth) {
$('#homePageMainPanel').width('100%');
$('#bottomLayer').width('100%');
$('#carousel').width($(document).width());
$("#carousel").children("img").each(function() {
if (($(document).height() - $('#bottomLayer').height()) >= $(this).height()) {
// Resize the image height to $("#background") height, as the image should fill from the top till the footer
$(this).css({ 'width': (($("#carousel").height() / $(this).height()) * $(this).width()), 'height': $("#carousel").height() });
}
});
}
function positionFooter() {
return null;
var footerPosition = $('#carousel').height() - $('#bottomLayer').height() + 1;
if ($('#carousel').height() < minHeight) {
footerPosition = minHeight - $('#carousel').height() + 1;
}
$('#carousel').css({ 'position': 'absolute', 'top': footerPosition });
$('html').css({ 'overflow': 'auto' });
$("#homePageMainPanel").css({ 'height': $('#carousel').height() });
}
var waitingTimeout;
function rotateBanner(param) {
var nextBanner = 0;
nextBanner = parseInt(currBanner) + 1;
if (nextBanner >= totalBanner) { nextBanner = 0; }
// wait until next bg image is fully loaded
if (imgReady[nextBanner] != true) {
waitingTimeout = window.setTimeout("rotateBanner('waiting')", timeWaiting);
return false;
}
clearTimeout(waitingTimeout);
transitionStart();
// cross fade
if (currBanner > -1) {
if (hybridMode) {
window.setTimeout("changeClass('quality','speed')", 500);
window.setTimeout("changeClass('speed','quality')", 1500);
}
fadeBgImg('#text_box_' + String(currBanner), 0, 500);
window.setTimeout("fadeBgImg('#img_box_" + String(currBanner) + "',0," + 1000 + ")", 500);
window.setTimeout("fadeBgImg('#img_box_" + String(nextBanner) + "',1," + 1000 + ")", 500);
window.setTimeout("fadeBgImg('#text_box_" + String(nextBanner) + "',1," + 1000 + ",true)", 1500);
window.setTimeout("transitionComplete()", 2500);
}
else {
if (hybridMode) {
changeClass('quality', 'speed');
window.setTimeout("changeClass('speed','quality')", 1000);
}
fadeBgImg("#img_box_" + String(nextBanner), 1, 1000);
window.setTimeout("fadeBgImg('#text_box_" + String(nextBanner) + "',1," + 1000 + ",true)", 1000);
window.setTimeout("showShadow()", 1000);
window.setTimeout("transitionComplete()", 2000);
}
currBanner = nextBanner;
}
function nextPaging(nextBanner) {
$('#carousel #paging ul li').each(function() {
if ($(this).attr('id') == 'paging_item_' + nextBanner) {
$(this).addClass("active");
}
else {
$(this).removeClass("active");
}
});
}
function changeClass(from, to) {
$("#carousel").removeClass(from).addClass(to);
}
function fadeBgImg(id, inout, duration, triggerTimer) {
$(id).stop(true, true);
if (inout == 1) {
$(id).fadeIn(duration);
}
else {
$(id).fadeOut(duration);
}
//$(id).animate({ 'opacity': inout }, duration);
if (triggerTimer == true) {
window.clearTimeout(theTimer);
if (totalBanner > 1) {
theTimer = window.setTimeout("rotateBanner()", timeTransInit + timeTransInterval);
}
}
}
function transitionStart() {
transitioning = true;
}
function transitionComplete() {
transitioning = false;
}
function Timer(callback, delay) {
var timerId, start, remaining = delay;
this.pause = function() {
window.clearTimeout(timerId);
remaining -= new Date() - start;
};
this.resume = function() {
start = new Date();
timerId = window.setTimeout(callback, remaining);
};
this.resume();
}
var waitingTimeout2;
function onBlur() {
//theTimer.pause();
clearTimeout(waitingTimeout2);
if (transitioning) {
waitingTimeout2 = window.setTimeout("onBlur()", timeWaiting);
return false;
}
window.clearTimeout(theTimer);
};
function onFocus() {
//theTimer.resume();
if (totalBanner > 1) {
window.clearTimeout(theTimer);
theTimer = window.setTimeout("rotateBanner()", timeTransInit + timeTransInterval);
}
};
if (/*#cc_on!#*/false) { // check for Internet Explorer
document.onfocusin = onFocus;
document.onfocusout = onBlur;
readyToRotate = true;
} else {
window.onfocus = onFocus;
window.onblur = onBlur;
readyToRotate = true;
}
function showShadow() {
// Do not fade in shadow png IE8 and below
if ($.browser.msie && parseInt($.browser.version, 10) <= 8) {
$(".carouselShadow").delay(1000).show();
}
else {
$(".carouselShadow").delay(1000).fadeIn();
}
}
While it is great that you've built this yourself, someone has already solved all your problems with Backstretch.
how to determine, using jquery, if the element is visible on the current page view. I'd like to add a comment functionality, which works like in facebook, where you only scroll to element if it's not currently visible. By visible, I mean that it is not in the current page view, but you can scroll to the element.
Live Demo
Basically you just check the position of the element to see if its within the windows viewport.
function checkIfInView(element){
var offset = element.offset().top - $(window).scrollTop();
if(offset > window.innerHeight){
// Not in view so scroll to it
$('html,body').animate({scrollTop: offset}, 1000);
return false;
}
return true;
}
Improving Loktar's answer, fixing the following:
Scroll up
Scroll to a display:none element (like hidden div's etc)
function scrollToView(element){
var offset = element.offset().top;
if(!element.is(":visible")) {
element.css({"visibility":"hidden"}).show();
var offset = element.offset().top;
element.css({"visibility":"", "display":""});
}
var visible_area_start = $(window).scrollTop();
var visible_area_end = visible_area_start + window.innerHeight;
if(offset < visible_area_start || offset > visible_area_end){
// Not in view so scroll to it
$('html,body').animate({scrollTop: offset - window.innerHeight/3}, 1000);
return false;
}
return true;
}
After trying all these solutions and many more besides, none of them satisfied my requirement for running old web portal software (10 years old) inside IE11 (in some compatibility mode). They all failed to correctly determine if the element was visible. However I found this solution. I hope it helps.
function scrollIntoViewIfOutOfView(el) {
var topOfPage = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
var heightOfPage = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
var elY = 0;
var elH = 0;
if (document.layers) { // NS4
elY = el.y;
elH = el.height;
}
else {
for(var p=el; p&&p.tagName!='BODY'; p=p.offsetParent){
elY += p.offsetTop;
}
elH = el.offsetHeight;
}
if ((topOfPage + heightOfPage) < (elY + elH)) {
el.scrollIntoView(false);
}
else if (elY < topOfPage) {
el.scrollIntoView(true);
}
}
I made a slightly more generic version of digitalPBK's answer that minimally scrolls an element contained within a div or some other container (including the body). You can pass DOM elements or selectors to the function, as long as the element is somehow contained within the parent.
function scrollToView(element, parent) {
element = $(element);
parent = $(parent);
var offset = element.offset().top + parent.scrollTop();
var height = element.innerHeight();
var offset_end = offset + height;
if (!element.is(":visible")) {
element.css({"visibility":"hidden"}).show();
var offset = element.offset().top;
element.css({"visibility":"", "display":""});
}
var visible_area_start = parent.scrollTop();
var visible_area_end = visible_area_start + parent.innerHeight();
if (offset-height < visible_area_start) {
parent.animate({scrollTop: offset-height}, 600);
return false;
} else if (offset_end > visible_area_end) {
parent.animate({scrollTop: parent.scrollTop()+ offset_end - visible_area_end }, 600);
return false;
}
return true;
}
You can take a look at his awesome link from the jQuery Cookbook:
Determining Whether an Element Is Within the Viewport
Test if Element is contained in the Viewport
jQuery(document).ready(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
documentScrollTop = jQuery(document).scrollTop(),
documentScrollLeft = jQuery(document).scrollLeft(),
$myElement = jQuery('#myElement'),
elementOffset = $myElement.offset(),
elementHeight = $myElement.height(),
elementWidth = $myElement.width(),
minTop = documentScrollTop,
maxTop = documentScrollTop + viewportHeight,
minLeft = documentScrollLeft,
maxLeft = documentScrollLeft + viewportWidth;
if (
(elementOffset.top > minTop && elementOffset.top + elementHeight < maxTop) &&
(elementOffset.left > minLeft && elementOffset.left + elementWidth < maxLeft)
) {
alert('entire element is visible');
} else {
alert('entire element is not visible');
}
});
Test how much of the element is visible
jQuery(document).ready(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
documentScrollTop = jQuery(document).scrollTop(),
documentScrollLeft = jQuery(document).scrollLeft(),
$myElement = jQuery('#myElement'),
verticalVisible, horizontalVisible,
elementOffset = $myElement.offset(),
elementHeight = $myElement.height(),
elementWidth = $myElement.width(),
minTop = documentScrollTop,
maxTop = documentScrollTop + viewportHeight,
minLeft = documentScrollLeft,
maxLeft = documentScrollLeft + viewportWidth;
function scrollToPosition(position) {
jQuery('html,body').animate({
scrollTop : position.top,
scrollLeft : position.left
}, 300);
}
if (
((elementOffset.top > minTop && elementOffset.top < maxTop) ||
(elementOffset.top + elementHeight > minTop && elementOffset.top +
elementHeight < maxTop))
&& ((elementOffset.left > minLeft && elementOffset.left < maxLeft) ||
(elementOffset.left + elementWidth > minLeft && elementOffset.left +
elementWidth < maxLeft)))
{
alert('some portion of the element is visible');
if (elementOffset.top >= minTop && elementOffset.top + elementHeight
<= maxTop) {
verticalVisible = elementHeight;
} else if (elementOffset.top < minTop) {
verticalVisible = elementHeight - (minTop - elementOffset.top);
} else {
verticalVisible = maxTop - elementOffset.top;
}
if (elementOffset.left >= minLeft && elementOffset.left + elementWidth
<= maxLeft) {
horizontalVisible = elementWidth;
} else if (elementOffset.left < minLeft) {
horizontalVisible = elementWidth - (minLeft - elementOffset.left);
} else {
horizontalVisible = maxLeft - elementOffset.left;
}
var percentVerticalVisible = (verticalVisible / elementHeight) * 100;
var percentHorizontalVisible = (horizontalVisible / elementWidth) * 100;
if (percentVerticalVisible < 50 || percentHorizontalVisible < 50) {
alert('less than 50% of element visible; scrolling');
scrollToPosition(elementOffset);
} else {
alert('enough of the element is visible that there is no need to scroll');
}
} else {
// element is not visible; scroll to it
alert('element is not visible; scrolling');
scrollToPosition(elementOffset);
}
The following code helped me achieve the result
function scroll_to_element_if_not_inside_view(element){
if($(window).scrollTop() > element.offset().top){
$('html, body').animate( { scrollTop: element.offset().top }, {duration: 400 } );
}
}
Here is the solution I came up with, working both up and down and using only Vanilla Javascript, no jQuery.
function scrollToIfNotVisible(element) {
const rect = element.getBoundingClientRect();
// Eventually an offset corresponding to the height of a fixed navbar for example.
const offset = 70;
let scroll = false;
if (rect.top < offset) {
scroll = true;
}
if (rect.top > window.innerHeight) {
scroll = true;
}
if (scroll) {
window.scrollTo({
top: (window.scrollY + rect.top) - offset,
behavior: 'smooth'
})
}
}
There is a jQuery plugin which allows us to quickly check if a whole element (or also only part of it) is within the browsers visual viewport regardless of the window scroll position. You need to download it from its GitHub repository:
Suppose to have the following HTML and you want to alert when footer is visible:
<section id="container">
<aside id="sidebar">
<p>
Scroll up and down to alert the footer visibility by color:
</p>
<ul>
<li><span class="blue">Blue</span> = footer <u>not visible</u>;</li>
<li><span class="yellow">Yellow</span> = footer <u>visible</u>;</li>
</ul>
<span id="alert"></span>
</aside>
<section id="main_content"></section>
</section>
<footer id="page_footer"></footer>
So, add the plugin before the close of body tag:
<script type="text/javascript" src="js/jquery-1.12.0.min.js"></script>
<script type="text/javascript" src="js/jquery_visible/examples/js/jq.visible.js"></script>
After that you can use it in a simple way like this:
<script type="text/javascript">
jQuery( document ).ready(function ( $ ) {
if ($("footer#page_footer").visible(true, false, "both")) {
$("#main_content").css({"background-color":"#ffeb3b"});
$("span#alert").html("Footer visible");
} else {
$("#main_content").css({"background-color":"#4aafba"});
$("span#alert").html("Footer not visible");
}
$(window).scroll(function() {
if ($("footer#page_footer").visible(true, false, "both")) {
$("#main_content").css({"background-color":"#ffeb3b"});
$("span#alert").html("Footer visible");
} else {
$("#main_content").css({"background-color":"#4aafba"});
$("span#alert").html("Footer not visible");
}
});
});
</script>
Here a demo
No-JQuery version.
The particular case here is where the scroll container is the body (TBODY, table.body) of a TABLE (scrolling independently of THEAD). But it could be adapted to any situation, some simpler.
const row = table.body.children[ ... ];
...
const bottomOfRow = row.offsetHeight + row.offsetTop ;
// if the bottom of the row is in the viewport...
if( bottomOfRow - table.body.scrollTop < table.body.clientHeight ){
// ... if the top of the row is in the viewport
if( row.offsetTop - table.body.scrollTop > 0 ){
console.log( 'row is entirely visible' );
}
else if( row.offsetTop - table.body.scrollTop + row.offsetHeight > 0 ){
console.log( 'row is partly visible at top')
row.scrollIntoView();
}
else {
console.log( 'top of row out of view above viewport')
row.scrollIntoView();
}
}
else if( row.offsetTop - table.body.scrollTop < table.body.clientHeight ){
console.log( 'row is partly visible at bottom')
row.scrollIntoView();
}
else {
console.log( 'row is out of view beneath viewport')
row.scrollIntoView();
}
I think this is the complete answer. An elevator must be able to go both up and down ;)
function ensureVisible(elementId, top = 0 /* set to "top-nav" Height (if you have)*/) {
let elem = $('#elementId');
if (elem) {
let offset = elem.offset().top - $(window).scrollTop();
if (offset > window.innerHeight) { // Not in view
$('html,body').animate({ scrollTop: offset + top }, 1000);
} else if (offset < top) { // Should go to top
$('html,body').animate({ scrollTop: $(window).scrollTop() - (top - offset) }, 1000);
}
}
}