Vertical scroll on mobile - hammer.js element in page - javascript

There are a million similar questions but I can't find an answer that works for me.
Here is the situation:
I have an HTML page, and within that page is an element that I am using hammer.js on.
Need to be able to scroll like this:
--->
While also being able to pinch-to-zoom (and subsequently pan on that zoomed element) on the seating chart element above.
The element itself works perfectly. I'm using doubletap, pinch, pinchend, pan, and panend on it.
Now, in the event that the element is totally zoomed out (I'm keeping track of the scale for this reason), I would like the entire page to scroll when using it on a mobile browser (aka the finger will be dragging the page up).
I have tried almost everything under the sun at this point. I can't seem to get it to manually scroll to a specific position (I have tried setting window.scrollTop and using window.scrollTo() with no results).
If someone could point me in the right direction, I'll worship you and your family for the next...say....13 days. Heck, maybe even 14.
TL;DR
- Have we pinch zoomed on the element? If so, handle panning around that element with glee!
- Are we fully zoomed out / pinched out on the element? If so, mobile users should be able to scroll the page like normal!
Thanks
Chris

You may try window.scrollTo to "simulate" normal scroll. Like so:
var currentScroll = 0;
var currentScale = 1; //"fully zoomed out" state
hammer.on("panstart", function (ev) {
currentScroll = window.scrollY;
});
hammer.on("pan", function(ev) {
if (currentScale == 1) {
//abort pan and scroll window instead
window.scrollTo(0, currentScroll + ev.deltaY * -1);
return;
}
//do stuff with pan here...
});

Related

How to create forced scrolling to anchors on a website on scroll

I have a site where I have each section as 100vh so it fills the height of the screen perfectly. The next step I wanted to implement was disabling the regular scrolling, and on scroll force the screen to jump smoothly to the top of the next 100vh section. Here is the example of this animation / feature:
https://www.quay.com.au/
I was having a hard time finding any answers for this as most things just deal with smooth scrolling when clicking on anchors, not actually forcing div relocation when the user scrolls up / down.
I just wanted to know what code I would need do this...
Thanks, been using stack overflow for a while but first post, let me know if there is anything I can do to make this more clear.
disclaimer: this solution needs some testing and probably a bit of improvements, but works for me
if you don't want to use a plugin and prefer a vanilla JavaScript solution I hacked together a small example how this can be achieved with JS features in the following codepen:
https://codepen.io/lehnerchristian/pen/QYPBbX
but the main part is:
function(e) {
console.log(e);
const delta = e.deltaY;
// check which direction we should scroll
if (delta > 0 && currentlyVisible.nextElementSibling) {
// scroll downwards
currentlyVisible = currentlyVisible.nextElementSibling;
} else if (delta < 0 && currentlyVisible.previousElementSibling) {
// scroll upwards
currentlyVisible = currentlyVisible.previousElementSibling;
} else {
return false;
}
// perform scroll
currentlyVisible.scrollIntoView({ behavior: 'smooth' });
e.preventDefault();
e.stopPropagation();
}
what it does is that it listens for the wheel event and then calls the callback, which intercepts the scroll event. inside the callback the direction is determined and then Element.scrollIntoView() is called to let the browser do the actual scrolling
check https://caniuse.com/#search=scrollintoview for browser support, if you're going for this solution

jQuery's scrollTop() behaving strange on Android browsers including Chrome

I'm having trouble with an animated scrollbar. The intended behaviour should be on clicking the nav-button, scroll with ease to the end of the page(and a little break near the end).
Now the problem on PC works perfect. On android device (I tried my phone), the scrollTop value and the ($(document.body).height() - $(window).height()) do not match. There is exactly 55px less with the scrollTop thus acting all sorts of strange... Also sometimes it works sometimes it doesn't. I've figured it has something to do with the browser bar collapsing and upsetting the value...but i can't figure it out.
I've tried the following: initializing the variables on scroll event, i've tried vanilla js that didn't work. Need help :) for reference http://www.developer.morningmood.org , also i've printed out the values on bottom of the page if it helps. Here's the code.
contactF = Math.floor($(document.body).height() - $(window).height());
$("#cont").click(function(){
if ($(document).scrollTop() < contactF && flagScroll==true){ //flag stops other buttons from beying pushed
flagScroll = false;
var inter = setInterval(function(){
var doc = $(document).scrollTop();
if (doc == contactF){ // this is the final desired position
clearInterval(inter);
flagScroll = true;
pix = 10; //pixels to jump
return;
}
if (doc >= contactF-50){ // this is a break on aproach
pix = 1;
}
$(document).scrollTop(doc + pix);
}, 10);
}
})
EDIT: also to find the bug, you nedd to scroll from the top of the page all the way to the bottom, if from the top of the page you just push the contact button it works. but if you scroll it doesn't, it upsets the value...
Had the same exact problem and spent a whole day to figure it out.
You are right about the address bar collapse on Android chrome messing it up. Turns out the jQuery function $(window).height() always reports the viewport height that is before the address bar collapses. To get the correct value, use window.innerHeight instead. You can find more information about URL bar resizing here https://developers.google.com/web/updates/2016/12/url-bar-resizing
You can also find people asking similar questions regarding the safari address bar auto-hide, the solutions are similar. Mobile Safari $(window).height() URL bar discrepancy

iOS Safari Overscrolling: Pulling down vs. bouncing

My team and me are developing a web application which bears a fixed header, that doesn't scroll.
In order to handle overscrolling on iOS, we need to detect scrolling in negative direction and reposition the fixed header as static again to make it scroll along with the rest of the page.We do this by binding a jQuery scroll handler to window:
$(window).scroll(function() {
if ($(window).scrollTop() < 0) {
// position static header postioning in order
// let the header behave correctly when overscrolling
}
});
This works well, when the page is manually pulled (dragged) down.
But as every iOS user knows, when scrolling the page from a downwards position with speed up again, it bounces (overscrolls), once it reaches its top.
In this case, our scroll handling doesn't work.
At the moment I can imagine two reasons, why this different behaviour occurs:
Rapid scrolling upwards, and making a page bounce, is too fast for Safari's JS engine to ensure a fluid handling
Is bouncing when scrolling upwards technically the same as manually pulling down a webpage? In respect to $(window).scrollTop() ?
Has anybody some hints how to make my scroll handling work in both cases?
If position:fixed in CSS isn't working for you, then you should try to make a draw loop, and every single time that loop runs, you place a horizontal offset that is equal to how far your user has scrolled.
Basically, your JS should look like this if CSS doesn't work:
var head = document.getElementById("header");
//head now has our header
head.style.position = "relative";
//and now, we can manipulate it's position
function draw(){
head.style.top = window.pageYOffset;
//all that's left to do is do this each and every frame.
}
And if you don't know how to make a draw loop, here's the code:
var frameRate = 60;
var frameCounter = (function(){
var counter = 0;
return function(){
counter ++;
if(counter > frameRate/1000){
counter -= frameRate/1000;
draw();
}
}
})();
setInterval(frameCounter, 1);
This has been resolved in iOS 9.3 New meta tag option
<meta name="viewport"content="width=device-width,shrink-to-fit=no">

Switch tabs based on mouse scroll

I would like to have a widget on a webpage containing a number of tabs. When the user scrolls the page and the widget comes in to view and he keeps scrolling down, the tabs should be activated one by one (without the page scrolling further down). Once the last tab is showing, the page should resume scrolling as usual. Is this doable using JS/jQuery?
UPDATE:
Since this seems too broad a question:
The problem is, I don't know how to use the scroll offset and prevent the page from scrolling down until I decide it can resume its normal behavior
UPDATE 2
I created This fiddle,
$(document).ready(function(){
$('#tabbed').mouseover(function(){
$(this).focus();
}).scroll(function(){
console.log("scrolling tabs");
});
$(window).scroll(function(evt){
var scrollPos = $(this).scrollTop()
console.log(scrollPos);
// BULLETPROOF WAY TO DETECT IF THE MOUSE IS OVER THE
// SCROLLABLE DIV AND GIVE IT FOCUS HERE?
});
});
it contains a long page and a scrollable div among its contents. The only problem is that the div starts catching scroll events only if I move my mouse. If I could find a bulletproof way to activate the scrolling div whenever the mouse is over it I'm there. Any ideas?
You can't prevent scrolling with javascript. Using iframes and divs with scroll will only work if the mouse is over them.
You can cancel the mouse wheel and keys events related to the scrolling, however the user will be able to scroll using the scrollbar (more here).
Another approach is leaving an empty area and fixing your widget inside this area, like in this working example
$(window).bind('scroll', function()
{
var scroll = $(window).scrollTop(),
innerHeight = window.innerHeight || $(window).height(),
fooScroll = $('#fooScroll'),
emptyArea = $('#emptyArea'),
offset = emptyArea.offset(),
fixedClass = 'fixed';
if(scroll > offset.top)
{
if(scroll < offset.top + emptyArea.height() - fooScroll.height())
{
fooScroll.addClass(fixedClass);
fooScroll.css("top", 0);
}
else
{
fooScroll.removeClass(fixedClass);
fooScroll.css("top", emptyArea.height() - fooScroll.height());
}
}
else
{
fooScroll.removeClass(fixedClass);
fooScroll.css("top", 0);
}
});
Then you can change the tabs while the page is scrolling.
You should be able to do this. You can use the jQuery scroll event to run your own code whenever the user scrolls up or down. Also, so long as you call e.preventDefault() whenever the scroll event is fired, you can prevent the whole window from scrolling up or down.

iOS touches to device's viewport x/y coordinates via Javascript

I am currently developing a webpage for an iPhone which contains a DIV element that the user can touch and drag around. In addition, when the user drags the element to the top or bottom of the device's screen, I want to automatically scroll the page up or down.
The problem I am having is trying to determine a reliable formula to get the coordinates in the onTouchMove event that coorespond with the user's finger reaching the top or the bottom of the device viewport. My current formula seems tedious and I feel there may be an easier way to do this.
My current formula to determine if the touch event has reached the bottom of the screen:
function onTouchMoveHandler(e)
{
var orientation=parent.window.orientation;
var landscape=(orientation==0 || orientation==180)?true:false;
var touchoffsety=(!landscape?screen.height - (screen.height - screen.availHeight):screen.width - (screen.width - screen.availWidth)) - e.touches[0].screenY + (window.pageYOffset * .8);
if(touchoffsety < 40) alert('finger is heading off the bottom of the screen');
}
I have done a bit of Javascript reflection on objects such as the window, document, body, e.touches to see if I could find a set of numbers that would always add up to equal the top or bottom of the screen, but without reliable success. Help with this would be greatly appreciated.
Assuming the screenY field of a touch holds the y coordinate relative to the screen-top regardless of current scroll position, your current calculation does not make a whole lot of sense to me. I hope I did not misunderstand what your trying to do.
To find out if a touch is close to the top or the bottom of the device, I would first check if screenY is close to top (top being 0), since you can work with that value directly. Then, if it's not close to top, calculate how close it is to the bottom and check that.
var touch = e.touches[0];
if (touch.screenY < 50)
{
alert("Closing in on Top");
}
else //Only do bottom calculations if needed
{
var orientation=parent.window.orientation;
var landscape=(orientation==0 || orientation==180)?true:false;
//height - (height - availHeight) is the same as just using availHeight, so just get the screen height like this
var screenHeight = !landscape ? screen.availHeight : screen.availWidth;
var bottomOffset = screenHeight - touch.screenY; //Get the distance of the touch from the bottom
if (bottomOffset < 50)
alert("Closing in on Bottom");
}
That's actually not bad. You could also use Zepto.js and its built-in touch events and .offset() method to get it a little easier:
http://zeptojs.com/#touch
http://zeptojs.com/#offset
However, I'm interested to know whether or not you actually manage to get it scrolling at the bottom, and if the performance is smooth enough to make the effect worthwhile. (frequently scrolling in iOS interrupts JavaScript really hard)

Categories