scrollTo div on hover - javascript

I asked this question and the answer works really well.
The only thing though is that now I need a version that scrolls directly to the respective div instead of scrolling through all of them (i.e. if you hover over the last link, it won't scroll through 6 former divs to get to it).
It still needs to return to the first div when you aren't hovering over the link.
Also, it would be most ideal if there was also a way to stay on that div if you hover over it as well as its link. As of now, the div is not intractable because when you hover over it and leave its link, it scrolls away.
Thanks.

Try that way:
DEMO fiddle
var flag = false,
goto = 0,
hre;
$('#nav li a').bind('mouseenter mouseleave', function(e) {
if (e.type === 'mouseenter') {
flag = true;
hre = $(this).attr('href');
goto = $(hre).position().top;
$('#sections').stop().animate({top : '-'+goto },800);
} else {
flag = false;
setTimeout(function() {
if( flag != true ){
$('#sections').stop().animate({top : '0' },800);
}
}, 1000);
}
});
$('#sections').mouseenter(function(){
flag = true;
});
After you hover an anchor, go fast into the 'wrapper' and it won't go back to the 1st slide.
BTW... why you just don't create something more... practique? :)
EXAMPLE fiddle

I'm pretty sure what you are asking is impossible for this reason:
First you want to have the animation return the top when the user is not hovering over the link BUT you also want to be able to stay on the div when the user LEAVES the link and hovers over the div it scrolled to.
Here is a jsfiddle which does the first part of your question though.
http://jsfiddle.net/YWnzc/8/
I just set the animation time to 0

Just move the elements around before animating: http://jsfiddle.net/YWnzc/12/.
I made use of $.doTimeout and $.scrollTo for convenience. Also I parsed the number out with a regexp. The timeout is to allow for movement into the div without scrolling back.
var current, prev;
jQuery( "#nav").delegate( "a", "mouseenter mouseleave", function(e){
var i, self = this, pos;
if( e.type == "mouseleave" ) {
i = 1;
} else {
i = $(this).attr("href").match(/(\d)$/)[1];
}
//stop the previous animation, otherwise it will be queued
if(e.type === "mouseleave") {
var elem = $("#section1").insertBefore(current);
elem = $("#section1");
$.doTimeout("test", 500, function() {
current = $("#section1");
jQuery("#wrapper").scrollTo(elem, 250);
});
} else {
var elem = $("#section" + i);
elem.insertAfter(current || "#section1");
current = elem;
$.doTimeout("test");
jQuery("#wrapper").scrollTo(elem, 250);
}
});
jQuery( "#wrapper").on("mouseover", function() {
jQuery( "#wrapper").stop();
});

Just remove the animation scroll and do a direct scrollTop() call
Fiddle Demo: http://jsfiddle.net/YWnzc/9/

Related

Restore scroll position after mobile menu is closed

I'm having a mobile menu that opens and closes using jquery by adding a css class that has display:block while the menu div has display:none.
The jquery code has a part where it is supposed to close the menu when a click is registered outside the menu div. Everything works execept the: $("body").scrollTop(scrollpos) . This was supposed to scroll the user back where he left off after the scrollTop(0) took place and the menu has closed, but it does not scroll at all the scroll is stuck at the top. Any help will be appreciated. Thank you.
EDIT: Here is an example: https://jsfiddle.net/mufwwudj/
$(function () {
var menutoggle = $(".menu-toggle");
var sidenav = $(".side-nav");
menutoggle.click(function () {
var scrollpos = $('body').scrollTop();
if (!$("body").hasClass("m-nav-open")) {
$("body").scrollTop(0).addClass("m-nav-open");
}
$(document).mouseup(function (e){
if (!sidenav.is(e.target) && sidenav.has(e.target).length === 0 && !menutoggle.is(e.target) && menutoggle.has(e.target).length === 0){
if ($("body").hasClass("m-nav-open")) {
$("body").scrollTop(scrollpos).removeClass("m-nav-open");
}
}
});
});
});
One problem here is that you are assigning a new mouseup event every time the menutoggle.click function runs.
$(document).mouseup(function (e){
if (!sidenav.is(e.target) && sidenav.has(e.target).length === 0 && !menutoggle.is(e.target) && menutoggle.has(e.target).length === 0){
if ($("body").hasClass("m-nav-open")) {
$("body").scrollTop(scrollpos).removeClass("m-nav-open");
}
}
});
Only the first one passes the conditional, even though each one will fire and scrollpos will always equal whatever it was in the first mouseup event listener.
I don't know how you are testing it, or what the HTML looks like but if you are at the top of the page the first time you click it, scrollpos in the mouseup event will always be 0.
Try assigning the mouseup event once, and putting scrollpos outside both so it can be accessed in both.
$(function () {
var menutoggle = $(".menu-toggle");
var sidenav = $(".side-nav");
var scrollpos;
menutoggle.click(function () {
scrollpos = $('body').scrollTop();
if (!$("body").hasClass("m-nav-open")) {
$("body").scrollTop(0).addClass("m-nav-open");
}
});
$(document).mouseup(function (e){
if (!sidenav.is(e.target) && sidenav.has(e.target).length === 0 && !menutoggle.is(e.target) && menutoggle.has(e.target).length === 0){
if ($("body").hasClass("m-nav-open")) {
$("body").scrollTop(scrollpos).removeClass("m-nav-open");
}
}
});
});
function ScrollOnTopo() {
window.scrollTo(0, 0); //It scrolls page at top
}
This function may be useful to you.

Eliminate Recursion on Events Triggered Inside Mousewheel Event

I'm working on a project that's using a sort of dummy pagination. The body is set to overflow: hidden and currently the only way to navigate the pages is by physically clicking on either links in the nav pane, or on sroll-down/scroll-up buttons. Here's an idea of the events that are triggered when those elements are physically clicked:
var links = $('#topnav, .top-mid a'), l = links.length - 1;
var id = 0;
$('.scrollDown, .scrollUp, .top-mid a, body.home #topnav').click(function (e) {
e.preventDefault();
var $this = $(this);
if ($this.is('.scrollDown') && id < l) id++;
if ($this.is('.scrollUp') && id > 0) id--;
if ($this.is('#topnav, .top-mid a')) id = links.index(this);
// Body is animated down or up and elements are
// shown or hidden depending on what was clicked and
// and what the var id is currently equal to
});
The idea is to trigger exactly ONE click of the scroll button on a mousewheel event. So something close to as simple as this, but that actually works:
$(window).on('mousewheel', function(e){ // I realize this will not work in FF
var evt = e.originalEvent.wheelDelta;
console.log(evt);
// Scrolling Down
if (evt < 0) {
$('.scrollDown').click(); // This fires recursively as long as wheelDelta !== 0
}
});
How can I either force wheelDelta to only increment or decrement by one, or, barring that, how can I eliminate the recursion on the click event?
I've been at this for a while, and read lots of posts and haven't been able to crack it. I've also tried fullPage.js, but it's rather heavy and doesn't really suit my project for other various reasons.
I finally solved this, and of course it turned out to be quite simple. It was a matter of toggling a boolean value inside the click() event, but only after all the animations had taken place. Like this:
var scrolled = false;
$(window).on('mousewheel', function(e){
var evt = e.originalEvent.wheelDelta;
// Scrolling Down - Only fire the click event if it hasn't already fired
if (evt < 0 && !scrolled) {
$('.scrollDown').click();
// Scrolling Up
} else if (evt > 0 && !scrolled) {
$('.scrollUp').click();
}
});
// Toggle the scrolled variable inside the original click event
$('.scrollDown, .scrollUp').click(function (e) {
e.preventDefault();
var $this = $(this);
if ($this.is('.scrollDown') && id < l) {
id++;
scrolled = true;
setTimeout(function(){
scrolled = false;
}, 1500);
}
if ($this.is('.scrollUp') && id > 0) {
id--;
scrolled = true;
setTimeout(function(){
scrolled = false;
}, 1500);
}
// Other events here
// The timeout has to be set high enough to assure
// that the mousewheel event is finished
});

onmouseout event happens when I am still hovering over the label

When hovering over a label, I want an image to appear and appear at the forefront of the screen. When I move off of it, I want it to disappear. My problem is when I move my mouse across the label, the image disappears and reappears really fast. Shouldn't the mouse off event, that makes the item disappear, only happen when I completely go off the label? How can I achieve this?
labelArray[1].onmouseover = function() {
if (BBVar != 1)
mouseOverOption('BB1' + group);
};
labelArray[1].onmouseout = function() {
if ((clicked == false) && (BBVar != 1))
mouseOffOption('BB1' + group);
};
function mouseOverOption(a) {
document.getElementById(a).style.visibility = 'visible';
document.getElementById(a).style.zIndex="5";
}
function mouseOffOption(a) {
document.getElementById(a).style.visibility = 'hidden';
document.getElementById(a).style.zIndex="0";
}
mouseout will fire even when you are moving cursor from the target element to one of it's children.
The alternative is mouseleave event, unfortunately it is supported only in IE. Read more here http://www.quirksmode.org/dom/events/mouseover.html
If you can use jQuery, it has cross browser support for mouseleave:
$(labelArray[1]).on('mouseleave', function() {
if ((clicked == false) && (BBVar != 1))
mouseOffOption('BB1' + group);
});
In pure JS you have to check event.relatedTarget property to see where the mouse goes. It's hard to give an exact solution without seeing your markup.

How to prevent duplicate events when scroll in jQuery?

I have 4 divs like;
<div class="diva">diva</div>
<div class="divb">divb</div>
<div class="divc">divc</div>
<div class="divd">divd</div>
They are 400px wide and high. I want to alert a when div b scrolls to top of page, and did using scroll function and scrollTop method. Each time when scroll, it check if scrollTop() if lager than 400, and alert a. But if I don't click the on the ok button of alert window, if I continue scrolling, multiple alerts will come, and I have to close them all.
But I just want one alert, and even if I continue scrolling, I want no more alerts. Also if the scrollTop is below 400px, I want to alert b (here also, I don't want repeats). If I got alert a, and if I scroll in opposite direction, and if scrollTop becomes below 400px, I want alert b, no problem for that.
Here is the fiddle.
please add this script on your file JS and try this script:
$(document).ready(function() {
$(window).scroll(function(){
var xx = $(document).scrollTop();
if(xx > jQuery(".divb").height()){
alert("a");
}else{
alert("b");
}
});
});
You are popping alerts on a 'scroll' event which happens every time you scroll..
if this is just a debugging annoyance, what you can do is use console.log('a') instead - example
If you wanted the actual function to run once for each time you reach it you can do this:
var a = false;
$(window).scroll(function(){
var xx = $(document).scrollTop();
if(xx > 400){
if (!a) {
alert("a");
a = true;
}
}else{
if (a) {
alert("b");
a = false;
}
}
});
fiddle for this example
The easiest way to avoid any confusion would be to keep state of scroll actions.
Demo: http://jsfiddle.net/abhitalks/uwUvC/1/
var last = 0, // last scroll-top to determine scroll direction
scrolledUp = false, // to cache state of scroll up
scrolledDown = false; // to cache state of scroll down
$(window).scroll(function (event) {
var current = $(this).scrollTop();
if (current > last) { // if scrolled down
if (current > 400 && !scrolledDown) { // check position and state
alert("A");
scrolledDown = true; // reset scroll down state
}
} else { // if scrolled up
if (current < 400 && scrolledDown && !scrolledUp) {
alert("B");
scrolledUp = true; // reset scroll up state
}
}
last = current; // keep current position to check direction
});
This way you are sure about when you are scrolling up and when you are scrolling down. Keep state of scroll in respective variables and check them.
The alerts fire only once in each direction.

Controlling the scroll of div A while scrolling div B with mousewheel and vice versa

I have 2 div that act like a list or a table i am trying to make div A's scrolling scroll div B and vice versa. with the mousewheel.
The issue with that is since i bind "scroll" on both, when i set scrollTop = something from div B for div A it will also trigger the "scroll" of div A.
What i came up with is: on mouseover - bind "scroll" for current element, then on mouseout unbind it and in the bind function i change the scrollTop example:
$('#parent1, #parent2').off('mouseover').on( 'mouseover', function () {
var that = this;
refresh(that);
$(this).off( 'scroll').on( 'scroll', function () {
refresh(that);
});
} ).off('mouseout').on( 'mouseout', function () {
$(this).off( 'scroll');
refresh(this);
});
function refresh(that){
if(that == $('#parent1')[0]){
$('#parent2').scrollTop($(that).scrollTop());
}else{
$('#parent1').scrollTop($(that).scrollTop());
}
}
See it in action in: Fiddle
however when scrolling and moving from 1 div to another fast enough it causes trouble and wont work correctly.
Anyone with an idea ?
Ah ignore the following code in the fiddle:
var i= 0;
$('#parent1 div').each(function(index, div){
$(div).append(" " + i);
i++;
});
var i= 0;
$('#parent2 div').each(function(index, div){
$(div).append(" " + i);
i++;
});
Thanks in advanced.
You can add an event listener that when you scroll A it updates the scroll position of B. But for that you need a flag so that when you set the scroll B position it don't trigger the scroll B event.
Fiddle: http://jsfiddle.net/7qBvM/
var ignoreEvent = false;
$('#parent1').scroll( function() {
var ignore = ignoreEvent;
ignoreEvent = false
if (!ignore) {
ignoreEvent = true;
$('#parent2').scrollTop($(this).scrollTop());
}} );
$('#parent2').scroll( function() {
var ignore = ignoreEvent;
ignoreEvent = false;
if (!ignore) {
ignoreEvent = true;
$('#parent1').scrollTop($(this).scrollTop());
}} );
(With help from this question)

Categories