Начиная свою карьеру Web-программистом, столкнулся с задачей разместить видео на фоне сайта, да так, чтобы оно прокручивалось в соответствии с положением ползунка. Задание звучало примерно так: если пользователь листает вниз, то видео проигрывается вперед, если прокручивается вверх, то видео проигрывается в обратном порядке, когда прокрутка останавливается, то и и воспроизведение останавливается.
Сперва я пытался соорудить нечто на основе тега <video> что было плохой идеей, потому что всё жутко тормозило, а обработать изменение направления просто не возможно и сперва сделал это путем использованием двух роликов одинаковых по содержанию, но различных по направлению воспроизведению. А всё потому, что браузеры не могут воспроизвести в обратном порядке. В итоге всё это жестоко прыгало, одно видео постоянно выскакивало поверх другого и я уже не говорю про тормоза при воспроизведении. Что уж говорить об отзывчивости на скорость прокрутки! Ведь идеальным вариантом было бы жесткая привязка воспроизведения к движению ползунка прокрутки. запрограммировать логику наверно возможно но безумно сложно.
Позже мне показали пример сайта где подобная фишка была реализована. И вот, приступив к изучению аналога меня осенило, что подход вкорне неверен!
<canvas> — Вот что мне нужно было. Заменяем видео на последовательность изображений. На этом этапе мне пришлось немного погуглить и я нашел отличный сервис для этого: on-line конвертер видео в изображения. Он бесплатный до тех пор, пока ваше видео не превышает 100МБт. Лучше выбрать максимальное качество, потому что результат другого качества меня не устроил, уж сильно искажались цвета близкие к черному. Попробую для этого использовать пакетную обработку в GIMP.
Технология заключается в том, что мы вставляем изображения на холст тега canvas в соответствии с положением ползунка прокрутки.
Мой HTML:
1 |
<canvas width="1014px" height="600px" class="video_bg" id="canvas" style="position:fixed;"></canvas> |
width и height очень важно указать, так как в canvas они указывают на количество пикселей в холсте. И соответственно изображение на холсте автоматически масштабируется в соответствии с указанием в CSS:
1 2 3 4 5 6 7 |
.video_bg { width: 100%; height: 100%; z-index: -1000; margin-top: -10px; margin-left: -10px; } |
Указываем высоту и ширину в 100%, это же фон.
z-index, по той же причине, хотя конечно же не обязательно брать именно -1000. margin указаны в -10 пикселей из-за того, что по умолчанию canvas немного отступает от краев.
С JavaScript всё немного сложней:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
//обязательно выполняем код только после полной прогрузки документа, иначе поймаем ошибки window.onload = function() { //находим наш canvas var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); //переменная для отслеживания события окончания загрузки всех изображений браузером var VideoLoader = 0; //храним номер текущего кадра - при жесткой привязке не нужно var currentCadre = 0; //максимальное количество кадров в нашем ролике var maximalCadre = 749; //массив в котором храним наши кадры var cadre = new Array(); //далее цикл для загрузки изображений с сервера в браузер клиента for (var i = 0;i<=maximalCadre;i++) { //очень удобно будет, если все изображения будут пронумерованы в порядке очереди ;) cadre[i]= new Image(); cadre[i].src= "BGs/o_c3f9a6451dbe543f-"+i+".jpg"; //отслеживаем событие загрузок изображений cadre[i].onload = function() { VideoLoader++; if ((VideoLoader/maximalCadre)*100==100) { //Все кадры загружены! можно на этом месте выполнить произвольный код } else { //кадры еще не загружены можно выполнять произвольный код } } //Данная функция отвязывает количество пикселей в скроле и количество кадров в ролике и позволяет очень просто выбирать нужный кадр в соответсьвии с положением полосы прокрутки var ScrollPosition = function() { return parseInt((window.pageYOffset/(document.body.scrollHeight-window.innerHeight))*maximalCadre); } //во время скрола меняем кадр жесткая привязка window.onscroll = function() { context.drawImage(cadre[ScrollPosition()],0,0); } }; |
При жесткой привязке стоит помнить, что при короткой высоте страницы, ролик будет слишком быстро прокручиваться, решением будет дробление страницы на блоки и создание больших интервалов между блоками.
Если нам нужна мягка привязка, когда от скорости прокрутки не зависит скорость воспроизведения кадров. При таком раскладе прокрутив немного видео как бы догоняет пользователя и только потом останавливается. В этом случае код несколько усложняется:
Вполне возможно что его можно сократить, я его для этой статьи сократил как мог, убрав не нужную реализацию с частичным воспроизведением части ролика сразу после начала просмотра сайта. Потом мне сообщили, что нужна только жесткая привязка и я не стал отлаживать до конца этот кусок кода
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
indow.onscroll = function() { //сложные условия позволяют нам менять кадры только в том случае, если ползунок находится между минимальным и максимальным положениями if ((currentCadre >= 0) && ((VideoLoader/maximalCadre)*100>=100)) { //условие проверяет запущено ли воспроизведение ролика и если да, то останавливает его if(VideoInterval!==undefined) { clearInterval(VideoInterval); } //запуск воспроизведения var VideoInterval = window.setInterval(function() { //отрисовка кадра context.drawImage(cadre[currentCadre],0,0); //если позиция ползунка больше или равна текущему месту воспроизведения if(ScrollPosition()>=currentCadre) { if (currentCadre<maximalCadre) { currentCadre++ } else { clearInterval(VideoInterval); } } else { if (currentCadre<=0) { clearInterval(VideoInterval); } else { currentCadre--; } } if (currentCadre==ScrollPosition()) { clearInterval(VideoInterval); } },30) } else { if(VideoInterval!==undefined) { clearInterval(VideoInterval); } } } |