Это происходит потому, что событие колеса может сработать с очень высокой скоростью, превышающей частоту обновления экрана.
Это означает, что для каждого кадра, нарисованного на экране, вы фактически нарисовали несколько кадров на холсте. В браузере возникают проблемы с обработкой всех этих запросов, что приводит к задержке.
Чтобы избежать этого, вы можете ограничить свое событие: выполнить ваш обратный вызов условно, только если прошло больше определенного времени, когда оно еще не было запущено.
При работе с визуальной анимацией хорошей основой для такого времени регулирования является обновление экрана. И у нас есть метод синхронизации, который делает именно это: requestAnimationFrame
.
var images = new Array();
var currentLocation = 0;
var totalImages = 200;
for (var i = 1; i < totalImages; i++) {
var img = new Image;
var slug = '000' + i;
img.src = 'https://s3.amazonaws.com/clearmotion/hero/high-min/frame' + slug.slice(-3) + '-low.jpg'
images.push(img);
}
var c = document.getElementById("background");
var ctx = c.getContext("2d");
var mouseWheel = function() {
var evt = null; // avoids a new 'draw' function generation
window.addEventListener('wheel', function(e) {
e.preventDefault(); // No scroll
if (!evt) { // if set, we already are waiting
evt = e; // store our event
requestAnimationFrame(draw); // wait next screen refresh to fire
}
});
// the throttled funtion
function draw() {
var e = evt;
var delta = Math.max(-1, Math.min(1, e.deltaY));
if (delta == -1) currentLocation += 1;
if (delta == 1) currentLocation -= 1;
if (currentLocation < 0) currentLocation = 0;
if (currentLocation >= (totalImages - 1)) currentLocation = (totalImages - 1);
setImage(currentLocation);
evt = null; // so the throttler knows we can kick again
}
}
var setImage = function(newLocation) {
if (!images[newLocation]) return;
ctx.fillRect(0, 0, c.width, c.height);
ctx.drawImage(images[newLocation], 0, 0, 1000, 1000);
}
images[0].onload = function() {
ctx.fillRect(0, 0, c.width, c.height);
ctx.drawImage(images[currentLocation], 0, 0, 1000, 1000);
mouseWheel();
};
<canvas id="background" width="1000" height="1000"></canvas>
Теперь, поскольку мы блокируем всю обработку событий, ваша анимация также может выглядеть медленнее (даже более плавной). Чтобы обойти это, вы все равно можете обновлять свои переменные так быстро, как только можете, и только ограничивать фактический чертеж.
var images = new Array();
var currentLocation = 0;
var totalImages = 200;
for (var i = 1; i < totalImages; i++) {
var img = new Image;
var slug = '000' + i;
img.src = 'https://s3.amazonaws.com/clearmotion/hero/high-min/frame' + slug.slice(-3) + '-low.jpg'
images.push(img);
}
var c = document.getElementById("background");
var ctx = c.getContext("2d");
var mouseWheel = function() {
var newLocation = null;
window.addEventListener('wheel', function(e) {
e.preventDefault(); // No scroll
// update our variable at high frequency
var delta = Math.max(-1, Math.min(1, e.deltaY));
if (delta == -1) currentLocation += 1;
if (delta == 1) currentLocation -= 1;
if (currentLocation < 0) currentLocation = 0;
if (currentLocation >= (totalImages - 1)) currentLocation = (totalImages - 1);
if (newLocation === null) { // if set, we already are waiting to draw
requestAnimationFrame(setImage);
}
newLocation = currentLocation;
});
function setImage() {
if (images[newLocation]) {
ctx.fillRect(0, 0, c.width, c.height);
ctx.drawImage(images[newLocation], 0, 0, 1000, 1000);
}
newLocation = null; // so the throttler knows we can draw again
}
}
images[0].onload = function() {
ctx.fillRect(0, 0, c.width, c.height);
ctx.drawImage(images[currentLocation], 0, 0, 1000, 1000);
mouseWheel();
};
<canvas id="background" width="1000" height="1000"></canvas>
Обратите внимание, что я обновил ваше мероприятие, чтобы использовать единственную, совместимую со спецификацией: WheelEvent .
Также обратите внимание, что вам лучше загружать видео, а не столько неподвижных изображений. Или даже конвертируйте свою оригинальную 3D-анимацию в webGL.