I tried by several ways to detect accurately mousewheel / DOMMouseScroll event, but it seems that the result will vary much from browser to another browser, and above all from hardware to another hardware. (ex: MacBook Magic Trackpad fires many mousewheel events, etc.)
There has been many attempts of JS library to "normalize" the wheelDelta of a mousewheel event. But many of them failed (I don't find the relevant SO question anymore but there are some that point this failure).
That's why I try now a solution without the mousewheel event, but rather onscroll event. Here is an example of scrolling / mousewheel detection with a hidden container that scrolls (#scroller), and the normal container (#fixed_container) with normal content.
As #scroller has a finite height (here 4000px), I cannot detect scrolling / mousewheel
infinitely...
How to allow endless scroll events (by setting an infinite height for #scroller? how?) ?
Code / Live demo :
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
body { overflow:hidden; }
#scroller { height: 4000px; }
#fixed_container { position:fixed; top:0px; left:0px; }
#text { position:absolute; top:100px; left:100px; }
</style>
<script type="text/javascript">
window.onscroll = function(e) {
console.log("scroll event detected! " + window.pageXOffset + " " + window.pageYOffset);
e.preventDefault();
return false;
}
</script>
</head>
<body>
<div id="scroller"></div>
<div id="fixed_container">
<div id="text">
Bonjour
</div>
</div>
</body>
</html>
"How to allow endless scroll events"
This should do it:
$(window).scroll(function() {
var st= $(window).scrollTop();
var wh= $(window).height();
var sh= $('#scroller').height();
if(sh < st+wh*2) {
$('#scroller').css({
height: st+wh*2
});
};
});
Tested in IE11, Firefox, Chrome, Opera, and Safari.
In the fiddle below, clicking adds text, so you can see it scroll:
Fiddle
Related
I am testing a page on an IPad (IOS 14.3) in portrait mode . (see code below)
I am outputting the touched Y-value of the screen.
When I tap the screen near the top the output is near 0 (depending on the thickness of finger).
When I tap the screen near the bottom the output is near 1000.
However when I swipe vertically from the top to bottom the values start from 0 but when I reach the bottom with my finger it stops near 600.
The same issue in the other directory, when I start at the bottom is shows a value around 1000 and when it reaches the top is stops around 300.
It almost seems there are missing 300px in each (vertical) direction.
Note: the X-value (horizontal swipes) is accurate, hence I've excluded it in this example. Also on Android the output from the console.log seems fine.
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1,minimum-scale=1.0, user-scalable=yes">
<style>
body,
html {
position: fixed;
width: 100%;
height: 100%;
margin: 0;
padding 0;
background-color: #AAAAAA;
}
</style>
</head>
<body>
<div style='text-align:center;font-size:25px;width:100px;border:1px solid blue;margin:auto' id='feedback'>Hello</div>
</body>
</html>
<script>
var func = function (e) {
var evt = (typeof e.originalEvent === 'undefined') ? e : e.originalEvent;
var touch = evt.touches[0] || evt.changedTouches[0];
document.getElementById('feedback').textContent = 'top:'+touch.pageY;
};
document.body.addEventListener('touchstart', func);
document.body.addEventListener('touchmove', func);
document.body.addEventListener('touchend', func);
</script>
What is the reason the with swipping vertically I am getting different results than when I touch the screen?
It was solved by changing
document.getElementById('feedback').textContent = 'top:'+touch.pageY;
into
document.getElementById('feedback').textContent =
'top:'+touch.clientY;
Although I don't quite see why these would differ in this case.
I basically want the browser to trigger a function when a section touches the top of the viewport as the user scrolls and I'm not really sure how to do this with Vanilla JS.
I've found some jQuery alternatives, but I'm just trying to figure out how Javascript works at the moment, so I'm not exactly sure where to begin or what to google for that matter.
The following example creates a page with a single div inside.
The scroll event handler uses Element.getBoundingClientRect() in order to get the div's position relative to the viewport and logs a msg to the console when the div is at or above the top edge of the viewport.
var handlerFired;
window.addEventListener('scroll', function(e){
var containerTop = document.querySelector('.container').getBoundingClientRect().top;
if (containerTop <= 0) {
if (!handlerFired) {
handlerFired = 1;
console.log('container at top of viewport or above');
}
}
if (containerTop > 0) {
handlerFired = 0;
}
});
body{
height:2000px;
}
.container{
width:300px;
height:200px;
border:5px solid red;
position: absolute;
top: 100px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class='container'> <p>scroll window ...</p> </div>
</body>
</html>
I'm working on a web app which uses simple-keyboard javascript library.
By looking at the source code, I can see that the library synchronizes its internal keyboard buffer and caret position with the input field's ones by executing some sync code (selectionStart) on certain events: keyup, mouseup, touchend.
https://github.com/hodgef/simple-keyboard/blob/master/src/lib/components/Keyboard.js#L574
On a touch device and only in Edge browser, there is an issue with it. The problem is that Edge doesn't seem to allow placing the caret by clicking somewhere within the bounds of the text, but allows the user to drag the caret cursor.
This 'dragging' doesn't seem to fire touchend event, so the input's cursor and virtual keyboard caret go out of sync.
Does anyone know if I can prevent this dragging behaviour in Edge (and allow positioning within the text with a simple touch) or if there is some Edge specific event for dragging the cursor?
Example:
/**
* This seems to work in any browser **Except** on a touch device in Edge browser
*/
document.addEventListener("keyup", caretEventHandler);
document.addEventListener("mouseup", caretEventHandler);
document.addEventListener("touchend", caretEventHandler);
function caretEventHandler(event) {
let targetTagName;
if (event.target.tagName) {
targetTagName = event.target.tagName.toLowerCase();
}
if (targetTagName === "textarea" || targetTagName === "input") {
document.querySelector(".selectionStart span").innerHTML =
event.target.selectionStart;
}
}
body {
font-family: sans-serif;
margin: 0;
}
input {
width: 100%;
height: 50px;
text-align: left;
padding-left: 10px;
}
.selectionStart {
padding: 10px;
}
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
<link href="src/styles.css" rel="stylesheet" />
</head>
<body>
<input
class="input"
value="Click anywhere in this string to get selectionStart"
/>
<div class="selectionStart">selectionStart: <span></span></div>
<script src="src/index.js"></script>
</body>
</html>
In Edge and Internet Explorer, I'm noticing a strange issue with wheel events not equating to their expected scroll amounts. Even though the deltaMode values are reported as DOM_DELTA_PIXEL (0), the number of pixels found in deltaY is greater then the number of pixels actually being scrolled in a small scrollable div.
Take this code for example:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<style>
#scroller {
width: 200px;
height: 200px;
overflow: scroll;
}
</style>
</head>
<body>
<div id="scroller">
<p>test</p><p>test</p><p>test</p><p>test</p>
<p>test</p><p>test</p><p>test</p><p>test</p>
<p>test</p><p>test</p><p>test</p><p>test</p>
</div>
<script>
(function() {'use strict';
var scroller = document.getElementById('scroller');
scroller.addEventListener('wheel', function(e) {
var scrollY = e.deltaY;
console.log('scrollY:', scrollY);
setTimeout(function() {
console.log('scroller.scrollTop:', scroller.scrollTop);
}, 250);
});
})();
</script>
</body>
</html>
In the console I'm seeing values like this:
scrollY: 101.8499984741211
scroller.scrollTop: 28
In other browsers like Chrome, these values match or are at-least very close.
So the amount actually being scrolled is not the same as what is reported. Why is this, and can we get the correct value?
The reason the values are different is because IE and Edge actually scale the DOM pixels down based on how much of the window the scrolling area being scrolled takes up.
This complicates computing the proper scaling for a browser, and since IE/Edge are the only ones doing it, you will have to use some form of user-agent sniffing.
To get the correct amount of scrolling, you need to multiply the deltaY by (scroller.clientHeight / window.innerHeight) (and likewise with deltaX).
Here is that same sample with these adjustments:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<style>
#scroller {
width: 200px;
height: 200px;
overflow: scroll;
}
</style>
</head>
<body>
<div id="scroller">
<p>test</p><p>test</p><p>test</p><p>test</p>
<p>test</p><p>test</p><p>test</p><p>test</p>
<p>test</p><p>test</p><p>test</p><p>test</p>
</div>
<script>
(function() {
'use strict';
var scroller = document.getElementById('scroller');
scroller.addEventListener('wheel', function(e) {
var deltaY = e.deltaY;
var scaleY = scroller.clientHeight / window.innerHeight;
var scrollY = deltaY * scaleY;
console.log('scrollY:', scrollY);
setTimeout(function() {
console.log('scroller.scrollTop:', scroller.scrollTop);
}, 250);
});
})();
</script>
</body>
</html>
Which gives the following output in my console:
scrollY: 28.199999577518067
scroller.scrollTop: 28
Note that scrollTop values do not have floating points, so if you want the values to match exactly, you can Math.round them.
I'm trying to use <canvas> in iPhone Safari, and if I place the element in the body, there are unused pixels to the left and top of the element. I tried specifying margin:0;padding:0 with CSS to no avail.
What's going on here?
<html>
<head>
$(document).ready(function()
{
$('#screen').attr("height", $(window).height() );
$('#screen').attr("width", $(window).width() );
//prevent scrolling
$(document).bind('touchstart touchmove', function(e)
{
e.preventDefault();
});
});
</script>
</head>
<body>
<canvas id = "screen">
</canvas>
</body>
</html>
margin,padding, and border have no effect.
Use position:absolute; top:0;left:0
add <style>* {margin:0;padding:0;border:0;position:absolute;width:100%;height:100%}</style>