I'm trying to migrate some jQuery code to vanilla JS that modifies the mouse wheel behavior to scroll a site horizontally instead of vertically:
jQuery:
var wheel = function() {
var width = $( window ).width();
if ( width > 954 ) {
$( 'html' ).on( 'wheel', function( e ) {
e.preventDefault();
if ( Math.abs( e.originalEvent.deltaY ) >= Math.abs( e.originalEvent.deltaX ) ) {
this.scrollLeft += ( e.originalEvent.deltaY * 10 );
} else {
this.scrollLeft -= ( e.originalEvent.deltaX * 10 );
}
} );
} else {
$( 'html' ).off( 'wheel' );
}
}
wheel();
$( window ).on( 'resize', wheel );
As you can see ( if (width > 954) ), the new behavior is just set on desktops, not mobile nor tablet devices.
This is the vanilla JS code I came up with:
Vanilla JS:
var wheel = function() {
var width = window.innerWidth;
var scroll = function( e ) {
e.preventDefault();
if ( Math.abs( e.deltaY ) >= Math.abs( e.deltaX ) ) {
this.scrollLeft += ( e.deltaY * 10 );
} else {
this.scrollLeft -= ( e.deltaX * 10 );
}
}
if ( width > 954 ) {
document.documentElement.addEventListener( 'wheel', scroll );
} else {
document.documentElement.removeEventListener( 'wheel', scroll );
}
}
wheel();
window.addEventListener( 'resize', wheel );
But, when I resize the window to the tablet/mobile width, the horizontal scrolling is not disabled and I cannot scroll the site vertically. It seems as if the removeEventListener() function is not really removing my listener function.
Any ideas about what's going on here?
You are binding wheel handler many times as you resize the window. I would suggest to bind it once and then check the window width in it. Maybe something like this:
var scroll = function( e ) {
var width = window.innerWidth;
if(width <= 954) return;
e.preventDefault();
if ( Math.abs( e.deltaY ) >= Math.abs( e.deltaX ) ) {
this.scrollLeft += ( e.deltaY * 10 );
} else {
this.scrollLeft -= ( e.deltaX * 10 );
}
}
document.documentElement.addEventListener( 'wheel', scroll);
Related
I have Fixed Header ,That Work With Mouse Scroll
How Change This code That Work only With Scroll UP
function init() {
window.addEventListener( 'scroll', function( event ) {
if( !didScroll ) {
didScroll = true;
setTimeout( scrollPage, 250 ); //Scroll Page
}
}, false );
}
//Scroll Function
function scrollPage() {
var sy = scrollY();
if ( sy >= changeHeaderOn ) {
if(!$('.template-content').hasClass('fixed-active') && (!$('.header-wrapper').hasClass('slider-overlap') || $('body').hasClass('breadcrumbs-type-9') || $('body').hasClass('breadcrumbs-type-default')) )
etTheme.headerHeight('set');
classie.add( wrapper, 'fixed-active' );
setTimeout( function() {
classie.add( wrapper, 'fixed-active-animate' );
},250);
}
else {
classie.remove( wrapper, 'fixed-active' );
classie.remove( wrapper, 'fixed-active-animate' );
etTheme.headerHeight('unset');
}
didScroll = false;
}
//Scroll Position
function scrollY() {
return window.pageYOffset || docElem.scrollTop;
}
//Call Function
init();
function scrollPage() {
var sy = scrollY();
if ( sy >= changeHeaderOn && LastscrollY > sy) {
if(!$('.template-content').hasClass('fixed-active') && (!$('.header-wrapper').hasClass('slider-overlap') || $('body').hasClass('breadcrumbs-type-9') || $('body').hasClass('breadcrumbs-type-default')) )
etTheme.headerHeight('set');
classie.add( wrapper, 'fixed-active' );
setTimeout( function() {
classie.add( wrapper, 'fixed-active-animate' );
},250); //150
}
else {
classie.remove( wrapper, 'fixed-active' );
classie.remove( wrapper, 'fixed-active-animate' );
etTheme.headerHeight('unset');
}
didScroll = false;
LastscrollY = sy;
}
I have an onkeydown event that may or may not scroll the page, and may or may not set a variable. I would like to have an onscroll event that sets that variable to false. I do not want the onkeydown event to trigger the onscroll event. How can I do this?
edit: Added my code. It lets you use your left and right arrow keys to move up and down through the images on my page. Sorry it's so wide.
<script>
window.anImageHasBeenCentered = false;
window.onkeydown = function ( key )
{
var element = document.elementFromPoint ( window.innerWidth / 2, window.innerHeight / 2 );
if ( anImageHasBeenCentered ) // move to next image
{
switch ( window.event ? event.keyCode : key.keyCode )
{
case 37: element = element.parentNode.previousSibling.previousSibling.firstChild; break; // Left Arrow
case 39: element = element.parentNode.nextSibling.nextSibling.firstChild; break; // Right Arrow
default: anImageHasBeenCentered = false; element = null;
}
}
else // center current image
{
switch ( window.event ? event.keyCode : key.keyCode )
{
case 37: break; // Left Arrow
case 39: break; // Right Arrow
default: element = null;
}
}
if ( element )
{
element.scrollIntoView ( );
if ( ( window.innerHeight + window.scrollY ) < document.body.offsetHeight ) // if we are not at the bottom of the page
{
if ( element.offsetHeight < window.innerHeight ) // if the element is shorter than the screen
{ window.scrollBy ( 0, -( ( window.innerHeight - element.offsetHeight ) / 2 ) ) } // position it in the middle of the screen
}
anImageHasBeenCentered = true;
}
};
// The function I would like to add, that is unfortunately triggered by the onkeydown function.
// window.onscroll = function ( ) { anImageHasBeenCentered = false; }
</script>
I found a workaround. I don't know if I can really guarantee it will always work, but it has so far. I just used setTimeout to delay setting my variable to true until after onscroll sets it to false.
window.anImageHasBeenCentered = false;
window.onscroll = function ( ) { anImageHasBeenCentered = false; };
window.onkeydown = function ( key )
{
var element = document.elementFromPoint ( window.innerWidth / 2, window.innerHeight / 2 );
switch ( window.event ? event.keyCode : key.keyCode )
{
case 37: // Left Arrow
if ( anImageHasBeenCentered ) element = element.parentNode.previousSibling.previousSibling.firstChild;
break;
case 39: // Right Arrow
if ( anImageHasBeenCentered ) element = element.parentNode.nextSibling.nextSibling.firstChild;
break;
default: element = null;
}
if ( element )
{
element.scrollIntoView ( );
if ( ( window.innerHeight + window.scrollY ) < document.body.offsetHeight ) // if we are not at the bottom of the page
{
if ( element.offsetHeight < window.innerHeight ) // if the element is shorter than the screen
window.scrollBy ( 0, -( ( window.innerHeight - element.offsetHeight ) / 2 ) ); // position it in the middle of the screen
}
window.setTimeout ( function ( ) { anImageHasBeenCentered = true; }, 1 );
}
};
I need make a element follow another element when dragging, but with delay in the animation, is similar to "Chat heads of facebook's messenger", you know, the bubbles on Android.
This is my jQuery plugin:
// Draggable plugin
(function($) {
$.fn.drag = function(options) {
options = $.extend({
handle: null,
cursor: 'move',
draggingClass: 'dragging',
heads: null
}, options);
var $handle = this,
$drag = this;
if( options.handle ) {
$handle = $(options.handle);
}
$handle
.css('cursor', options.cursor)
.on("mousedown", function(e) {
var x = $drag.offset().left - e.pageX,
y = $drag.offset().top - e.pageY,
z = $drag.css('z-index');
$drag.css('z-index', 100000);
$(document.documentElement)
.on('mousemove.drag', function(e) {
var chats = $($(options.heads).get().reverse());
chats.each(function(i) {
$(chats[i]).css({ left: $drag.position().left - (10*i)});
$(chats[i]).css({top: $drag.position().top});
});
$drag.offset({
left: x + e.pageX,
top: y + e.pageY
});
})
.one('mouseup', function() {
$(this).off('mousemove.drag');
$drag.css('z-index', z);
var window_width = $(window).width();
var window_height = $(window).height();
var head_wpostion = $(options.heads).position().left;
var head_hposition = $(options.heads).position().top;
if( head_wpostion > (window_width / 2) )
{
$(options.heads).animate({left: (window_width-40)+"px"}, 300 );
$(options.heads).animate({left: (window_width-50)+"px"}, 300 );
}
else
{
$(options.heads).animate({left: "-15px"}, 300 );
$(options.heads).animate({left: "-5px"}, 300 );
}
if( head_hposition > (window_height - 50) )
{
$(options.heads).animate({top: (window_height-75)+"px"}, 200 );
$(options.heads).animate({top: (window_height-65)+"px"}, 200 );
}
if( head_hposition < 0 )
{
$(options.heads).animate({top: "15px"}, 150 );
$(options.heads).animate({top: "5px"}, 150 );
}
});
// disable selection
e.preventDefault();
});
};
})(jQuery);
the only way you can do that is if you position the element you want to to be dragged along relevant to the drag-able element.
My draggable div becomes draggable on touch devices, but it "flickers" to weird positions when starting to move it. Works like a charm om desktop devices but not on iPad or Android.
Any suggestions for a solution?
Thanks in advance!
Unfortunately, I can't share the code since it will go into a product, and I am not able to reproduce the issue in a jsfiddle or similar.
But I have made a fix for the draggable flickering on touch devices, which I will share here if someone else encounters the problem.
var prevPos = null, diffX, diffY, maxDiff;
$( '#draggable' ).draggable( {
...,
...,
drag: function ( event, ui ) {
if ( prevPos ) {
diffX = Math.abs( prevPos.left - ui.position.left );
diffY = Math.abs( prevPos.top - ui.position.top );
maxDiff = Math.max( diffX, diffY );
if ( maxDiff > 60 ) {
ui.position = prevPos;
}
}
prevPos = ui.position;
},
stop: function ( event, ui ) {
prevPos = null;
}
} );
With help from various websites, I've created a very simple pop-up box using javascript that contains my contact information. I'm happy with how it works, except that the popup window that appears is positioned absolutely, and I want to have it appear relative to the browser window (ie I want the pop up to appear in the centre of the browser window, regardless of where you are on the page when you click the info icon).
I'm comfortable with HTML, but not with javascript. I know that relative positioning works very differently in javascript, but I cannot get my head around how to fix this. Any advice would be appreciated.
The webpage is here: http://www.thirstlabmedia.com/
The script is as follows:
<script type="text/javascript">
function toggle( div_id ) {
var el = document.getElementById( div_id );
if( el.style.display == 'none' ) {
el.style.display = 'block';
}
else {
el.style.display = 'none';
}
}
function blanket_size( popUpDivVar ) {
if( typeof window.innerWidth != 'undefined' ) {
viewportheight = window.innerHeight;
}
else {
viewportheight = document.documentElement.clientHeight;
}
if( ( viewportheight > document.body.parentNode.scrollHeight ) && ( viewportheight > document.body.parentNode.clientHeight ) ) {
blanket_height = viewportheight;
}
else {
if( document.body.parentNode.clientHeight > document.body.parentNode.scrollHeight ) {
blanket_height = document.body.parentNode.clientHeight;
}
else {
blanket_height = document.body.parentNode.scrollHeight;
}
}
var blanket = document.getElementById( 'blanket' );
blanket.style.height = blanket_height + 'px';
var popUpDiv = document.getElementById( popUpDivVar );
popUpDiv_height = window.innerHeight / 2 - 200;
popUpDiv.style.top = popUpDiv_height + 'px';
}
function window_pos( popUpDivVar ) {
if( typeof window.innerWidth != 'undefined' ) {
viewportwidth = window.innerHeight;
}
else {
viewportwidth = document.documentElement.clientHeight;
}
if( ( viewportwidth > document.body.parentNode.scrollWidth ) && ( viewportwidth > document.body.parentNode.clientWidth ) ) {
window_width = viewportwidth;
}
else {
if( document.body.parentNode.clientWidth > document.body.parentNode.scrollWidth ) {
window_width = document.body.parentNode.clientWidth;
}
else {
window_width = document.body.parentNode.scrollWidth;
}
}
var popUpDiv = document.getElementById( popUpDivVar );
window_width = window_width / 2 - 200;
popUpDiv.style.left = window_width + 'px';
}
function popup( windowname ) {
blanket_size( windowname );
window_pos( windowname );
toggle( 'blanket' );
toggle( windowname );
}
</script>
(My apologies for placing it all on one line; the website is created through Cargo Collective, and it doesn't accept script unless it's all placed on one line).
Use CSS position : fixed:
#my-element {
position : fixed;
top : 50%;
left : 50%;
margin : -100px 0 0 -250px;
width : 500px;
height : 200px;
z-index : 1000;
}
Here is a demo: http://jsfiddle.net/huRcV/1/
This centers a 500x200px element in the viewport. The negative margins are used to center the element with respect to its dimensions. If the user scrolls the page, the element will stay centered in the viewport.
Docs for position: https://developer.mozilla.org/en/CSS/position
fixed
Do not leave space for the element. Instead, position it at a
specified position relative to the screen's viewport and doesn't move
when scrolled. When printing, position it at that fixed position on
every page.
You can do this with JavaScript but it's probably better to use the CSS version. If you do want to use jQuery here is a quick example:
var $myElement = $('#my-element');
$(window).on('scroll resize', function () {
$myElement.css({
top : ($(this).scrollTop() + ($(this).height() / 2)),
});
});
Here is a demo: http://jsfiddle.net/huRcV/ (notice that position : fixed is changed to position : absolute for this demo)