I have this simple JavaScript to make a hidden div appear on img hover:
document.onmouseover = quickView;
function quickView(e) {
(!e) var e = window.event;
var target = e.target || e.srcElement;
var bWide = window.innerWidth || document.documentElement.clientWidth;
if(target.className == 'p-image') {
var dTarg = target.parentNode.lastChild;
dTarg.style.visibility = 'visible';
dTarg.style.top = (target.parentNode.offsetTop - 110) + 'px';
if (target.parentNode.offsetLeft < (bWide * .5)) {
dTarg.style.left = (target.parentNode.offsetLeft + 185) + 'px';
}
if (target.parentNode.offsetLeft >= (bWide * .1801)) {
dTarg.style.left = (target.parentNode.offsetLeft - 497) + 'px';
}
target.onmouseout = hideQuickView;
}
}
function hideQuickView(e) {
if (!e) var e = window.event;
var target = e.target || e.srcElement;
target.parentNode.lastChild.style.visibility = 'hidden';
}
What I need is to add a fadein and fadeout effect instead of just visible / hidden.
Also a delay in fadein would be great. I know some jQuery but this is old JS, how can I add the fade effects?
Thank you very much
EDIT:
i managed to fadein the hiddendiv but it will not allways fadein. If i move the mouse very fast to another hidden div the effect will not work anymore.I need to wait sometime for the fade to work again. I mean the code is not an accurate solution.
As i said the hover class is called p-image and the hidden class is called quickview.
This is the jQuery, but i would prefere if i can edit the original JavaScript somehow to include the delay fade there.
$(document).ready(function(){
$(".p-image").hover(function () {
jQuery(".quickview").css("opacity", .20);
jQuery(".quickview").fadeTo(430, 1);
});
return true;
});
add jQuery to your site and use $(selector).fadeIn(); and $(selector).fadeOut();
selector can be any css selector e.g. $('#element_id').fadeIn()
replace the bit of code where you hide/show the elements with the jquery bits. you can leave the rest in normal js. to change the duration of the fade add an argument to the function e.g. $(element).fadeIn(400); will make the fade last 400ms
more information here
You use jQuery's fadeIn function to fade elements in and fadeOut to fade them out. Then use delay with fadeIn if you want a delay, $( "selector" ).delay( 500 ).fadeIn()
$( document ).on( "mouseover", function( e ) {
e = e || window.event;
var $target = $( e.target || e.srcElement );
var bWide = $( window ).width();
if ( $target.hasClass( "p-image" ) )
{
var $dTarg = $target.parent().children().last();
var targOffset = $target.parent().offset();
$dTarg.fadeIn().css( "top", targOffset.top - 110 + "px" );
if ( targOffset.left < ( bWide * .5 ) )
{
$dTarg.css( "left", $targOffset.left + 185 + 'px' );
}
else if ( targOffset.left >= ( bWide * .1801 ) )
{
$dTarg.css( "left", $targOffset.left - 497 + 'px' );
}
$target.on( "mouseout", hideQuickView );
}
});
// You should be able to figure out hideQuickView implementation.
$(dTarg).fadeIn("1000")
This fades the stuff in in 1 sec.
You must also change the css for the dTarg item from
visibility:hidden
to
display:none
Related
I have a page which contains a hype document, which is a sequence of animations played as scenes. In the final scene a green tick is generated allowing the user to move onto the next chapter. I want the green tick to show its tooltip as designated by a javascript file tooltip.js. This file is loaded with the page as it used on other elements within the page outside the hype element.
The problem is that as tooltip.js is loaded with the page before the green tick has been generated, it does not apply itself to the green tick. I can get round this by:
if (scenenumber3 == finalSceneNumber) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "/scripts/tooltip.js"
head.appendChild(script);
}
Where scenenumber3 is the current scene number, so on the final scene where the green tick is generated the tooltip.js is added and loaded. This works but means the tooltip.js file is loaded every time that scene is run. It also means this file clashes with the originally loaded file, causing some problems. The tooltip.js file is as follows:
$(function ()
{
var targets = $( '[data-rel~=tooltip]' ),
target = false,
tooltip = false,
title = false;
targets.bind('mouseenter', function ()
{
target = $( this );
tip = target.attr( 'title' );
tooltip = $( '<div id="tooltip"></div>' );
if( !tip || tip == '' )
return false;
target.removeAttr( 'title' );
tooltip.css( 'opacity', 0 )
.html( tip )
.appendTo( 'body' );
var init_tooltip = function ()
{
if( $( window ).width() < tooltip.outerWidth() * 1.5 )
tooltip.css( 'max-width', $( window ).width() / 2 );
else
tooltip.css( 'max-width', 340 );
var pos_left = target.offset().left + ( target.outerWidth() / 2 ) - ( tooltip.outerWidth() / 2 ),
pos_top = target.offset().top - tooltip.outerHeight() - 8;
if( pos_left < 0 )
{
pos_left = target.offset().left + target.outerWidth() / 2 - 8;
tooltip.addClass( 'left' );
}
else
tooltip.removeClass( 'left' );
if( pos_left + tooltip.outerWidth() > $( window ).width() )
{
pos_left = target.offset().left - tooltip.outerWidth() + target.outerWidth() / 2 + 20;
tooltip.addClass( 'right' );
}
else
tooltip.removeClass( 'right' );
if( pos_top < 0 )
{
var pos_top = target.offset().top + target.outerHeight();
tooltip.addClass( 'top' );
}
else
tooltip.removeClass( 'top' );
tooltip.css( { left: pos_left, top: pos_top } )
.animate( { top: '+=0', opacity: 1 }, 250 );
};
init_tooltip();
$( window ).resize( init_tooltip );
var remove_tooltip = function ()
{
tooltip.animate({ top: '-=0', opacity: 0 }, 250, function ()
{
$( this ).remove();
});
target.attr( 'title', tip );
};
target.bind( 'mouseleave', remove_tooltip );
tooltip.bind( 'click', remove_tooltip );
});
What I would like to know is what is the best way to handle this? Can I re-run the tooltip.js file that has already been loaded so it applies to the green tick only? I'm not in any way experienced with javascript so I would appreciate hearing what those who know javascript well would do to handle this situation?
Hey guys I'm back with another question. I'm using the code below to add a bouncing effect to a div on my site. It works fine right now but the div has to be clicked in order for the effect to start. I would like to modify it so that when the user is scrolling down the page and reaches that section it triggers the effect automatically. How can I modify the code below to trigger the effect when the user scroll's down and reaches that section of the site?
Here is the code I' using
$(".servi-block").click(function () {
doBounce($(this), 2, '10px', 150);
});
function doBounce(element, times, distance, speed) {
for (i = 0; i < times; i++) {
element.animate({
marginTop: '-=' + distance
}, speed)
.animate({
marginTop: '+=' + distance
}, speed);
}
}
$(window).scroll(function(event){
isElementVisible = inViewport($(".servi-block"));
if(isElementVisible)
{
doBounce($(this), 2, '10px', 150);
}
});
function inViewport (el)
{
var r, html;
if ( !el || 1 !== el.nodeType ) { return false; }
html = document.documentElement;
r = el.getBoundingClientRect();
return ( !!r
&& r.bottom >= 0
&& r.right >= 0
&& r.top <= html.clientHeight
&& r.left <= html.clientWidth
);
}
This should help you out: http://api.jquery.com/scroll/
$( "#target" ).scroll(function() {
$( "#log" ).append( "<div>Handler for .scroll() called.</div>" );
});
Also utilize this
$('#target').on("mousewheel", function() {
alert($(document).scrollTop());
});
Those two together should get you the ability to figure out you are scrolling, and when you reach position X, do something.
EDITED
Let's go at it this way -
var targetPos = "500px";
$( document ).scroll(function() {
if ($(document).scrollTop() == targetPos) {
doBounce($(this), 2, '10px', 150);
}
});
You can simply check to see when the element comes into view by taking the element's offset and subtracting that element's parent height and scrollTop value.
Here's an example:
$(document).ready(function() {
$(document).on('scroll', function() {
var offset = $('.element').offset().top,
scroll = $(document).scrollTop(),
height = $(document).height(),
inViewDown = ((offset - scroll - height) <= 0) ? true : false;
if (inViewDown) {
// Do some stuff
}
});
});
Here's a working example: http://jsfiddle.net/ughEe/
I have a div, with a scroll bar, When it reaches the end, my page starts scrolling. Is there anyway I can stop this behavior ?
You can inactivate the scrolling of the whole page by doing something like this:
<div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>
Found the solution.
http://jsbin.com/itajok
This is what I needed.
And this is the code.
http://jsbin.com/itajok/edit#javascript,html
Uses a jQuery Plug-in.
Update due to deprecation notice
From jquery-mousewheel:
The old behavior of adding three arguments (delta, deltaX, and deltaY)
to the event handler is now deprecated and will be removed in later
releases.
Then, event.deltaY must now be used:
var toolbox = $('#toolbox'),
height = toolbox.height(),
scrollHeight = toolbox.get(0).scrollHeight;
toolbox.off("mousewheel").on("mousewheel", function (event) {
var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
return !blockScrolling;
});
Demo
The selected solution is a work of art. Thought it was worthy of a plugin....
$.fn.scrollGuard = function() {
return this
.on( 'wheel', function ( e ) {
var event = e.originalEvent;
var d = event.wheelDelta || -event.detail;
this.scrollTop += ( d < 0 ? 1 : -1 ) * 30;
e.preventDefault();
});
};
This has been an ongoing inconvenience for me and this solution is so clean compared to other hacks I've seen. Curious to know how more about how it works and how widely supported it would be, but cheers to Jeevan and whoever originally came up with this. BTW - stackoverflow answer editor needs this!
UPDATE
I believe this is better in that it doesn't try to manipulate the DOM at all, only prevents bubbling conditionally...
$.fn.scrollGuard2 = function() {
return this
.on( 'wheel', function ( e ) {
var $this = $(this);
if (e.originalEvent.deltaY < 0) {
/* scrolling up */
return ($this.scrollTop() > 0);
} else {
/* scrolling down */
return ($this.scrollTop() + $this.innerHeight() < $this[0].scrollHeight);
}
})
;
};
Works great in chrome and much simpler than other solutions... let me know how it fares elsewhere...
FIDDLE
You could use a mouseover event on the div to disable the body scrollbar and then a mouseout event to activate it again?
E.g. The HTML
<div onmouseover="disableBodyScroll();" onmouseout="enableBodyScroll();">
content
</div>
And then the javascript like so:
var body = document.getElementsByTagName('body')[0];
function disableBodyScroll() {
body.style.overflowY = 'hidden';
}
function enableBodyScroll() {
body.style.overflowY = 'auto';
}
As answered here, most modern browsers now support the overscroll-behavior: none; CSS property, that prevents scroll chaining. And that's it, just one line!
Here's a cross-browser way to do this on the Y axis, it works on desktop and mobile. Tested on OSX and iOS.
var scrollArea = this.querySelector(".scroll-area");
scrollArea.addEventListener("wheel", function() {
var scrollTop = this.scrollTop;
var maxScroll = this.scrollHeight - this.offsetHeight;
var deltaY = event.deltaY;
if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
event.preventDefault();
}
}, {passive:false});
scrollArea.addEventListener("touchstart", function(event) {
this.previousClientY = event.touches[0].clientY;
}, {passive:false});
scrollArea.addEventListener("touchmove", function(event) {
var scrollTop = this.scrollTop;
var maxScroll = this.scrollHeight - this.offsetHeight;
var currentClientY = event.touches[0].clientY;
var deltaY = this.previousClientY - currentClientY;
if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
event.preventDefault();
}
this.previousClientY = currentClientY;
}, {passive:false});
I wrote resolving for this issue
var div;
div = document.getElementsByClassName('selector')[0];
div.addEventListener('mousewheel', function(e) {
if (div.clientHeight + div.scrollTop + e.deltaY >= div.scrollHeight) {
e.preventDefault();
div.scrollTop = div.scrollHeight;
} else if (div.scrollTop + e.deltaY <= 0) {
e.preventDefault();
div.scrollTop = 0;
}
}, false);
If I understand your question correctly, then you want to prevent scrolling of the main content when the mouse is over a div (let's say a sidebar). For that, the sidebar may not be a child of the scrolling container of the main content (which was the browser window), to prevent the scroll event from bubbling up to its parent.
This possibly requires some markup changes in the following manner:
<div id="wrapper">
<div id="content">
</div>
</div>
<div id="sidebar">
</div>
See it's working in this sample fiddle and compare that with this sample fiddle which has a slightly different mouse leave behavior of the sidebar.
See also scroll only one particular div with browser's main scrollbar.
this disables the scrolling on the window if you enter the selector element.
works like charms.
elements = $(".selector");
elements.on('mouseenter', function() {
window.currentScrollTop = $(window).scrollTop();
window.currentScrollLeft = $(window).scrollTop();
$(window).on("scroll.prevent", function() {
$(window).scrollTop(window.currentScrollTop);
$(window).scrollLeft(window.currentScrollLeft);
});
});
elements.on('mouseleave', function() {
$(window).off("scroll.prevent");
});
You can inactivate the scrolling of the whole page by doing something like this but display the scrollbar!
<div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>
$this.find('.scrollingDiv').on('mousewheel DOMMouseScroll', function (e) {
var delta = -e.originalEvent.wheelDelta || e.originalEvent.detail;
var scrollTop = this.scrollTop;
if((delta < 0 && scrollTop === 0) || (delta > 0 && this.scrollHeight - this.clientHeight - scrollTop === 0)) {
e.preventDefault();
}
});
Based on ceed's answer, here is a version that allows nesting scroll guarded elements. Only the element the mouse is over will scroll, and it scrolls quite smoothly. This version is also re-entrant. It can be used multiple times on the same element and will correctly remove and reinstall the handlers.
jQuery.fn.scrollGuard = function() {
this
.addClass('scroll-guarding')
.off('.scrollGuard').on('mouseenter.scrollGuard', function() {
var $g = $(this).parent().closest('.scroll-guarding');
$g = $g.length ? $g : $(window);
$g[0].myCst = $g.scrollTop();
$g[0].myCsl = $g.scrollLeft();
$g.off("scroll.prevent").on("scroll.prevent", function() {
$g.scrollTop($g[0].myCst);
$g.scrollLeft($g[0].myCsl);
});
})
.on('mouseleave.scrollGuard', function() {
var $g = $(this).parent().closest('.scroll-guarding');
$g = $g.length ? $g : $(window);
$g.off("scroll.prevent");
});
};
One easy way to use is to add a class, such as scroll-guard, to all the elements in the page that you allow scrolling on. Then use $('.scroll-guard').scrollGuard() to guard them.
If you apply an overflow: hidden style it should go away
edit: actually I read your question wrong, that will only hide the scroll bar but I don't think that's what you are looking for.
I couldn't get any of the answers to work in Chrome and Firefox, so I came up with this amalgamation:
$someElement.on('mousewheel DOMMouseScroll', scrollProtection);
function scrollProtection(event) {
var $this = $(this);
event = event.originalEvent;
var direction = (event.wheelDelta * -1) || (event.detail);
if (direction < 0) {
if ($this.scrollTop() <= 0) {
return false;
}
} else {
if ($this.scrollTop() + $this.innerHeight() >= $this[0].scrollHeight) {
return false;
}
}
}
I have an HTML element with some padding. I would like to detect for clicks on that element's padding. That is, I don't want the event to fire when the user clicks on the content, just the padding.
I needed this as well, but also wanted a "real" solution. The accepted answer does really not target the question "Detecting click event on padding only" but suggests an intrusive change to the markup.
A "padding click" can be detected simply by retrieving the elements padding settings, computed width and height and compare those values to the mouse click offsets :
function isPaddingClick(element, e) {
var style = window.getComputedStyle(element, null);
var pTop = parseInt( style.getPropertyValue('padding-top') );
var pRight = parseFloat( style.getPropertyValue('padding-right') );
var pLeft = parseFloat( style.getPropertyValue('padding-left') );
var pBottom = parseFloat( style.getPropertyValue('padding-bottom') );
var width = element.offsetWidth;
var height = element.offsetHeight;
var x = parseFloat( e.offsetX );
var y = parseFloat( e.offsetY );
return !(( x > pLeft && x < width - pRight) &&
( y > pTop && y < height - pBottom))
}
demo here -> http://jsfiddle.net/er5w47yf/
jQuery :
$('#element').on('click', function(e) {
if (isPaddingClick(this, e)) {
console.log('click on padding')
} else {
console.log('click on element')
}
})
native :
document.getElementById('element').addEventListener('click', function(e) {
if (isPaddingClick(this, e)) {
console.log('click on padding')
} else {
console.log('click on element')
}
}, false)
For convenience, this can be turned into a jQuery pseudo event handler :
(function($) {
var isPaddingClick = function(element, e) {
var style = window.getComputedStyle(element, null);
var pTop = parseInt( style.getPropertyValue('padding-top') );
var pRight = parseFloat( style.getPropertyValue('padding-right') );
var pLeft = parseFloat( style.getPropertyValue('padding-left') );
var pBottom = parseFloat( style.getPropertyValue('padding-bottom') );
var width = element.offsetWidth;
var height = element.offsetHeight;
var x = parseFloat( e.offsetX );
var y = parseFloat( e.offsetY );
return !(( x > pLeft && x < width - pRight) &&
( y > pTop && y < height - pBottom))
}
$.fn.paddingClick = function(fn) {
this.on('click', function(e) {
if (isPaddingClick(this, e)) {
fn()
}
})
return this
}
}(jQuery));
Now paddingClick works "natively" :
$('#element').paddingClick(function() {
console.log('padding click')
})
demo -> http://jsfiddle.net/df1ck59r/
Create an inner element which has 100% height/width so it fills out the whole element. Then register a click event handler on this event and prevent bubbling of the event.
Here's an example (using jQuery): http://jsfiddle.net/ThiefMaster/QPxAp/
The markup:
<div id="outer">
<div id="inner"></div>
</div>
and the JS code:
$('#outer').click(function() {
alert('click');
});
$('#inner').click(function(e) {
e.stopPropagation();
});
Since events bubble, the click event on the inner element hits this element first - stopping its propagation will prevent it from ever reaching the outer element, so its click event handler only triggers if the are that belongs to the element but is not covered by the inner element is clicked.
I think this is what ThiefMaster intended to describe. In this scenario, a click on the content will do nothing but a click on the div with lots of padding will yield an action.
Basic markup:
<div id="divWithPadding" style="padding:30px;">
<div>Content content content</div>
</div>
then
click listener for content div that prevents bubbling to divWithPadding:
$("#divWithPadding > div").click(function(e){
e.stopPropagation();
});
click listener for divWithPadding that does something:
$("#divWithPadding").click(function(){
//do something
});
I've implemented an animation for my photo blog. I still have big problem because the 'body' element is activating the animation twice.
I think the problem stems from the $('body').animate. Because I think that when the body is animating, the scroll event would be activated again and thus triggering the event twice.
The problem of my code is scrolling the page up. When I scroll the page upwards. The scrollAnimatePrev will trigger and then $('body') element will animate itself. After the animation the animating variable is set to false. But the $('body') element triggers the scroll event because I guess when I set the scrollTop the scroll event is triggered. So once again currentPos is set to the $(window).scrollTop() then currentPos > previousPos returns true and !animating returns true so it will trigger the scrollAnimate.
Now I want to fix this. How?
$(function() {
var record = 0;
var imgHeight = $(".images").height();
var offset = $(".images").eq(0).offset();
var offsetHeight = offset.top;
var previousPos = $(window).scrollTop();
var animating = false;
var state = 0;
$(window).scroll(function() {
var currentPos = $(window).scrollTop();
console.log(currentPos);
if(currentPos > previousPos && !animating) {
record++;
scrollAnimate(record, imgHeight, offsetHeight);
animating = true;
} else if (currentPos < previousPos && !animating) {
record--
scrollAnimatePrev(record, imgHeight, offsetHeight);
animating = true;
}
previousPos = currentPos;
console.log(previousPos)
})
function scrollAnimate(record, imgHeight, offsetHeight) {
$('body').animate(
{scrollTop: (parseInt(offsetHeight) * (record+1)) + (parseInt(imgHeight) * record)},
1000,
"easeInOutQuart"
)
.animate(
{scrollTop: (parseInt(offsetHeight) * (record)) + (parseInt(imgHeight) * (record))},
1000,
"easeOutBounce",
function() {
animating = false;
}
)
}
function scrollAnimatePrev(record, imgHeight, offsetHeight) {
$('body').animate(
{scrollTop: ((parseInt(imgHeight) * record) + (parseInt(offsetHeight) * record)) - offsetHeight},
1000,
"easeInOutQuart"
)
.animate(
{scrollTop: ((parseInt(imgHeight) * record) + (parseInt(offsetHeight) * record))},
1000,
"easeOutBounce",
function() {
animating = false;
}
)
}
})
I think it might be firing that callback twice. I had a similar problem recently.
I had something similiar to
$('#id, #id2').animate({width: '200px'}, 100, function() { doSomethingOnceOnly(); })
It was calling my doSomethingOnceOnly() twice, and I thought it must have been the dual selectors in the $ argument. I simply made it 2 different selectors and it worked fine. So like this
$('#id').animate({width: '200px'}, 100);
$('#id2').animate({width: '200px'}, 100, function() { doSomethingOnceOnly(); );
Using a flag to control the trigger did the trick for me.
var targetOffset = 0;
var allow_trigger = true;
$('html,body').animate({scrollTop: targetOffset}, 'slow', function() {
if (allow_trigger) {
allow_trigger = false;
doSomethingOnlyOnce();
}
});