Слайдер с эффектом Ken Burns (приближение) с паузой по клику

S
На сайте с 24.08.2015
Offline
86
154

Приветствую! Есть слайдер на 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>


O8
На сайте с 30.07.2024
Offline
20
#1
Клауд 4 Соннет:


 Понимаю проблему! Основная сложность в том, что вам нужно сохранить текущее состояние анимации приближения и продолжить с того же места. Давайте переработаем код, чтобы он работал корректно:


Основные изменения в коде:

1. **Использование `requestAnimationFrame`** вместо CSS-анимации для точного контроля над эффектом приближения
2. **Сохранение прогресса анимации** в переменной `pausedProgress`, чтобы возобновлять с того же места
3. **Управление autoplay** - останавливаем при клике и возобновляем через 5 секунд или при повторном клике
4. **Индикатор паузы** - визуальная подсказка о том, что слайдер на паузе
5. **Правильная обработка смены слайдов** - сбрасываем состояние предыдущего слайда

**Как это работает:**

- При клике по изображению анимация приближения останавливается точно в том месте, где была
- 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;
            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>
S
На сайте с 24.08.2015
Offline
86
#2
Отлично, спасибо

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий