Scroll firing too many times and crashing chrome and opera - javascript

I wrote a program in which you drag my custom scroll bar and page scrolls accordingly, everything works fine, however while testing it I discovered that if the page is too big 20 000 pixels and you do a large scroll it will crash chrome and opera.
This is caused by window.scroll(0, whereto1); being fired too many times on drag. when i comment this line of code everything works on the large scroll obviously, except for the functionality of scrolling page while dragging.
Below is the relevant code, if anyone has any good idea on how to do this without crashing the browser on large pages let me know. Thank you very much for your time.
var $dragging = null;
var pageheight1 = $( document ).height();
$(document.body).on("mousemove", function(e) {
if ($dragging) {
var wrap = jQuery('.pvs_inner_fixedbar');
wrapoffset = wrap.offset();
wrapbottomborder = ( wrapoffset.top + wrap.height() ) - jQuery('.pvs_scroll_marker').height();
var pos = e.pageY;
if(pos < wrapoffset.top){
pos = wrapoffset.top;
}
if(pos > wrapbottomborder){
pos = wrapbottomborder;
}
$dragging.offset({
top: pos
});
var ratio1 = pageheight1 / 400;
var whereto1 = Math.round((pos - wrapoffset.top) * ratio1) - 100;
window.scroll(0, whereto1); // FIRES TOO MANY TIMES :((((
}
});
$(document.body).on("mousedown", ".pvs_scroll_marker", function (e) {
$dragging = $(e.target);
});
$(document.body).on("mouseup", function (e) {
$dragging = null;
});

You can throttle calls to window.scroll() called from mousemove event handler
https://remysharp.com/2010/07/21/throttling-function-calls

Related

Alternative of position fixed using JavaScript shows weird behavior on window resize

I have CSS transform scale on the body of my page and some other elements. The position fixed CSS property doesn't work with transform property. I tried to do the same as position fixed but with JavaScript by changing the element's top/bottom value while scrolling. This requires some calculations dynamically as you load the page on different sized screens. Mine works on different screens but when I do window resize on any screen, the fixed div behaves weirdly. It disappears and reappear again. Sometimes it doesn't fixes its position on the intended scroll-y value. I have applied "scroll" and "resize" event listeners for the body/window. I had to do some initial calculations before scroll event, so some functions are under a parent function.
JAVASCRIPT
function chekon()
{
document.addEventListener('DOMContentLoaded', upme);
window.addEventListener('resize', upme);
function upme()
{
var rome = document.getElementById("out-cmnt");
var rect = rome.getBoundingClientRect();
// console.log(rect.top, rect.right, rect.bottom, rect.left);
var poss = rect.top + window.scrollY;
var koss = rect.bottom + window.scrollY; var loss = koss - poss;
var isMobile = !(navigator.userAgentData.mobile);
// event listeners
// window.addEventListener('resize', relod, false);
// function relod() { if(isMobile) { location.reload(); } }
window.addEventListener('scroll', doso, false);
window.addEventListener('resize', doso, false);
function doso()
{
lopp = document.getElementById("Web_1920__1");
hope = lopp.clientHeight;
const meme = document.body.scrollHeight;
const keke = hope/meme;
const scsc = window.scrollY;
var scmx = (document.documentElement.scrollHeight - document.documentElement.clientHeight);
console.log("meme scroll-height = ", meme); console.log("scsc scroll-y = ", scsc);
console.log("scmx max-scroll-y = ", scmx);
var innr = window.innerHeight; console.log("innr inner-height = ", innr);
var scbb = scmx - scsc; var finn = scsc * keke; var nunn = scbb * keke;
if (window.matchMedia("(min-width: 765px)").matches)
{
var finn = scsc * keke * 1.087;
var nunn = scbb * keke * 1.087;
}
var noss = poss - innr + loss;
if(scsc > noss && window.matchMedia("(min-width: 765px)").matches && isMobile)
{
var xoxo = nunn;
document.getElementById("out-cmnt").style.top = "auto";
document.getElementById("out-cmnt").style.bottom = xoxo + "px";
}
if(scsc < noss)
{
document.getElementById("out-cmnt").style.top = "7074px";
}
if(nunn < 100 && isMobile)
{
document.getElementById("last-dab").style.visibility = "hidden";
}
if(nunn > 100 && isMobile)
{
document.getElementById("last-dab").style.visibility = "visible";
}
} }
}
chekon();
Function upme() and doso() is under function chekon() there. The upme() has 2 event listeners and doso() has also 2 event listeners with resize in common. I checked that if doso() resize isn't applied, the upme() resize event listener has no effect on doso() even though doso() is under upme() function. I though, maybe there is overlapping. But seems like fine to me. Is there something messed up in my code that is responsible for the window resize action? The "Web_1920__1" is for getting the total height of the page. The "out-cmnt" is flickering and showing up at wrong place after stopping window resize action for the browser. Then when I start scrolling again the element should get back at its intended position again. But no, staying at wrong position. A reload only fixes the problem for now. Funny thing is, I can't reproduce the wrong position even when the resize is down to at the same window size that showed the problem before. So I think Chrome is showing the problem at random window resizes. Is it browser bug or mine? Help me out please.
You can ignore the variables and calculations. Just care more for the structure, functions and event-listeners like any wrong declarations. Please help me to understand the problem.

Adjust the scrolling speed when scrolling by dragging

I have a page on a website i am working on, that includes many images in a div in a grid (map). I made the div show a scroll bar at overflow and used jquery to enable scrolling via dragging and it works as intented with only a hundred or so showing at a time.
My only issue is, that since there are thousands of small images, moving the mouse only a bit will already result in blowing past a lot of objects.
My question now is, how can i modify my code, so that moving the mouse over the screen once will only scroll about one tenth of the div's width. So basically i want to reduce the scrolling speed.
I am super new to javascript etc. so please be patient.
<div id="map" class="center unselectable overflow">
lots of images here in a grid</div>
<script>
var clicked = false, clickY, clickX;
var map = document.getElementById('map');
$(document).on({
'mousemove': function(e) {
clicked && updateScrollPos(e);
},
'mousedown': function(e) {
clicked = true;
clickY = e.pageY;
clickX = e.pageX;
},
'mouseup': function() {
clicked = false;
$('html').css('cursor', 'auto');
}
});
var updateScrollPos = function(e) {
$('html').css('cursor', 'row-resize');
$(map).scrollTop($(map).scrollTop() + (clickY - e.pageY));
$(map).scrollLeft($(map).scrollLeft() + (clickX - e.pageX));
}
</script>
TLDR: how to I reduce the drag to scroll speed in jQuery?
A little more elabouration from my comment: it seems like you are trying to dampen the scrolling speed. Mathematically, this means all you need is to reduce the value you feed to the .scrollTop() and .scrollLeft() functions. This can be done by dividing them by a set, arbitrarily determined factor, so that the transformation is linear. An example will be, if you want to dampen your scrolling speed by a factor of 10×, then you simply divide the values by 10:
var updateScrollPos = function(e) {
var scrollTop = $(map).scrollTop() + (clickY - e.pageY);
var scrollLeft = $(map).scrollLeft() + (clickX - e.pageX);
$('html').css('cursor', 'row-resize');
$(map).scrollTop(scrollTop / 10);
$(map).scrollLeft(scrollLeft / 10);
}
Pro-tip: since you are accessing $(map) several times, you can (micro)optimize your code by caching it:
var updateScrollPos = function(e) {
var $map = $(map);
var scrollTop = $map.scrollTop() + (clickY - e.pageY);
var scrollLeft = $map.scrollLeft() + (clickX - e.pageX);
$('html').css('cursor', 'row-resize');
$map.scrollTop(scrollTop / 10);
$map.scrollLeft(scrollLeft / 10);
}

Javascript window resize not firing onload

I'm working off a specific codepen which can be found here https://codepen.io/anon/pen/WXgvjR .. Its not mine.
Everything works perfect with it, except when i open the page on a mobile or change the browser width to be mobile size, its still displaying some items outside the browser window width ways, is there any way to detect a mobile or change in screen size and just display them going down?
The following is the resize code that is found in the codepen if that helps
$(window).resize(function(){
var margin=40;
var padding=15;
var columns=0;
var cWidth=300;
var windowWidth = $(window).width();
var overflow = false;
while(!overflow){
columns++;
var WidthTheory = ((cWidth*columns)+((columns+1)*padding)+margin);
if(WidthTheory > windowWidth)
overflow = true;
}
if(columns > 1)
columns--;
var GridWidth = ((cWidth*columns)+((columns+1)*padding)+margin);
if( GridWidth != $('#grid').width()){
$('#grid').width(GridWidth);
}
});
Any help would be greatly appreciated
Resizing using the Maximise, Minimise, or the Chrome DevTools Devices Buttons, etc. does not trigger the resize event properly (it triggers it before actually resizing, so it does not get the right size).
For the mobile page load, put the same code from the window resize function into the document ready function as well (I would recommend making it a function and then call the function in both to reduce duplicate code):
function setDisplayBoardSize()
{
var margin=40;
var padding=15;
var columns=0;
var cWidth=300;
var windowWidth = $(window).width();
var overflow = false;
while(!overflow){
columns++;
var WidthTheory = ((cWidth*columns)+((columns+1)*padding)+margin);
if(WidthTheory > windowWidth)
overflow = true;
}
if(columns > 1)
columns--;
var GridWidth = ((cWidth*columns)+((columns+1)*padding)+margin);
if( GridWidth != $('#grid').width()){
$('#grid').width(GridWidth);
}
}
$(window).resize(function()
{
setDisplayBoardSize();
});
$(document).ready(function()
{
setDisplayBoardSize();
});
For the min-max etc. see this stackoverflow thread:
jQuery resize() using browser maximise button
This answer specifically should help:
$(window).resize(function()
{
setTimeout(function() {
setDisplayBoardSize();
}, 100);
});

Prevent vertical scroll on swipe -vanilla JS

I wrote this code to add swipe function for an image slider. The slider is working correctly.
However when i perform a right or left swipe there is some vertical scrolling which is distracting and annoying.
I'm storing the reference to touchstart in the touch object.
And on touchend event, if vertical distance (lenY) is more than 50, i trigger preventDefault on the touchstart.
This isn't working.
Simplest option is to call preventDefault directly on touchStart. But the image slider occupies a large part of the mobile screen making scrolling down the page tricky.
I need to pass the lenY (vertical distance) to the touch start handler to prevent default action.
function triggerTouch() {
"use strict";
var tZone = document.getElementById('sl-m'),
touch = {},
startX = 0,
startY = 0,
endX = 0,
endY = 0;
if (tZone) {
tZone.addEventListener('touchstart', function (e) {
startX = e.changedTouches[0].screenX;
startY = e.changedTouches[0].screenY;
// store reference to touch event
touch.start = e;
}, false);
tZone.addEventListener('touchend', function (e) {
endX = e.changedTouches[0].screenX;
endY = e.changedTouches[0].screenY;
var lenX = Math.abs(endX - startX);
var lenY = Math.abs(endY - startY);
// check if user intended to scroll down
if (lenY < 50 && lenX > 50) {
touch.start.preventDefault();
e.preventDefault();
swipe(tZone, startX, endX);
}
}, false);
}
}
Since i haven't got an answer i am posting my own answer, hoping someone can provide the correct implementation.
I ended up using the css overflow property to temporarily disable vertical scroll.
This works perfectly though there is a small side effect. Once you swipe through the image slider, the scroll is disabled.
A swipe upwards is required to restore scroll to the page. Its not noticeable but i still want to figure the right way.
var touch = {};
window.onload = function () {
"use strict";
document.body.addEventListener("touchstart", touchHandler);
document.body.addEventListener("touchend", touchHandler);
};
function touchHandler(e) {
"use strict";
var el = e.target;
if (el.parentNode.id === "sl-m") {
if (e.type === "touchstart") {
touch.startX = e.changedTouches[0].screenX;
touch.startY = e.changedTouches[0].screenY;
} else {
touch.endX = e.changedTouches[0].screenX;
touch.endY = e.changedTouches[0].screenY;
touch.lenX = Math.abs(touch.endX - touch.startX);
touch.lenY = Math.abs(touch.endY - touch.startY);
if (touch.lenY < 20) {
// disable scroll
document.body.style.overflowY = "hidden";
// do swipe related stuff
swipe(el.parentNode);
} else {
// enable scroll if swipe was not intended
document.body.style.overflowY = "scroll";
}
}
} else {
// keep scroll enabled if touch is outside the image slider
document.body.style.overflowY = "scroll";
}
}
I want to share the solution that works for me. The above solution did not work on ios. I am sorry for my English. I do not know english.
function stop(e){
e=e || event;
e.preventDefault;
}
window.onscroll=stop(); //-->Yes, we will use it ..
For example, where you will use;
function move(event){
var finish=event.touches[0].clientX;
var verticalFinish=event.touches[0].clientY;
var diff=finish-strt;
var verticalDiff=verticalStrt-verticalFinish;
var f;
if(diff<0 && (Math.abs(diff)>Math.abs(verticalDiff)/3)){
f=verticalDiff+widthOffset;
slayt[x].style.left=diff+"px";
slayt[x].style.transition="none";
slayt[y].style.left=f+"px";
slayt[y].style.transition="none";
window.onscroll=stop(); //-->we used it here :)
}
else if(diff>0 && (Math.abs(diff)>Math.abs(verticalDiff)/3)){
f=diff-widthOffset;
slayt[x].style.left=diff+"px";
slayt[x].style.transition="none";
slayt[z].style.left=f+"px";
slayt[z].style.transition="none";
window.onscroll=stop();//-->we used it here :)
}
}
but there is a small problem. cancels if there is another function related to scrolling. return true; it does not work. I also write twice if I have a function related to the slider inside and outside the touchend.
function end(event){
//"touchend" related codes...
//bla bla
window.onscroll=function(){m=window.pageYOffset;console.log(m);if(m>=850)
{buton.style.display="block";}else{buton.style.display="none";}}
}
If it is useful, I will be happy...
Update :
I typed wrong. I want to fix. Actually, the scroll event cannot be canceled unfortunately. So the event we canceled above, scroll is not a vertical scroll event. All events.
window.onscroll=stop(); // ==>improper use
stop(); // ==> actually - Correct usage
It just needs to be written so stop().
html,
body {
overflow: hidden;
}
Did you try this?

synchronising two divs scroll is not smooth in iOS

--> Please goto Edit part of this Question
I want to synchronise scroll bar of two divs and this is how I am doing it
var div1 = document.getElementById('element1'),
div2 = document.getElementById('element2');
div1.addEventListener('touchmove', scrolled, false);
div2.addEventListener('touchmove', scrolled, false);
function getscrollTop(node) {
return node.pageYOffset || node.scrollTop;
}
function scrolled() {
var node = this, scrollTop = getscrollTop(node);
var percentage = scrollTop / (node.scrollHeight - node.clientHeight);
var other = document.getElementById({
"element1": "element2",
"element2": "element1"
}[node.id]);
other.scrollTop = percentage * (other.scrollHeight - other.clientHeight);
};
Fiddle -> used scroll instead touchmove
But the problem is it is flickering in low end devices and would like to make it smooth in event low end devices.
Edit
I have used below code to smoothen the scrolling
var children = document.querySelectorAll('.scrolldiv');
var getscrollTop = function(node) {
return node.pageYOffset || node.scrollTop;
}, toInt = function(n) {
return Math.round(Number(n));
};
window.setInterval(function() {
var scrollTop = getscrollTop(children[0]);
var percentage = scrollTop / (children[0].scrollHeight - children[0].clientHeight);
var oscrollTop = percentage * (children[1].scrollHeight - children[1].clientHeight);
// console.log(1);
children[1].scrollTop = toInt(oscrollTop);
}, 2);
It is smoother in Desktop browsers but in iOS browser, when setting second DIv's scroll it is jerking, jerking in the sense setting scrollTop once scrolling is completed, not while scrolling.
If you round your scroll value numbers to integers then this problem goes away :
http://jsfiddle.net/2Cj4S/15/
I just used a rounding function :
function toInt(n){ return Math.round(Number(n)); };
and this seems to have fixed it. Double values really confused GUI widgets like scrollbars, and 2D drawing.
I don't see why you have to calculate a new percentage here, value which you hand over to the second scroll.. that's probably the reason for the jerking.. instead you could simply take the scroll value from the first scroll and assign it directly to the other scroll.. This will remove the jerky-ness in the other scroll.. and synchronising them..
I just added the following line to the bottom of your scrolled function..
other.scrollTop = getscrollTop(node);
The modified function:-
function scrolled() {
var node = this,
scrollTop = getscrollTop(node);
var id = node.id;
var percentage = getscrollTop(node) / (node.scrollHeight - node.clientHeight);
var other = document.getElementById({
"element1": "element2",
"element2": "element1"
}[id]);
var oscrollTop = percentage * (other.scrollHeight - other.clientHeight)
//other.scrollTop = oscrollTop;
//Please note that I have commented out the above line.. and added the following line
other.scrollTop = getscrollTop(node);
};
I hope this the behaviour you were hoping for, i tested it out on jsfiddle, both scrolls are well synchronised.

Categories