Edit: Wystarczy znaleźć następujący projekt na github:
https://github.com/jquery/jquery-mousewheel
Próbowałem demo i jest w stanie zgłosić mój touchpad i mysz prędkość przewijania. Może również zatrzymać przewijanie bez hacków o ustalonej pozycji: D
Zajrzę w kilka następnych dni i zobaczę, czy mogę napisać cokolwiek, co zgłasza prędkość przewijania, kierunek, prędkość, urządzenie itd. Mam nadzieję, że " m jest w stanie stworzyć wtyczkę jQuery, która może zastąpić całą przewijaną interakcję.
Zaktualizuję ten wpis, gdy będę miał więcej informacji na ten temat.
Nie można przewidzieć, gdzie skończy się przewijanie myszy.
Z drugiej strony przesuwanie ekranu dotykowego/touchpada ma pewną prędkość, która zwolni po zatrzymaniu użytkownika, jak samochód, który popchnął i zaczyna zwalniać.
Niestety, każda przeglądarka/os/sterownik/ekran dotykowy/touchpad/etc ma własną implementację dla tej spowalniającej części, więc nie możemy tego przewidzieć.
Ale możemy oczywiście napisać własną implementację.
mamy 3 implementacje, które mogą być wykonane:
A. Kierunek
B. kierunek i prędkość
C, kierunku, prędkości i prędkość
iCalender prawdopodobnie używa implementacji A.
Wykonanie A:
Wyjścia przewijać kierunek pocieszyć, użytkownik jest w stanie przewinąć +/- 1px zanim zostanie wykryty kierunek.
Demo on JSFiddle
Demo with animation on JSFiddle
(function iDirection() {
var preventLoop = true;
var currentScroll = scrollTop();
function scroll() {
if(preventLoop) {
//Get new scroll position
var newScroll = scrollTop();
//Stop scrolling
preventLoop = false;
freeze(newScroll);
//Check direction
if(newScroll > currentScroll) {
console.log("scrolling down");
//scroll down animation here
} else {
console.log("scrolling up");
//scroll up animation here
}
/*
Time in milliseconds the scrolling is disabled,
in most cases this is equal to the time the animation takes
*/
setTimeout(function() {
//Update scroll position
currentScroll = newScroll;
//Enable scrolling
unfreeze();
/*
Wait 100ms before enabling the direction function again
(to prevent a loop from occuring).
*/
setTimeout(function() {
preventLoop = true;
}, 100);
}, 1000);
}
}
$(window).on("scroll", scroll);
})();
Wykonanie B:
Wyjścia przewiń kierunek, odległość i średnia prędkość pocieszyć, użytkownik jest w stanie aby przewinąć liczbę pikseli ustawionych w zmiennej distance
.
Jeśli użytkownik przewinie szybko, mogą przewinąć jeszcze kilka pikseli.
Demo on JSFiddle
(function iDirectionSpeed() {
var distance = 50; //pixels to scroll to determine speed
var preventLoop = true;
var currentScroll = scrollTop();
var currentDate = false;
function scroll() {
if(preventLoop) {
//Set date on scroll
if(!currentDate) {
currentDate = new Date();
}
//Get new scroll position
var newScroll = scrollTop();
var scrolledDistance = Math.abs(currentScroll - newScroll);
//User scrolled `distance` px or scrolled to the top/bottom
if(scrolledDistance >= distance || !newScroll || newScroll == scrollHeight()) {
//Stop scrolling
preventLoop = false;
freeze(newScroll);
//Get new date
var newDate = new Date();
//Calculate time
var time = newDate.getTime() - currentDate.getTime();
//Output speed
console.log("average speed: "+scrolledDistance+"px in "+time+"ms");
/*
To calculate the animation duration in ms:
x: time
y: scrolledDistance
z: distance you're going to animate
animation duration = z/y * x
*/
//Check direction
if(newScroll > currentScroll) {
console.log("scrolling down");
//scroll down animation here
} else {
console.log("scrolling up");
//scroll up animation here
}
/*
Time in milliseconds the scrolling is disabled,
in most cases this is equal to the time the animation takes
*/
setTimeout(function() {
//Update scroll position
currentScroll = newScroll;
//Unset date
currentDate = false;
//Enable scrolling
unfreeze();
/*
Wait 100ms before enabling the direction function again
(to prevent a loop from occuring).
*/
setTimeout(function() {
preventLoop = true;
}, 100);
}, 1000);
}
}
}
$(window).on("scroll", scroll);
})();
Wykonanie C:
Wyjścia przewijania kierunek, dystans i szybkość konsolę, użytkownik może przewinąć ilość pikseli ustawioną w distance
zmienna.
Jeśli użytkownik przewinie szybko, mogą przewinąć jeszcze kilka pikseli.
Demo on JSFiddle
(function iDirectionSpeedVelocity() {
var distance = 100; //pixels to scroll to determine speed
var preventLoop = true;
var currentScroll = [];
var currentDate = [];
function scroll() {
if(preventLoop) {
//Set date on scroll
currentDate.push(new Date());
//Set scrollTop on scroll
currentScroll.push(scrollTop());
var lastDate = currentDate[currentDate.length - 1];
var lastScroll = currentScroll[currentScroll.length - 1];
//User scrolled `distance` px or scrolled to the top/bottom
if(Math.abs(currentScroll[0] - lastScroll) >= distance || !lastScroll || lastScroll == scrollHeight()) {
//Stop scrolling
preventLoop = false;
freeze(currentScroll[currentScroll.length - 1]);
//Total time
console.log("Time: "+(lastDate.getTime() - currentDate[0].getTime())+"ms");
//Total distance
console.log("Distance: "+Math.abs(lastScroll - currentScroll[0])+"px");
/*
Calculate speeds between every registered scroll
(speed is described in milliseconds per pixel)
*/
var speeds = [];
for(var x = 0; x < currentScroll.length - 1; x++) {
var time = currentDate[x + 1].getTime() - currentDate[x].getTime();
var offset = Math.abs(currentScroll[x - 1] - currentScroll[x]);
if(offset) {
var speed = time/offset;
speeds.push(speed);
}
}
//Output array of registered speeds (milliseconds per pixel)
console.log("speeds (milliseconds per pixel):");
console.log(speeds);
/*
We can use the array of speeds to check if the speed is increasing
or decreasing between the first and last half as example
*/
var half = Math.round(speeds.length/2);
var equal = half == speeds.length ? 0 : 1;
var firstHalfSpeed = 0;
for(var x = 0; x < half; x++) {
firstHalfSpeed += speeds[x];
}
firstHalfSpeed /= half;
var secondHalfSpeed = 0;
for(var x = half - equal; x < speeds.length; x++) {
secondHalfSpeed += speeds[x];
}
secondHalfSpeed /= half;
console.log("average first half speed: "+firstHalfSpeed+"ms per px");
console.log("average second half speed: "+secondHalfSpeed+"ms per px");
if(firstHalfSpeed < secondHalfSpeed) {
console.log("conclusion: speed is decreasing");
} else {
console.log("conclusion: speed is increasing");
}
//Check direction
if(lastScroll > currentScroll[0]) {
console.log("scrolling down");
//scroll down animation here
} else {
console.log("scrolling up");
//scroll up animation here
}
/*
Time in milliseconds the scrolling is disabled,
in most cases this is equal to the time the animation takes
*/
setTimeout(function() {
//Unset scroll positions
currentScroll = [];
//Unset dates
currentDate = [];
//Enable scrolling
unfreeze();
/*
Wait 100ms before enabling the direction function again
(to prevent a loop from occuring).
*/
setTimeout(function() {
preventLoop = true;
}, 100);
}, 2000);
}
}
}
$(window).on("scroll", scroll);
})();
funkcje pomocnicze stosowane w powyższych implementacjach:
//Source: https://github.com/seahorsepip/jPopup
function freeze(top) {
if(window.innerWidth > document.documentElement.clientWidth) {
$("html").css("overflow-y", "scroll");
}
$("html").css({"width": "100%", "height": "100%", "position": "fixed", "top": -top});
}
function unfreeze() {
$("html").css("position", "static");
$("html, body").scrollTop(-parseInt($("html").css("top")));
$("html").css({"position": "", "width": "", "height": "", "top": "", "overflow-y": ""});
}
function scrollTop() {
return $("html").scrollTop() ? $("html").scrollTop() : $("body").scrollTop();
}
function scrollHeight() {
return $("html")[0].scrollHeight ? $("html")[0].scrollHeight : $("body")[0].scrollHeight;
}
Po prostu spojrzeć na scrollify wspomniano w komentarzach, że to 10kB i wymaga haka na każdym prostym wydarzeniu: dotyk, przewijanie myszy, przyciski klawiatury itp.
To nie wydaje się zbyt przyszłościowe, kto wie, jaka interakcja użytkownika może spowodować przewijanie w przyszłości?
Z drugiej strony zdarzenie onscroll będzie zawsze wyzwalane po przewinięciu strony, więc po prostu podłączmy kod animacji, nie martwiąc się o interakcję z urządzeniem wejściowym.
Jak byś wiedział, gdy użytkownik przestanie z wyprzedzeniem? – epascarello
@epascarello Mam na myśli zasadniczo jeden gest. Mimo że nasze zwoje wyglądają na ciągłe, składają się z sekwencji dyskretnych gestów z określonymi wartościami przewijania. Inny sprzęt traktuje te gesty w inny sposób, ale gdzieś na komputerze wie, jak daleko będzie się poruszał zwój. – Robert
Możesz wspomnieć, że chodzi tu o przewijanie bezwładności/pędu, a nie zwykłe przewijanie myszy. Nie wiem, jak to zrobić. –