How to add/remove a scroll event using resize observer - javascript

I want to trigger the scroll event when the browser window is 75rem and greater and remove it when the window is smaller.
This only works but doesn't watch for window size change:
const mql = window.matchMedia("(min-width: 75rem)")
const thumb = document.querySelector(".entry-figure")
const rate = 0.5
if (mql.matches) {
document.addEventListener("scroll", () => {
thumb.style.opacity = (100 / window.scrollY) * rate
})
}
I tried the following, but it fails:
mql.addEventListener( "change", (e) => {
if (e.matches) {
document.addEventListener("scroll", () => {
thumb.style.opacity = (100 / window.scrollY) * rate
})
}
})

Related

Draggable border like Leetcode

I want to make a border like Leetcode where i can adjust left and right containers. I have googled but I could find much about my problem.
I have the following code
const divider = document.getElementById('divider');
const [divPosition, setDivPosition] = useState(window.innerWidth - 700);
useEffect(() => {
function resize(e: MouseEvent) {
console.log(e.x);
const dx = window.innerWidth - e.x;
console.log(dx);
setDivPosition(e.x);
// if (divider) divider.style.width = dx + 'px';
}
if (divider)
divider?.addEventListener(
'mousedown',
(e) => {
if (e.offsetX < 6) {
logger(e.x, String(e.offsetX));
// setDivPosition(e.offsetX);
document.addEventListener('mousemove', resize, false);
}
},
false
);
document.addEventListener(
'mouseup',
function () {
document.removeEventListener('mousemove', resize, false);
},
false
);
return () => {
if (divider)
divider.removeEventListener('mousedown', (e) => {
if (e.offsetX < 6) {
logger(e.offsetX, 'offset is');
// logger(e.x, String(e.offsetX));
// setDivPosition(e.offsetX);
// document.addEventListener('mousemove', resize, false);
}
});
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [divider]);
But it has delays and more I resize slower it gets and border gets behind mouse. Moreover, when I click and start to resize, cursor changes to normal cursor.
How can I make it exactly like leetcode's? and any resources?
I have a found a great answer for y problem: Split.js

Keeping iframe/image ratio when resizing on height

I managed to keep the iframe's ratio for when the user resizes the window on width, but I have trouble adding the logic for when the user resizes the window on height due to conflicting logic, since the resize on width already alters the height of the iframe.
This is the function that gets called when resizing:
function calculateAspectRatioFit(width, height, ratio) {
if(height) {
let width = ((length)/(Math.sqrt((1)/(Math.pow(ratio, 2)+1))));
return Math.round(width);
} else if(width) {
let height = ((width)/(Math.sqrt((Math.pow(ratio, 2)+1))));
return Math.round(height);
}
}
But I believe that the problem lies in the trigger:
const resizeHandler = (e) => {
console.log("inside ", parseInt(iframeHeight), iframeElement.offsetHeight);
if(parseInt(iframeWidth) > iframeElement.offsetWidth) {
// overwrite inline styling
iframeElement.style.cssText = 'height: ' + calculateAspectRatioFit(iframeElement.offsetWidth, null, iframeRatio) + 'px!important';
} else if (parseInt(iframeHeight) > window.innerHeight) {
iframeElement.style.cssText = 'width: ' + calculateAspectRatioFit(null, iframeElement.offsetHeight, iframeRatio) + 'px!important';
}
}
Got any solutions for this? (pen below)
https://codepen.io/Dragosb/pen/WNoeXRa?editors=0011
Solved, as per the codepen (link is the same as the one in the original post):
Added a container for the iframe (if you are using a modal, that can be the container):
const resizeHandler = (e) => {
// get container measures
let computedContainerStyling = getComputedStyle(iframeContainer);
let containerWidth = parseInt(computedContainerStyling.width);
let containerHeight = parseInt(computedContainerStyling.height);
if ( (containerWidth / iframeRatio) > containerHeight){
iframeHeight = containerHeight;
iframeWidth = containerHeight * iframeRatio;
} else {
iframeWidth = containerWidth;
iframeHeight = containerWidth / iframeRatio;
}
iframeElement.style.width = Math.floor(iframeWidth) + 'px';
iframeElement.style.height = Math.floor(iframeHeight) + 'px';
}
window.addEventListener('resize', resizeHandler, false);
https://codepen.io/Dragosb/pen/WNoeXRa?editors=0011

How can I detect window scroll ended in javascript?

I want to add a class to selected element after scroll ended. How can I detect scroll ended in JS?
HTML
<ul class="list" id="wrapper">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li id="element">7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
JS
const element = document.getElementById('element');
const y = element.getBoundingClientRect().top + window.scrollY;
window.scroll({
top: y,
behavior: 'smooth'
});
JSBIN EXAMPLE
There is natively no event to tell when a smooth-scroll ends.
There is also no standard behavior for how this smooth-scroll should occur, no defined duration, no defined timing function (Chrome uses an ease-in-out function while Firefox uses a linear one), and added to that, a smooth-scroll can be canceled in the middle by an other call to the scroll algorithm, or even have no effect at all...
So this detection is not that easy.
The best way I found for now is to start a requestAnimationFrame powered loop which will check every painting frame (right after the scroll operations), if our target is at the same position. As soon as it has been at the same position for more than two frames, we assume the scrolling ended. That's when we can check if it succeeded, simply by checking if we are at the expected position:
const trigger = document.getElementById( 'trigger' );
const scroll_forcer = document.getElementById( 'scroll_forcer' );
let scrolling = false; // a simple flag letting us know if we're already scrolling
trigger.onclick = (evt) => startScroll();
function startScroll() {
setTimeout(()=> {
scroll_forcer.classList.add( "scrolling" )
smoothScrollTo( { top: 1000 } )
.catch( (err) => {
/*
here you can handle when the smooth-scroll
gets disabled by an other scrolling
*/
console.error( 'failed to scroll to target' );
} )
// all done, lower the flag
.then( () => scroll_forcer.classList.remove( "scrolling" ) );
}, 10);
};
/*
*
* Promised based window.scrollTo( { behavior: 'smooth' } )
* #param { Element } elem
** ::An Element on which we'll call scrollIntoView
* #param { object } [options]
** ::An optional scrollToOptions dictionary
* #return { Promise } (void)
** ::Resolves when the scrolling ends
*
*/
function smoothScrollTo( options ) {
return new Promise( (resolve, reject) => {
const elem = document.scrollingElement;
let same = 0; // a counter
// last known scroll positions
let lastPos_top = elem.scrollTop;
let lastPos_left = elem.scrollLeft;
// pass the user defined options along with our default
const scrollOptions = Object.assign( {
behavior: 'smooth',
top: lastPos_top,
left: lastPos_left
}, options );
// expected final position
const maxScroll_top = elem.scrollHeight - elem.clientHeight;
const maxScroll_left = elem.scrollWidth - elem.clientWidth;
const targetPos_top = Math.max( 0, Math.min( maxScroll_top, scrollOptions.top ) );
const targetPos_left = Math.max( 0, Math.min( maxScroll_left, scrollOptions.left ) );
// let's begin
window.scrollTo( scrollOptions );
requestAnimationFrame( check );
// this function will be called every painting frame
// for the duration of the smooth scroll operation
function check() {
// check our current position
const newPos_top = elem.scrollTop;
const newPos_left = elem.scrollLeft;
// we add a 1px margin to be safe
// (can happen with floating values + when reaching one end)
const at_destination = Math.abs( newPos_top - targetPos_top) <= 1 &&
Math.abs( newPos_left - targetPos_left ) <= 1;
// same as previous
if( newPos_top === lastPos_top &&
newPos_left === lastPos_left ) {
if( same ++ > 2 ) { // if it's more than two frames
if( at_destination ) {
return resolve();
}
return reject();
}
}
else {
same = 0; // reset our counter
// remember our current position
lastPos_top = newPos_top;
lastPos_left = newPos_left;
}
// check again next painting frame
requestAnimationFrame( check );
}
});
}
#scroll_forcer {
height: 5000vh;
background-image: linear-gradient(to bottom, red, green);
background-size: 100% 100px;
}
#scroll_forcer.scrolling {
filter: grayscale(70%);
}
.as-console-wrapper {
max-height: calc( 50vh - 30px ) !important;
}
<button id="trigger">click to scroll</button>
<div id="scroll_forcer">
</div>
You could use requestAnimationFrame to detect when the scrollTop is greater than y
requestAnimationFrame is way better than setting both an interval and an event listener on scroll, for a matter of performance.
const element = document.getElementById('element');
const y = element.getBoundingClientRect().top + window.scrollY;
function checkScrollEnd() {
if ((window.scrollY || document.body.scrollTop || document.documentElement.scrollTop) < y) {
window.requestAnimationFrame(checkScrollEnd);
}
else {
alert('end of scroll')
}
}
window.requestAnimationFrame(checkScrollEnd);
window.scroll({
top: y,
behavior: 'smooth'
});
Example fiddle
Hope this will help you
<script type="text/javascript">
jQuery(
function ($) {
$(window).on("scroll", function () {
var scrollHeight = $(document).height();
var scrollPosition = $(window).height() + $(window).scrollTop();
if (scrollHeight - scrollPosition <= 180) {
// when scroll to bottom of the page
// your function to call
}
});
}
);
</script>
Solution by LINK
const onScrollStop = (callback) => {
// Make sure a valid callback was provided
if (!callback || typeof callback !== 'function') return;
// Setup scrolling variable
let isScrolling;
// Listen for scroll events
window.addEventListener('scroll', (event) => {
// Clear our timeout throughout the scroll
window.clearTimeout(isScrolling);
// Set a timeout to run after scrolling ends
isScrolling = setTimeout(() => {
// Run the callback
callback();
}, 66);
}, false);
};
onScrollStop(() => {
console.log('Scrolling has stopped.');
});
$(window).scroll(function(){
if($(window).scrollTop() + $(window).height() >= $(document).height()) {
//Your Stuff
}
});

How to stop click event on resize & load if screen width is greater than?

I am facing this problem over and over again and just don't know how to solve this. I have a click event that I would like to fire only if the screen width is less than **576px* and if a page is loaded to make this event fire.
But when I resize the browser larger than 576px the click event still works.
Can someone please help me out how can I solve this common issue that I am facing?
Thanks in advance.
My code:
const onSearchMobile = () => {
let screenWidth = window.innerWidth;
let searchIcon = document.querySelector('.main-header__search--icon');
if (screenWidth <= 576) {
console.log('Yes lower then 576');
searchIcon.addEventListener('click', () => {
console.log('clicked!');
});
}
};
window.addEventListener('resize', onSearchMobile, false);
window.addEventListener('load', onSearchMobile);
Just check the width inside event
const onSearchMobile = () => {
let screenWidth = window.innerWidth;
let searchIcon = document.querySelector('.main-header__search--icon');
searchIcon.addEventListener('click', () => {
if (screenWidth <= 576) {
console.log('clicked!');
}
});
};
window.addEventListener('resize', onSearchMobile, false);
window.addEventListener('load', onSearchMobile);
Using MediaQueryList.onchange
let searchIcon = document.querySelector('.main-header__search--icon')
let clickListener = () => console.log('clicked!')
let mql = window.matchMedia('(max-width: 576px)')
mql.addEventListener("change", (e) => {
if (e.matches) {
searchIcon.addEventListener('click', clickListener)
} else {
searchIcon.removeEventListener('click', clickListener)
}
})
You can remove eventListener:
const onSearchMobile = () => {
let screenWidth = window.innerWidth;
let searchIcon = document.querySelector('.main-header__search--icon');
if (screenWidth <= 576) {
console.log('Yes lower then 576');
searchIcon.addEventListener('click', () => {
console.log('clicked!');
});
}
else {
searchIcon.removeEventListener('click');
}
};
window.addEventListener('resize', onSearchMobile, false);
window.addEventListener('load', onSearchMobile);

Recalculating element size on window resize

How do I propely use window.addEventListener("resize", () => { }) in the case below, where I need to recalculate size on every window resize:
const viewportWidth = Math.max(
document.documentElement.clientWidth,
window.innerWidth || 0
)
const viewportHeight = Math.max(
document.documentElement.clientHeight,
window.innerHeight || 0
)
const elements = list(48, () => {
const circle = document.createElement("span")
const minSize = Math.round((viewportWidth + viewportHeight) / 72)
const maxSize = Math.round((viewportWidth + viewportHeight) / 21)
const size = random(minSize, maxSize)
Object.assign(circle.style, {
width: `${size}px`,
height: `${size}px`
})
return circle
})
For whatever reason, I’m struggling with this, and I would greatly appreciate any help.
Try this :
window.addEventListener("resize", () => {
const docHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
document.getElementById('documentHeight').innerHTML = docHeight;
});
<div id="documentHeight">
Open this demo in full page view and resize the window to get the Inner height of the document.
</div>
You may simply encapsulate the above logic within the callback function within your event listener.
For instance,
class yourClass {
constructor() {
window.addEventListener("resize", () => {
// logic to carry out recalculation
elements();
});
}
// the rest of your logic
}
Doing so will ensure that the methods/functions will be called whenever the resize event is triggered on the Window.

Categories