I'm having trouble with jScrollPane's reinitialise() method. Whenever I call it, stuff that I implemented in the first initialisation stops working...
In my current code, I'm doing something like this:
$('.scrollable').each(function(){
var e = $(this),
parent = e.parent();
e.jScrollPane({
// parameters
});
var api = e.data('jsp'),
arrowup = e.find('.jspArrowUp'),
arrowdw = e.find('.jspArrowDown');
if ( api.getIsScrollableV() ) {
e.addClass('scrolled-top');
parent.addClass('scroll-parent');
}
e.scroll(function(){
var scrbef = api.getContentPositionY(),
scrmax = api.getContentHeight() - this.clientHeight,
scraft = scrmax - scrbef,
dlayup = (scrbef - 220)/100,
dlaydw = (scraft - 220)/100,
opacup = dlayup > 1 ? 1 : dlayup < 0 ? 0 : dlayup,
opacdw = dlaydw > 1 ? 1 : dlaydw < 0 ? 0 : dlaydw;
if ( scrbef === 0 ) {
e.addClass('scrolled-top').removeClass('scrolled-bot');
} else if ( scraft === 0 ) {
e.addClass('scrolled-bot').removeClass('scrolled-top');
} else {
e.removeClass('scrolled-top scrolled-bot');
}
arrowup.css('opacity', opacup);
arrowdw.css('opacity', opacdw);
});
So far, so good. What that does is:
initialise jScrollPane on the .scrollable elements
depending on the content position, add or remove scrolled-top or scrolled-bot classes.
controls the opacity of the arrows depending on the content's position (there's a lot of padding at the top and bottom, so I only want the arrows to appear when the actual content has reached the border of the screen).
Right after that bit, I have this:
var throttleTimeout;
$(window).resize(function(){
if ( !throttleTimeout ) {
throttleTimeout = setTimeout( function(){
api.reinitialise();
throttleTimeout = null;
}, 500
);
}
});
$('.deployer').click(function(e){
api.reinitialise();
});
});
Now, that is pretty straightforward; the code to reinitialise when the window is resized comes straight from the documentation.
However, as soon as either reinitialise() is called, so after resizing the window or clicking on the .deployer element, the previous code which controlled the arrows' opacity stops working – although, weirdly enough, the scrolled-top and scrolled-bot classes still get added or removed properly.
Does anyone know what might be causing this behaviour and how to fix it?
Cheers.
Found what was happening.
Whenever you reinitialise, basically everything gets resetted, so the elements that were previously stored in arrowup and arrowdw don't exist anymore. Adding
var arrowup = e.find('.jspArrowUp'),
arrowdw = e.find('.jspArrowDown');
again after each reinitialise() made the trick.
Related
I have a working bottom function in JavaScript to detect if the user scrolls at the bottom. However, a problem comes when the user has a strange resolution (like windows scale) or when you zoom. The function is not working anymore and can't detect the bottom.
Here is what I did :
const bottom = e.target.scrollHeight - e.target.scrollTop === e.target.clientHeight;
if (bottom) {
this.props.getNewValues();
}
Is there a way to avoid that? Even when you don't zoom, this is not working for people displaying the site on a TV or something like this (like a friend of mine did)
Thanks you
EDIT : I'm applying this on a precise element and I repeat that my solution is working except by unzooming. Unzooming provides float values that made the response not really accurate (it goes from 1 to 50px of difference based on the zoom made)
I use this function (can't take credit as someone else wrote it - sorry for no credit - it was ages ago). Maybe you can adapt this to your use case:
(function($) {
//CHECK SCROLLED INTO VIEW UTIL
function Utils() {
}
Utils.prototype = {
constructor: Utils,
isElementInView: function (element, fullyInView) {
var pageTop = $(window).scrollTop();
var pageBottom = pageTop + $(window).height();
var elementTop = $(element).offset().top;
var elementBottom = elementTop + $(element).height();
if (fullyInView === true) {
return ((pageTop < elementTop) && (pageBottom > elementBottom));
} else {
return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
}
}
};
var Utils = new Utils();
//END CHECK SCROLLED INTO VIEW UTIL
//USING THE ELEMENT IN VIEW UTIL
//this function tells what to do do when the element is or isnt in view.
//var inView = Utils.isElementInView(el, false); Where FALSE means the element doesnt need to be completely in view / TRUE would mean the element needs to be completely in view
function IsEInView(el) {
var inView = Utils.isElementInView(el, false);
if(inView) {
//console.log('in view');
} else {
//console.log('not in view');
}
};
//Check to make sure the element you want to be sure is visible is present on the page
var variableOfYourElement = $('#variableOfYourElement');
//if it is on this page run the function that checks to see if it is partially or fully in view
if( variableOfYourElement.length ) {
//run function on page load
IsEInView(variableOfYourElement);
//run function if the element scrolls into view
$(window).scroll(function(){
IsEInView(variableOfYourElement);
});
}
//END USING THE ELEMENT IN VIEW UTIL
})(jQuery);
I'm writing this after searching for mousewheel events in jQuery, but perhaps I'm not asking the right questions due to my lack of knowledge, and that's why I'm not finding any useful answers yet.
What I would like to achieve is a mousewheel effect that I can trigger only inside a certain div called #scroller. I'm using the jquery mousewheel plugin by Brandon Aaron and a script that updates the top value to the next or previous .js-slide whenever I delta scroll.
FIDDLE LINK:
I created this fiddle link. As you can see, it "jumps" from slide to slide, but then the content outside #scroller is not accesible anymore! I would like it to have a normal wheelmouse behaviour :S. I also have a working url where I would like to apply this effect, if you think that's of any use.
To better explain the structure and desired effect, here's an image:
I have already tried bounding my script only to $('#scroller').mouseover(function(){ my script }); but that didn't work. The mousewheel started out ok, it switched into jumping mode ok, but it never went back to normal after leaving the div #scroller and I don't find how to reset this behaviour.
My script right now is this:
jQuery(document).ready(function($) {
var slide = $('.js-slide');
var sectionHeight = $(window).height();
var slideHeight = $(slide).height();
var scrollingScreen = false;
$('#scroller').mouseover(function(){
$(slide).mousewheel(function(event, delta) {
if ( !scrollingScreen ) {
scrollingScreen = true; // prevent call
var top = $("body").scrollTop() || $("html").scrollTop();
// Chrome places overflow at body, Firefox places whacks at html...
// Finds slide headers above/below the current scroll top
var candidates = $(slide).filter(function() {
if ( delta < 0 )
return $(this).offset().top > top + (1);
else
return $(this).offset().top < top - (1);
});
// one or more slides found? Update top
if ( candidates.length > 0 ) {
if ( delta < 0 )
top = candidates.first().offset().top;
else if ( delta > 0 )
top = candidates.last().offset().top;
}
// Perform animated scroll to the right place
$("html,body").animate({ scrollTop:top }, "easeInOutQuint", function() {
scrollingScreen = false; // Release call
});
}
return false;
}); // closes mousewheel
}); // closes mouseover
});
Any help or insight on how to achieve this would be greatly appreciated.
Thank you!
Ok. Finally I found it!! I reviewed the web where the plugin author records different mousewheel events, including deactivating all of them and reseting a normal scrolling mouse. There's where I found the use of the function .unmousewheel(), just what I wanted!
But now, as the script is not able to find further slides past de last when scrolling down, and before the first when scrolling up, it became impossible to access content before and after #scroller with the scrolling wheel. That's why I had to change a bit the script and force a jump while on the first slide or the last.
Anyway, here's the script:
jQuery(document).ready(function($) {
var slide = $('#scroller .sectioncontainer');
var sectionHeight = $(window).height();
var slideHeight = slide.height();
var scrollingScreen = false;
slide.mousewheel(function(event, delta) {
if ( !scrollingScreen ) {
scrollingScreen = true; // prevent call
var top = $("body").scrollTop() || $("html").scrollTop();
// Chrome places overflow at body, Firefox places whacks at html...
// Finds slide headers above/below the current scroll top
var candidates = slide.filter(function() {
if ( delta < 0 )
return $(this).offset().top > top + (1/120);
else
return $(this).offset().top < top - (1/120);
});
// one or more slides found? Update top
if ( candidates.length > 0 ) {
if ( delta < 0 )
top = candidates.first().offset().top;
else if ( delta > 0 )
top = candidates.last().offset().top;
} else{ // no more slides found
if ( delta < 0 )
top = $("#contact").offset().top;
else if ( delta > 0 )
top = $("#about").offset().top;
}
// Perform animated scroll to the right place
$("html,body").animate({ scrollTop:top }, "easeInOutQuint", function() {
scrollingScreen = false; // Release call
});
}
return false;
});
$("#contact").unmousewheel();
$("#about").unmousewheel();
$("#div1").unmousewheel();
$("#div2").unmousewheel();
$("#div3").unmousewheel();
$("#div4").unmousewheel();
$("#div5").unmousewheel();
// . . .
//and all other divs and sections that don't use the mousewheel
});
And here's the result.
Well I hope the question is self-explanatory. I have the following code:
$(window).scroll(function () {
var scrollTop = $(window).scrollTop();
if (scrollTop > sliderTop) {
$('#slider').slideDown(1000);
} else {
$('#slider').slideUp(1000);
}
});
If I scroll down after a certain point the slideDown function will be called continuously. does JQuery animates it over and over again or is it smart enough to know that the element is already slide down? (currently I'm using a flag to check whether its already slide down).
The animation won't run again. See lines 459-468 in effect.js in the jquery src
doAnimation = function() {
// Operate on a copy of prop so per-property easing won't be lost
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
// Empty animations, or finishing resolves immediately
if ( empty || data_priv.get( this, "finish" ) ) {
anim.stop( true ); // ** here - stopping right after started.
}
};
doAnimation.finish = doAnimation;
But I would still recommend against it to improve code readability. just use a boolean, it doesn't hurt...
I have created a newsfeed. The feed switches every 2 seconds. You can also manually switch left/right, or click the panel from the squares at the bottom. The switching between slides is down using jQuery UI Slide.
Right now, if you are in the middle of a slide, and you click left/right/squares, then another slide occurs on top of the existing, still going slide and the whole system is messed up.
How can I prevent other actions occurring if a slide/switch is already in progress?
This is my code:
$(document).ready(function(){
newsfeedTimer = setInterval(newsfeed, displayDuration);
// Manual change of feed (LEFT)
$('#newsfeeds_wrapper > .left').click(function(event){
event.stopPropagation();
feedLeft();
clearInterval(newsfeedTimer);
newsfeedTimer = setInterval(newsfeed, displayDuration);
});
// Very similar code for feed right
// Ignore the other method of switching (if it works for above, I can implement it for this one)
});
function newsfeed() {
feedRight();
}
// Feed to the Right
// jump is used to jump multiple newsfeed instead of one at a time
function feedRight(jump)
{
jump = typeof jump !== 'undefined' ? jump : 1;
var current = $('.newsfeed:first');
var next = $('.newsfeed:nth(' + jump + ')');
current.hide('slide',{duration: transitionDuration}, function(){
// Append as many needed
for( var i = 0; i < jump; i++ ) {
$('.newsfeed:first').appendTo('#newsfeeds');
}
next.show('slide',{direction : 'right' , duration: transitionDuration});
}
I don't want to stop() an animation! I want to disable changing the slides IF there is animation happening!!
without seeing the full breadth of the code, I am shooting myself in the foot here. But here is a direction I would take it. You could also have two functions, one to bind, another to unbind. When animation is initiated, you unbind the left/right controls. When stopped, you bind. Or, set a global variable... ala.
var config = {'inProgress': false};
$('#newsfeeds_wrapper > .left').click(function(event){
if(!config.inProgress){
event.stopPropagation();
feedLeft();
clearInterval(newsfeedTimer);
newsfeedTimer = setInterval(newsfeed, displayDuration);
}
});
in your animation function. Seems like when you cut/paste, some of the code is lost, so lets just assume some animation.
when you enter your animation functions, set config.inProgress = true;
function feedRight(jump)
{
config.inProgress = true;
// removed your code, but just using for simplicity sake
// added a callback
next.show('slide',{direction : 'right' , duration: transitionDuration},
function() {
// Animation complete. Set inProgress to false
config.inProgress = false;
});
)
}
I would like to make it so when user scrolls down and reaches a certain div, say #float, set that div to margin-top: 50px and position fixed, and if user scrolls back up undo those changes. It's hard to understand I know ))) If you go to this page and pay your attention to sidebar once scrolling up and down you will see what I mean.
As you scroll down 2nd advertisement scrolls with a page too.
How would I achieve same functionality with jQuery/CSS?
This is a way of doing it in jQuery.
This code is provided for example purposes only; there are almost certainly a handful of regularly-maintained jQuery plugins that will do this thing for you - check GitHub or DailyJS.
$(window).scroll(function() {
var styledDiv = $('#styledDiv'),
targetScroll = $('#float').position().top,
currentScroll = $('html').scrollTop() || $('body').scrollTop();
styledDiv.toggleClass('fixedPos', currentScroll >= targetScroll);
});
Here is a simple JSFiddle of the above in action.
Edit: Have now refactored this code to a more elegant solution.
Edit 2: Following an email I received about a question, I've updated the code above so that it also works in Firefox. As $('body').scrollTop() will not work in Firefox (See comments on the jQuery API page), we need to check both the html and body elements.
This is the relevant jQuery/JavaScript code use on that site.
if (window.XMLHttpRequest) {
var topGagStay = $("top-gag-stay");
var isLoggedIn = $("profile-menu") ? true : false;
var sidebarAdsTop = 1061 - 545;
var signupBtnOffset = 60;
var dockPos = 72;
if (!isLoggedIn && !GAG.isReadOnly()) {
sidebarAdsTop += signupBtnOffset
}
if (formMessageShown) {
sidebarAdsTop += formMessageOffset
}
if (topGagStay) {
if (document.documentElement.scrollTop > sidebarAdsTop || self.pageYOffset > sidebarAdsTop) {
if (topGagStay.style.position != "fixed") {
topGagStay.style.position = "fixed";
topGagStay.style.top = dockPos + "px"
}
} else {
if (document.documentElement.scrollTop < sidebarAdsTop || self.pageYOffset < sidebarAdsTop) {
topGagStay.style.position = "";
topGagStay.style.top = ""
}
}
}
}
Thank FireBug and http://jsbeautifier.org/ for the code (and 9GAG, of course).
I have tried the above answer by beardtwizzle and it worked fine. Also made it work for the case when the page is scrolled upto the bottom of the page.
see the working demo/tutorial here