How do I create a vertical scroll mousewheel function? - javascript

I've created this script:
jQuery(".resultlist").mousewheel(function(event, delta) {
this.scrollLeft -= (delta);
event.preventDefault();
});
which fires a horizontal scroll function over the .resultlist container and this is working as expected. I need to disable this on screen widths underneath 545px so I've wrapped it in a resize function.
/* Trigger Resize Script */
jQuery(document).ready(function(){
function resizeForm(){
var width = (window.innerWidth > 0) ? window.innerWidth : document.documentElement.clientWidth;
if(width > 545){
jQuery(".resultlist").mousewheel(function(event, delta) {
this.scrollLeft -= (delta);
event.preventDefault();
});
} else {
// invert
}
}
window.onresize = resizeForm;
resizeForm();
});
/* End Trigger Resize Script */
The problem I have is that the script still runs if else is true, I did start working on a function that would include and then delete a separate script based on screenwidth but this became very cumbersome and is surely not the right way to achieve this.
I need to convert the mousewheel function so that it behaves like a normal vertical scroll instead, so that I can switch between my current horizontal scroll and a normal vertical scroll inside the resize function.
How do I amend the below function to scroll vertically?
jQuery(".resultlist").mousewheel(function(event, delta) {
this.scrollLeft -= (delta);
event.preventDefault();
});

There's a lot of going on in your code. One of the misconcepts is, that it creates a ton of mousewheel listeners on the elements when resizing the window. Here's how you can achieve what you need:
'use strict';
// Allows an event handler to run only when the event has stopped to fire
function debounce(callback, delay = 200) {
let timeout;
return function() {
const context = this,
args = arguments;
window.clearTimeout(timeout);
timeout = window.setTimeout(function() {
callback.apply(context, args);
}, delay);
};
}
jQuery(document).ready(function() {
let width, dirProp;
function resizeForm() {
width = jQuery(window).width();
dirProp = (width > 545) ? 'scrollLeft' : 'scrollTop';
}
function scroll(event) {
event.preventDefault();
// Use the original event object to access WheelEvent properties
this[dirProp] += (event.originalEvent.deltaY);
}
jQuery(".resultlist").on('wheel', scroll);
jQuery(window).on('resize', debounce(resizeForm));
resizeForm();
});
.resultlist {
position: relative;
width: 200px;
height: 200px;
overflow: auto;
}
.list-content {
position: relative;
height: 500px;
width: 500px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="resultlist">
<div class="list-content">Text</div>
</div>
The code uses standard WheelEvent and a debouncer to prevent the resize event to be handled continuously (resize event fires tens of times per second during resizing). The resize handler updates width and dirProp variables, which then are used in the WheelEvent handler to determine which way to scroll the element (with the bracket notation you can use a variable as a property name).
It's notable, that the strict mode is a must with this code, otherwise the debouncer might actually consume more time than it was purposed to save.
You might want to add some kind of "scroll home" function to reset the scrollable element when the window size is changed. You can test the code at jsFiddle.

Related

How to do eventListener by holding right click using VANILLA JS

I want to display the div wherever the cursor is holding right click.
in my case i have this code
<div class="d-none" id="item"></div>
#item{
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
background: royalblue;
/* transform: translate(calc(287px - 50%), calc(77px - 50%)); */
}
.d-none{
display: none;
}
var myMouseX, myMouseY;
function getXYPosition(e) {
myMouseX = (e || event).clientX;
myMouseY = (e || event).clientY;
getPosition(myMouseX, myMouseY);
function getPosition(x, y) {
console.log('X = ' + x + '; Y = ' + y);
let div = document.querySelector("#item");
if (div.classList.contains('d-none')) {
div.classList.remove('d-none');
} else {
div.classList.add('d-none');
}
divX = x + "px";
divY = y + "px";
div.style.transform = `translate(calc(`+divX+` - 50%) , calc(`+divY+` - 50%))`;
}
}
window.addEventListener('click', function () {
getXYPosition()
})
or you can see my Fiddle
Its work on left click by default using window.addEventListener('click')
so how do i change from left click to holding right click a few seconds
The MouseEvent API (with its mousedown and mouseup events) lets us check the event.button property to learn which mouse button the user is activating. And we can keep track of how much time passes between mousedown and mouseup to decide what to do when the mouse button is released, such as running a custom showOrHideDiv function.
And the contextmenu event fires after a right-click (unless the relevant context menu is already visible, I guess.) We can suppress the default contextmenu behavior if necessary -- although this power should be used sparingly if at all.
Note that the technique used here is problematic in that it assumes the user will never use their keyboard to see the context menu, which will eventually cause accessibility snafus and other unpleasant surprises for users. This is why hijacking the default right-click behavior should be avoided if possible (maybe in favor of something like Shift + right-click) unless the user explictly opts in to the new behavior.
// Defines constants and adds main (`mousedown`) listener
const
div = document.querySelector("#item"),
RIGHT = 2,
DELAY = 150;
document.addEventListener('mousedown', forceDelay);
// Main listener sets subsequent listeners
function forceDelay(event){
// Right mouse button must be down to proceed
if(event.button != RIGHT){ return; }
// Enables contextmenu and disables custom response
document.removeEventListener('contextmenu', suppressContextMenu);
document.removeEventListener('mouseup', showOrHideDiv);
// After 150ms, disables contextmenu and enables custom response
setTimeout(
function(){
document.addEventListener('contextmenu', suppressContextMenu);
document.addEventListener('mouseup', showOrHideDiv);
},
DELAY
);
}
// The `contextmenu` event listener
function suppressContextMenu(event){
event.preventDefault();
}
// The `mouseup` event listener
function showOrHideDiv(event){
if(event.button != RIGHT){ return; }
const
x = event.clientX,
y = event.clientY;
div.classList.toggle('d-none'); // classList API includes `toggle`
div.style.transform = `translate(calc(${x}px - 50%), calc(${y}px - 50%))`;
}
#item{ position: absolute; top: 0; left: 0; width: 100px; height: 100px; background: royalblue; }
.d-none{ display: none; }
<div id="item" class="d-none"></div>
EDIT
Note: The script works properly when tested in a standalone HTML file using Chrome, but (at least with my laptop's touchpad) behaves strangely when run here in a Stack Overflow snippet. If you experience similar issues, you can paste it into a <script> element in an HTML file (with the CSS in a <style> element) to see it working.

True/False depending on screen size dynamically?

I'm following a guide that allows Google Map screen to disable scrolling depending on the screen size. The only part i'm struggling is to write a code that dynamically changes the True/False value when i resize the screen manually.
This is the website that I followed the instruction but I can't seem to write the correct syntax code to produce the dynamic true false value depending on the screen size https://coderwall.com/p/pgm8xa/disable-google-maps-scrolling-on-mobile-layout
Part of the code that i need to use:
$(window).resize()
And then:
setOptions()
So I'm struggling to combine them together.
I have tried something like this:
var dragging = $(window).width(function resize() {
if (dragging > 560) {
return true;
} else {
return false;
}
});
The article you linked to is lacking important information as it fails to mention that $ is (presumably) jQuery. But you don't need jQuery at all.
What you can use instead is the MediaQueryList. It is similar to media queries in CSS, but it is a JavaScript API.
The following is an untested example of how you might use it with a MediaQueryList event listener. It sets the initial value and listens to changes to your media query with a handler that uses setOptions from the Google Maps API.
var mql = window.matchMedia('(min-width: 560px)');
var isDraggable = mql.matches;
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
draggable: isDraggable
});
}
function mqChange(e) {
map.setOptions({draggable: !!e.matches});
}
mql.addListener(mqChange);
You could add an event listener to the resize event and set a value of your variable whenever the size of the window is changed:
var dragging = false;
window.addEventListener('resize', function(event) {
dragging = window.innerWidth > 560;
});
Since you mentioned that you want to disable scrolling when the windows size extends a certain value, it might be easier to just do this. If you try it you can see in the console that the value changes whenever you resize your window):
window.addEventListener('resize', function(event) {
console.log(window.innerWidth);
if (window.innerWidth > 560) {
// disable scrolling or do whatever you want to do
}
});
BTW, in your code you do this:
if (dragging > 560) {
return true;
} else {
return false;
}
You can simplify this to:
return dragging > 560
Which is exactly the same.
You can use this function to get the width and height on a resize of the screen.
$(window).resize(function() {
$windowWidth = $(window).width();
$windowHeight = $(window).height();
// run other functions or code
});
But, if you want to only show/hide a html element based on the screen size, you can also use plain html/css.
<div id="maps"></div>
Css:
#media only screen and (max-width: 560px) {
#maps {
display: none;
}
}
you can use the matchMedia function to run a callback whenever the media query status is changing
var mql = window.matchMedia('(min-width: 700px)');
function mediaHandler(e) {
if (e.matches) {
/* the viewport is more than 700 pixels wide */
} else {
/* the viewport is 700 pixels wide or less */
}
}
mql.addListener(mediaHandler);

Performance problems when user scrolls to bottom of the page

I have a button that's fixed on the bottom right side of the page;
.btn-this{
width: 313px;
height: 61px;
background-color: #ebb762;
position: fixed;
bottom: 0;
right: 0;
z-index: 99;
}
And so i wanted to change the position of the button from 'fixed' to 'relative' after scrolling at a certain point of the page;
Now at first i had this work out for me:
JQuery(function ($) {
var masinfo = $(".btn-this");
$(window).scroll(function () {
var scroll = $(window).scrollTop();
if (scroll >= 457) {
masinfo.css('position', 'relative');
} else {
masinfo.css({
position: 'fixed',
bottom: '0'
});
}
});
});
But then i did see that this was not a quality solution , since i would have to paste and change the code for each page, and it would never be smooth.
So i did check this two posts:
Check if a user has scrolled to the bottom
How could I add a class of "bottom" to "#sidebar" once it reaches the bottom of its parent container?
But then again , i couldn't make it work smoothly, the code works, but it executes a lot of time,
when using:
if ($(window).scrollTop() + $(window).height() > $(document).height() - 78) {
console.log('bottom');
}
the console logs "bottom" 11 times;
I tried using a debouncer, but i just didn't understand the concept or just didn't do it the right way;
Has anyone been able to do something like this?
I see 3 possible bottlenecks:
global event listener($(window).scroll()) may be attached for several times(it can be if you have SPA where navigation does not reload page and each new page set up one more handler)
scroll event handler occurs on each scroll event
... and handler freeze page until its ended - that's where passive event listeners come to rescue.
As for #2 you addressed this with debouncing but it's better to see your code(about exact debouncing logic). You may make it in wrong way so not only last event dispatch handler is called but every time(with some delay)
As for #3 jQuery does not support it yet so you need to use low-level addEventListener instead.
A debounce function limits the rate at which a function can fire. Read more about debounce function
There is one more way you can improve the performance of animations/scroll that is requestAnimationFrame
so your function can be written as
JQuery(function ($) {
var masinfo = $(".btn-this");
$(window).scroll(function () {
// If there's a timer, cancel it
if (timeout) {
window.cancelAnimationFrame(timeout);
}
// Setup the new requestAnimationFrame()
timeout = window.requestAnimationFrame(function () {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 78) {
console.log('bottom');
}
});
});
});

Manipulating the DOM using jQuery .resize()

I want to change the order of elements in the DOM based on different browser sizes.
I've looked into using intention.js but feel that it might be overkill for what I need (it depends on underscore.js).
So, i'm considering using jQuery's .resize(), but want to know if you think something like the following would be acceptable, and in line with best practices...
var layout = 'desktop';
$( window ).resize(function() {
var ww = $( window ).width();
if(ww<=767 && layout !== 'mobile'){
layout = 'mobile';
// Do something here
}else if((ww>767 && ww<=1023) && layout !== 'tablet'){
layout = 'tablet';
// Do something here
}else if(ww>1023 && layout !== 'desktop'){
layout = 'desktop';
// Do something here
}
}).trigger('resize');
I'm storing the current layout in the layout variable so as to only trigger the functions when the window enters the next breakpoint.
Media queries are generally preferred. However, if I am in a situation where I am in a single page application that has a lot of manipulation during runtime, I will use onresize() instead. Javascript gives you a bit more freedom to work with dynamically setting breakpoints (especially if you are moving elements around inside the DOM tree with stuff like append()). The setup you have is pretty close to the one I use:
function setWidthBreakpoints(windowWidth) {
if (windowWidth >= 1200) {
newWinWidth = 'lg';
} else if (windowWidth >= 992) {
newWinWidth = 'md';
} else if (windowWidth >= 768) {
newWinWidth = 'sm';
} else {
newWinWidth = 'xs';
}
}
window.onresize = function () {
setWidthBreakpoints($(this).width());
if (newWinWidth !== winWidth) {
onSizeChange();
winWidth = newWinWidth;
}
};
function onSizeChange() {
// do some size changing events here.
}
The one thing that you have not included that is considered best practice is a debouncing function, such as the one below provided by Paul Irish, which prevents repeated firing of the resize event in a browser window:
(function($,sr){
// debouncing function from John Hann
// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
};
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
}
// smartresize
jQuery.fn[sr] = function(fn){ return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
})(jQuery,'smartresize');
// usage:
$(window).smartresize(function(){
// code that takes it easy...
});
So incorporate a debouncer into your resize function and you should be golden.
In the practice is better to use Media Queries
Try this, I'm in a hurry atm and will refactor later.
SCSS:
body, html, .wrapper { width: 100%; height: 100% }
.sidebar { width: 20%; height: 500px; float: left;
&.mobile { display: none } }
.content { float: right; width: 80% }
.red { background-color: red }
.blue { background-color: blue }
.green { background-color: green }
#media all and (max-width: 700px) {
.content { width: 100%; float: left }
.sidebar { display: none
&.mobile { display: block; width: 100% }
}
}
HAML
.wrapper
.sidebar.blue
.content.red
.content.green
.sidebar.mobile.blue
On 700 px page breaks, sidebar disappears and mobile sidebar appears.
This can be much more elegant but you get the picture.
Only possible downside to this approach is duplication of sidebar.
That's it, no JS.
Ok, the reason for my original question was because I couldn't find a way to move a left sidebar (which appears first in the HTML) to appear after the content on mobiles.
Despite the comments, I still can't see how using media queries and position or display alone would reliably solve the problem (perhaps someone can give an example?).
But, it did lead me to investigate the flexbox model - display: flex, and so I have ended up using that, and specifically flex's order property to re-arrange the order of the sidebars and content area.
Good guide here - https://css-tricks.com/snippets/css/a-guide-to-flexbox/

Why resize event doesn't fire when scrollbar appears or disappears?

When browser's vertical scrollbar appears or disappears, the width of viewport or browser window changes (can be tested using jQuery's $(window).width() method), but window's resize event is not triggered. How come?
Re-size is an event that is driven by the actual browser window changing size.
What if I removed elements from my page until my content fit within the screen ? That's not a window re-size. Or if i change the overflow for the page to hidden. The scroll bars will disappear, however this again is not a re size.
What I am getting at is this: Scrollbar visibility does not necessarily mean that there was a re-size event.
Instead of resize, use overflowchanged event.
Browsers don't recognize it as resize. Then if you need "scrollbar appeared" and "scrollbar disappeared" events, use this code:
<div id="footerDiv" style="float: left; height: 1px; width: 100%;"></div>
bodywidth = 0;
$(document).ready(function () {
bodywidth = $("#footerDiv").width();
setInterval(scrollbarHelper, 100);
});
function scrollbarHelper() {
var newwidth = $("#footerDiv").width();
if (bodywidth !== newwidth) {
if (bodywidth > newwidth) {
alert("Scrollbar Appeared");
// Your code here
}
else if (bodywidth < newwidth) {
alert("Scrollbar Disppeared");
// Your code here
}
bodywidth = newwidth;
}
}

Categories