Слайдер с эффектом Ken Burns (приближение) с паузой по клику
Приветствую! Есть слайдер на swiper js. Реализован эффект приближения, но никак не могу добиться нужного результата. Смысл в том, что при клике по изображению эффект приближения должен остановиться (встать на паузу) в том же месте, где он был когда я по нему кликнул. Так же, в этот момент должен остановиться autoplay слайдера. Остановка происходит на 5 секунд, либо возобновляется при повторном клике по изображению (если 5 секунд не прошло). На данный момент клик срабатывает не так как надо, эффект приближения не останавливается, а возвращается в исходный размер, плюс не встает на паузу autoplay. Если кто-то сможет помочь, буду благодарен. Мой код:
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Swiper Slider with Zoom Effect</title> <link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css"> <style> body { margin: 0; font-family: Arial, sans-serif; } .swiper-container { width: 100%; height: 100vh; } .swiper-slide { display: flex; justify-content: center; align-items: center; overflow: hidden; } .swiper-slide img { max-width: 100%; transition: transform 5s ease-in-out; } .zoom { transform: scale(1.2); } </style> </head> <body> <div class="swiper-container"> <div class="swiper-wrapper"> <div class="swiper-slide"><img src="https://images.wallpaperscraft.com/image/single/lynx_animal_predator_1398659_1920x1080.jpg" alt=""></div> <div class="swiper-slide"><img src="https://images.wallpaperscraft.com/image/single/lake_trees_sunset_1398065_1920x1080.jpg" alt=""></div> <div class="swiper-slide"><img src="https://images.wallpaperscraft.com/image/single/field_river_trees_1399666_1920x1080.jpg" alt=""></div> </div> <div class="swiper-pagination"></div> </div> <script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script> <script> const swiper = new Swiper('.swiper-container', { loop: true, pagination: { el: '.swiper-pagination', clickable: true, }, }); let zoomInterval; let isPaused = false; function startZoom() { const activeSlide = document.querySelector('.swiper-slide-active img'); if (activeSlide) { activeSlide.classList.add('zoom'); zoomInterval = setTimeout(() => { activeSlide.classList.remove('zoom'); swiper.slideNext(); startZoom(); }, 5000); } } function stopZoom() { const activeSlide = document.querySelector('.swiper-slide-active img'); if (activeSlide) { clearTimeout(zoomInterval); activeSlide.classList.remove('zoom'); } } function togglePause() { isPaused = !isPaused; const activeSlide = document.querySelector('.swiper-slide-active img'); if (isPaused) { stopZoom(); } else { startZoom(); } } swiper.on('slideChange', () => { if (!isPaused) { stopZoom(); startZoom(); } }); document.querySelectorAll('.swiper-slide').forEach(slide => { slide.addEventListener('click', togglePause); }); // Начинаем эффект приближения startZoom(); </script> </body> </html> |
Рабочий вариант (возможно кому-то пригодится):
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Swiper Slider with Zoom Effect</title> <link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css"> <style> body { margin: 0; font-family: Arial, sans-serif; } .swiper-container { width: 100%; height: 100vh; } .swiper-slide { display: flex; justify-content: center; align-items: center; overflow: hidden; cursor: pointer; } .swiper-slide img { max-width: 100%; height: 100%; object-fit: cover; transition: none; } /* Индикатор паузы */ .pause-indicator { position: absolute; top: 20px; right: 20px; background: rgba(0, 0, 0, 0.7); color: white; padding: 10px; border-radius: 5px; font-size: 14px; z-index: 10; opacity: 0; transition: opacity 0.3s; } .pause-indicator.show { opacity: 1; } </style> </head> <body> <div class="swiper-container"> <div class="swiper-wrapper"> <div class="swiper-slide"><img src="https://images.wallpaperscraft.com/image/single/lynx_animal_predator_1398659_1920x1080.jpg" alt=""></div> <div class="swiper-slide"><img src="https://images.wallpaperscraft.com/image/single/lake_trees_sunset_1398065_1920x1080.jpg" alt=""></div> <div class="swiper-slide"><img src="https://images.wallpaperscraft.com/image/single/field_river_trees_1399666_1920x1080.jpg" alt=""></div> </div> <div class="swiper-pagination"></div> <div class="pause-indicator">Пауза (5 сек)</div> </div> <script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script> <script> const swiper = new Swiper('.swiper-container', { loop: true, autoplay: { delay: 5000, disableOnInteraction: false, }, pagination: { el: '.swiper-pagination', clickable: true, }, }); let zoomAnimationId; let zoomStartTime; let zoomDuration = 5000; // 5 секунд let isPaused = false; let pauseTimeout; let pausedProgress = 0; // Прогресс анимации на момент паузы const pauseIndicator = document.querySelector('.pause-indicator'); function animateZoom(startTime, initialProgress = 0) { const activeSlide = document.querySelector('.swiper-slide-active img'); if (!activeSlide) return; function zoom(currentTime) { if (!startTime) startTime = currentTime; const elapsed = currentTime - startTime; const totalProgress = Math.min((elapsed + initialProgress * zoomDuration) / zoomDuration, 1); // Вычисляем масштаб от 1 до 1.2 const scale = 1 + (totalProgress * 0.2); activeSlide.style.transform = `scale(${scale})`; activeSlide.style.transition = 'none'; if (totalProgress < 1 && !isPaused) { zoomAnimationId = requestAnimationFrame(zoom); } else if (totalProgress >= 1 && !isPaused) { // Анимация завершена, переходим к следующему слайду activeSlide.style.transform = 'scale(1)'; activeSlide.style.transition = 'transform 0.3s ease-out'; swiper.slideNext(); } // Сохраняем текущий прогресс pausedProgress = totalProgress; } zoomAnimationId = requestAnimationFrame(zoom); } function startZoom() { if (isPaused) return; pausedProgress = 0; zoomStartTime = performance.now(); animateZoom(); } function pauseZoom() { isPaused = true; if (zoomAnimationId) { cancelAnimationFrame(zoomAnimationId); } // Показываем индикатор паузы pauseIndicator.classList.add('show'); // Автоматическое возобновление через 5 секунд pauseTimeout = setTimeout(() => { resumeZoom(); }, 5000); } function resumeZoom() { isPaused = false; // Скрываем индикатор паузы pauseIndicator.classList.remove('show'); // Очищаем таймаут автовозобновления if (pauseTimeout) { clearTimeout(pauseTimeout); pauseTimeout = null; } // Возобновляем анимацию с сохраненного прогресса if (pausedProgress < 1) { animateZoom(performance.now(), pausedProgress); } else { // Если анимация была завершена, начинаем новую startZoom(); } // Возобновляем autoplay swiper.autoplay.start(); } function togglePause() { if (isPaused) { resumeZoom(); } else { // Останавливаем autoplay swiper.autoplay.stop(); pauseZoom(); } } // Обработчик смены слайда swiper.on('slideChange', () => { // Сбрасываем состояние предыдущего слайда document.querySelectorAll('.swiper-slide img').forEach(img => { img.style.transform = 'scale(1)'; img.style.transition = 'transform 0.3s ease-out'; }); // Очищаем анимацию if (zoomAnimationId) { cancelAnimationFrame(zoomAnimationId); } // Если не на паузе, запускаем новую анимацию if (!isPaused) { setTimeout(() => { startZoom(); }, 100); // Небольшая задержка для корректной работы } }); // Добавляем обработчики кликов document.querySelectorAll('.swiper-slide').forEach(slide => { slide.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); togglePause(); }); }); // Запускаем первую анимацию после загрузки swiper.on('init', () => { setTimeout(() => { startZoom(); }, 100); }); // Если swiper уже инициализирован if (swiper.initialized) { setTimeout(() => { startZoom(); }, 100); } </script> </body> </html> |
Часовой пояс GMT +3, время: 07:08. |