• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Info 3D Slider

Oliver77

Aktives Mitglied
Hallo, habe mich mal mit 3D-Slidern beschäftigt.
Dabei ist das entstanden:

3DSlider

Einen kleinen Trick habe ich angewendet, animiert wird das ganze mit "setInterval", wenn ich das mit 10ms durchlaufen lasse ruckelt es im Firefox.
Daher habe ich das Intervall auf 80ms gesetzt und mit "transition" die Animation flüssig gemacht.

Mit der Maus links oder rechts von der Mitte hovern und es dreht sich!

Falls jemand am Code interessiert ist, kann in den Quelltext schauen!
Über Feedback freue ich mich!
 
Zuletzt bearbeitet:
Sehr cool, gut gemacht! 3D-Sachen erfordern immer gutes räumliches Vorstellungsvermögen.
Man könnte noch dran denken, die Animation anzuhalten, wenn sich die Maus in der Mitte befindet. Oder, noch einen Schritt weiter, die Geschwindigkeit abhängig von der Mausposition in x-Richtung steuern.
Möglicher Weise könnte man das setInterval weg rationalisieren, wenn man die Webanimation-API verwendet, da sehe ich die Methoden pause(), play() und reverse(). Habe ich aber nicht vollständig durchdacht und getestet.
 
Interessante Ideen hast Du da, die " Webanimation-API " kenne ich persönlich nicht - kenne nur Animate von jQuery.
 
Ich war so frei es mal umzustellen: Steuerung von Geschwindigkeit und Richtung durch die horizontale Mausposition:
Code:
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>3D Slider</title>
    <style>
        body {
            background: #222;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 0;
            margin: 0;
        }

        #wrap {
            position: relative;
        }

        .slider3d {
            position: relative;
            width: 300px;
            height: 225px;
            transform-style: preserve-3d;
        }

        .slide-trans {
            transition: transform 0.3s;
            transition-timing-function: linear;
        }

        .slider3d>div {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            transform-style: preserve-3d;
        }

        .slider3d div img {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            object-fit: cover;
            border: 7px solid #f2f2f2;
            box-sizing: border-box;
        }

        #ovl {
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            width: 500px;
            height: 400px;
        }
    </style>
</head>

<body>
    <div id="wrap">
        <div class="slider3d">
        </div>
        <div id="ovl"></div>
    </div>
    <script>
        const duration = 10000;
        const perspective = "800px";
        const translateZ = "400px";
        const imgs = ["dia0.jpg", "dia1.jpg", "dia2.jpg", "dia3.jpg", "dia4.jpg", "dia5.jpg"];
        const folder = "images";
        const slider3D = document.querySelector(".slider3d");

        for (i = 0; i < imgs.length; i++) {
            const innerDiv = document.createElement("div");
            innerDiv.style = "transform:rotateY(" + (i * (360 / imgs.length)) + "deg) translateZ(" + translateZ + ")";
            innerDiv.innerHTML = "<img src='" + folder + "/" + imgs[i] + "'\>";
            slider3D.appendChild(innerDiv);
        }

        const transform = "perspective(" + perspective + ") rotateY(0deg)";
        slider3D.style.transform = transform;

        slider3D.classList.add("slide-trans");

        const
            rotateKeyframes = new KeyframeEffect(
                slider3D,
                [
                    { transform: 'perspective(' + perspective + ') rotateY(0deg)' },
                    { transform: 'perspective(' + perspective + ') rotateY(360deg)' }
                ],
                { duration: duration, iterations: Infinity }
            ),
            rotateKeyframesReverse = new KeyframeEffect(
                slider3D,
                [
                    { transform: 'perspective(' + perspective + ') rotateY(0deg)' },
                    { transform: 'perspective(' + perspective + ') rotateY(-360deg)' }
                ],
                { duration: duration, iterations: Infinity }
            ),
            animObj = new Animation(rotateKeyframes, document.timeline);
        animObj.playbackRate = 0;
        animObj.play();
        let
            speed;
        const
            box = document.getElementById('ovl').getBoundingClientRect();
        document.addEventListener("mousemove", (event) => {
            const
                posX = event.clientX,
                posRel = posX - (box.left + box.width / 2),
                speedNew = posRel / box.width;
            console.log(speedNew)
            if (Math.sign(speedNew) != Math.sign(speed) || speed == null) {
                animObj.currentTime = duration - animObj.currentTime % duration;
                if (Math.sign(speedNew) > 0) {
                    animObj.effect = rotateKeyframes;
                    console.log('forward')
                } else {
                    animObj.effect = rotateKeyframesReverse;
                    console.log('reverse')
                }
            }
            animObj.playbackRate = Math.abs(speedNew);
            speed = speedNew;
        });
    </script>
</body>

</html>

Was man noch machen könnte:
  • Abhängig von der vertikalen Mausposition die Bilder um die x-Achse kippen.
  • Die Bilder responsiv machen.
 
Weil ich die Aufgabe sehr interessant finde, bin ich her gegangen und habe das auf responsives Verhalten umgestellt. Damit das auch beim Größer- und Kleinerziehen des Fensters funktioniert, ohne Neuladen, musste ich die Parameter für die Animation jedes Mal neu einstellen.
Klasse finde ich, dass man die Parameter einfach bei laufender Animation ändern kann, ohne dafür anhalten und weiter machen zu müssen.
Code:
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>3D Slider</title>
    <style>
        body {
            background: #222;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 0;
            margin: 0;
        }

        #wrap {
            display: grid;
            align-items: center;
            justify-items: center;
            width: 100%;
        }

        .slider3d {
            grid-row: 1/2;
            grid-column: 1/2;
            width: 20%;
            height: auto;
            display: grid;
            transform-style: preserve-3d;
        }

        .slide-trans {
            transition: transform 0.3s;
            transition-timing-function: linear;
        }

        .slider3d>figure {
            grid-row: 1/2;
            grid-column: 1/2;
            margin: 0;
            padding: 0;
            transform-style: preserve-3d;
        }

        .slider3d figure img {
            width: 100%;
            height: auto;
            object-fit: cover;
            border: 7px solid #f2f2f2;
        }

        #ovl {
            grid-row: 1/2;
            grid-column: 1/2;
            width: 500px;
            height: 400px;
        }
    </style>
</head>

<body>
    <div id="wrap">
        <div class="slider3d">
        </div>
        <div id="ovl"></div>
    </div>
    <script>
        const
            animObj = new Animation(null, document.timeline),
            slider3D = document.querySelector('.slider3d');
        let boxOvl, rotateKeyframes, rotateKeyframesReverse, speed = 1;
        function dynStyle() {
            boxOvl = document.getElementById('ovl').getBoundingClientRect();
            const
                wSlider3D = slider3D.clientWidth,
                perspective = (wSlider3D * 3) + 'px',
                translateZ = (wSlider3D * 1.5) + 'px';
            slider3D.classList.add("slide-trans");
            const
                innerWrappers = slider3D.querySelectorAll('figure');
            for (i = 0; i < innerWrappers.length; i++) {
                innerWrappers[i].style.transform = "rotateY(" + (i * (360 / imgs.length)) + "deg) translateZ(" + translateZ + ")";
            }

            rotateKeyframes = new KeyframeEffect(
                slider3D,
                [
                    { transform: 'perspective(' + perspective + ') rotateY(0deg)' },
                    { transform: 'perspective(' + perspective + ') rotateY(360deg)' }
                ],
                { duration: duration, iterations: Infinity }
            );
            rotateKeyframesReverse = new KeyframeEffect(
                slider3D,
                [
                    { transform: 'perspective(' + perspective + ') rotateY(0deg)' },
                    { transform: 'perspective(' + perspective + ') rotateY(-360deg)' }
                ],
                { duration: duration, iterations: Infinity }
            );
            if (speed > 0) {
                animObj.effect = rotateKeyframes;
            } else {
                animObj.effect = rotateKeyframesReverse;
            }
        }
        const
            duration = 10000,
            imgs = ["dia0.jpg", "dia1.jpg", "dia2.jpg", "dia3.jpg", "dia4.jpg", "dia5.jpg"],
            folder = "images";

        for (i = 0; i < imgs.length; i++) {
            const innerWrapper = document.createElement("figure");
            innerWrapper.innerHTML = "<img src='" + folder + "/" + imgs[i] + "'\>";
            slider3D.appendChild(innerWrapper);
        }

        dynStyle();
        animObj.playbackRate = 0;
        animObj.play();
        document.addEventListener("mousemove", (event) => {
            const
                posX = event.clientX,
                posRel = posX - (boxOvl.left + boxOvl.width / 2),
                speedNew = posRel / boxOvl.width;
            console.log(speedNew)
            if (Math.sign(speedNew) != Math.sign(speed) || speed == null) {
                animObj.currentTime = duration - animObj.currentTime % duration;
                if (Math.sign(speedNew) > 0) {
                    animObj.effect = rotateKeyframes;
                    console.log('forward')
                } else {
                    animObj.effect = rotateKeyframesReverse;
                    console.log('reverse')
                }
            }
            animObj.playbackRate = Math.abs(speedNew);
            speed = speedNew;
        });
        window.addEventListener('resize', dynStyle);
    </script>
</body>

</html>
 
Da kann ich mich gar nicht mehr erinnern.
  • Bei der Google-Suche nach einem Animations-Thema?
  • Beim Stöbern auf MDN?
  • Vielleicht hat sie auch jemand anders in einem Forum erwähnt?
 
Kannst Du nochmal erläutern wie du auf die Werte 1.5 und 3 kommst?

Javascript:
 perspective = (wSlider3D * 3) + 'px',
 translateZ = (wSlider3D * 1.5) + 'px';
 
Asche auf mein Haupt: Durch Versuch und Irrtum :wink: . Mir war klar, wofür die Werte sind und dass ich sie proportional zu der Größe des Karussells einstellen musste, damit immer das selbe Aussehen entsteht. Ich bin dann von deinen Werten ausgegangen, perspective doppelt wo groß wie translateZ und habe mit den Faktoren 2 und 1 begonnen. Da waren die Items zu nahe aneinander und ich habe im zweiten Versuch 3 und 1.5 genommen. Damit hat mich dann das Aussehen zufrieden gestellt.
 
Zurück
Oben