Benutzerdefinierter Effekt, der ein 3D-Rad mit Swiper 5 simuliert

9

Ich muss ein Karussell mit 12 Elementen bauen, die ein unendlich rotierendes 3D-Rad simulieren. Um klar zu sein, muss ich genau diesen Effekt erzeugen:

https://codepen.io/SitePoint/pen/yXWXaw ( hier zu finden )

Aber mit diesen zusätzlichen Funktionen (insbesondere auf dem Desktop und auf Mobilgeräten):

  1. Folien müssen Schritt für Schritt dem Wischen folgen, dh Folien sollten sich während des Wischens bewegen (wie dies bei Swiper der Fall ist).
  2. Mit einem schnellen Wischen sollte es viele Folien mit Schwung scrollen (wie es Swiper tut freeScroll).
  3. Wenn sich das Rad dann nicht mehr dreht, rastet es am vorderen Schlitten ein (wie Swiper es mit freeModeStickyund tut centeredSlides), dass es das vom Benutzer ausgewählte ist.
  4. Ich benötige jedes Mal einen Rückruf, wenn sich die Folie ändert (ereignisähnlich slideChanged) (wie bei Swiper).

Aus all diesen Gründen dachte ich, Swiper 5.3.0 wäre ein guter Ausgangspunkt.

Ich habe verschiedene Problemumgehungen versucht, die bessere ist mit diesem Setup, aber die loop: trueist eine schreckliche Problemumgehung und verursacht Probleme (siehe Kommentare):

  var swiper = new Swiper(el_class, {
    slidesPerView: 1.5,
    spaceBetween: 25,
    centeredSlides: true,
    grabCursor: true,
    speed: 550,
    loop: true, // <== repeat infinitely the 12 items. with fast scroll at the end of a cycle it waits a while before render the next cycle. Awful
    loopAdditionalSlides: 10, 

    // Free mode
    freeMode: true, // <== free scrolling. Good
    freeModeMomentumRatio: 1,
    freeModeMomentumVelocityRatio: 1.5,
    freeModeMomentumBounceRatio: 1,
    freeModeMinimumVelocity: 0.02,
    freeModeSticky: true, // <== snap to the slides. Good

    // Touch Resistance
    resistanceRatio: 0.85,

    // Prevent blurry texts
    roundLengths: true,

  });

Auf jeden Fall nicht der richtige Weg.

Ich denke , der richtige Weg ist , eine benutzerdefinierte swiper zu entwickeln effect(wie die eingebauten in cubeEffect, coverflowEffect...) , dass das Rad simuliert, ohne loop:truedass Ursachen Probleme. Hier erstellt beispielsweise ein Typ seinen eigenen benutzerdefinierten Effekt, den er dann im effectAttribut von Swiper festlegt: https://codepen.io/paralleluniv3rse/pen/yGQjMv

...
effect: "myCustomTransition",
...

Wie entwickle ich einen benutzerdefinierten Effekt wie das 3D-Rad, das ich brauche?

Fred K.
quelle
Ich frage mich, ob es am besten wäre, mit diesem Effekt als Ausgangspunkt zu arbeiten: swiperjs.com/demos/240-effect-coverflow.html . Ich bin neugierig darauf, die "vergangenen Folien" auf einer negativen x-Achse zu verschieben, um zur Wiedereinführung in die Show auf die rechte Seite des Schiebereglers zurückzukehren ...
Phlume
1
@Phlume Ich habe bereits versucht, coverflowEffectals Ausgangspunkt zu arbeiten und seine Parameter zu "hacken", aber es ist nur eine Problemumgehung, und ich kann den Effekt des ersten Codepens nicht erzielen. Die Folien werden einfach nicht auf einer kreisförmigen Oberfläche platziert.
Fred K
Entschuldigung, können Sie klarstellen, was Sie tun möchten? Möchten Sie, dass das Karussell drehbar ist, ohne auf die Schaltflächen Zurück / Weiter zu klicken?
Mukyuu
1
@ Mukyuu Aktualisierter Fragenbeitrag mit Details
Fred K

Antworten:

2

Ich denke, das ist was Sie wollen: https://codepen.io/mukyuu/pen/GRgPYqG .

Es hat Ihre Bedingungen fast erfüllt, außer dass Swiper 5 und Snap nicht verwendet werden.

  1. Es dreht sich mit der Richtung des Wischens.
  2. Mit einem schnellen Wischen sollten viele Folien mit Schwung gescrollt werden (wie es Swiper tut).
  3. Wenn sich das Rad dann nicht mehr dreht, rastet es auf einem Schlitten ein (wie es Swiper tut).
  4. In der ontouchFunktion gibt es einen Rückruf.

HTML:

<div class="carousel" id="wrapper">
    <figure>
    <img src="https://source.unsplash.com/7mUXaBBrhoA/800x533" alt="">
    <img src="https://source.unsplash.com/bjhrzvzZeq4/800x533" alt="">
        <img src="https://source.unsplash.com/EbuaKnSm8Zw/800x533" alt="">
        <img src="https://source.unsplash.com/kG38b7CFzTY/800x533" alt="">
        <img src="https://source.unsplash.com/nvzvOPQW0gc/800x533" alt="">
        <img src="https://source.unsplash.com/mCg0ZgD7BgU/800x533" alt="">
    <img src="https://source.unsplash.com/1FWICvPQdkY/800x533" alt="">
        <img src="https://source.unsplash.com/VkwRmha1_tI/800x533" alt="">
    </figure>
</div>

S (CSS):

body {
    margin: 0;
    font-family: 'Roboto';
    font-size: 16px;

    display: flex;
    flex-direction: column;
    height: 100vh;
    justify-content: center;
}

// Carousel configuration parameters
$n: 8;
$item-width: 400px;
$item-separation: 80px;
$viewer-distance: 500px;

// Derived variables
$theta: 2 * 3.141592653589793 / $n; 
$apothem: 482.842712474619px;

.carousel {
    padding: 20px;

    perspective: $viewer-distance;
    overflow: hidden;

    display: flex;
    flex-direction: column;
    align-items: center;
    > * {
        flex: 0 0 auto;
    }

    figure {
        cursor: grab;
        margin: 0;

        width: $item-width;
        transform-style: preserve-3d;
        transition: transform 0.5s;
        transform-origin: 50% 50% (-$apothem);

        img {
            width: 100%;
            box-sizing: border-box;
            padding: 0 $item-separation / 2;

            opacity: 0.9;

            &:not(:first-of-type) {
                position: absolute;
                left: 0;
                top: 0;
                transform-origin: 50% 50% (-$apothem);
            }

            @for $i from 2 through $n {
                &:nth-child(#{$i}) {
                    transform: rotateY(#{($i - 1) * $theta}rad);
                }
            }
        }
    }

    nav {
        display: flex;
        justify-content: center;
        margin: 20px 0 0;

        button {
            flex: 0 0 auto;
            margin: 0 5px;

            cursor: pointer;

            color: #333;
            background: none;
            border: 1px solid;
            letter-spacing: 1px;
            padding: 5px 10px;
        }
    }
}

JS:

var
    carousel = document.querySelector('.carousel'),
    figure = carousel.querySelector('figure'),
    nav = carousel.querySelector('nav'),
    numImages = figure.childElementCount,
    theta =  2 * Math.PI / numImages,
    currImage = 0
;

// add touch detect:
function ontouch(el, callback){
 // Modified from http://www.javascriptkit.com/javatutors/touchevents3.shtml
    var touchsurface = el,
    dir,
    swipeType,
    startX,
    startY,
    distX,
    distY,
    threshold = 150, //required min distance traveled to be considered swipe
    restraint = 100, // maximum distance allowed at the same time in perpendicular direction
    allowedTime = 500, // maximum time allowed to travel that distance
    elapsedTime,
    startTime,
    handletouch = callback || function(evt, dir, phase, swipetype, distance){}

    touchsurface.addEventListener('touchstart', function(e){
        var touchobj = e.changedTouches[0]
        dir = 'none'
        swipeType = 'none'
        dist = 0
        startX = touchobj.pageX
        startY = touchobj.pageY
        startTime = new Date().getTime() // record time when finger first makes contact with surface
        handletouch(e, 'none', 'start', swipeType, 0) // fire callback function with params dir="none", phase="start", swipetype="none" etc
        e.preventDefault()

    }, false)

    touchsurface.addEventListener('touchmove', function(e){
        var touchobj = e.changedTouches[0]
        distX = touchobj.pageX - startX // get horizontal dist traveled by finger while in contact with surface
        distY = touchobj.pageY - startY // get vertical dist traveled by finger while in contact with surface
        if (Math.abs(distX) > Math.abs(distY)){ // if distance traveled horizontally is greater than vertically, consider this a horizontal movement
            dir = (distX < 0)? 'left' : 'right'
            handletouch(e, dir, 'move', swipeType, distX) // fire callback function with params dir="left|right", phase="move", swipetype="none" etc
        }
        else{ // else consider this a vertical movement
            dir = (distY < 0)? 'up' : 'down'
            handletouch(e, dir, 'move', swipeType, distY) // fire callback function with params dir="up|down", phase="move", swipetype="none" etc
        }
        e.preventDefault() // prevent scrolling when inside DIV
    }, false)

    touchsurface.addEventListener('touchend', function(e){
        var touchobj = e.changedTouches[0]
        elapsedTime = new Date().getTime() - startTime // get time elapsed
        if (elapsedTime <= allowedTime){ // first condition for awipe met
            if (Math.abs(distX) >= threshold && Math.abs(distY) <= restraint){ // 2nd condition for horizontal swipe met
                swipeType = dir // set swipeType to either "left" or "right"
            }
            else if (Math.abs(distY) >= threshold && Math.abs(distX) <= restraint){ // 2nd condition for vertical swipe met
                swipeType = dir // set swipeType to either "top" or "down"
            }
        }
        // Fire callback function with params dir="left|right|up|down", phase="end", swipetype=dir etc:
        handletouch(e, dir, 'end', swipeType, (dir =='left' || dir =='right')? distX : distY)
        e.preventDefault()
    }, false)
}
function DoSomething(dir, distance) {
  //modifiy this function for wheel rotation (prev/next) images
  var momentum = 100; // modify this value for how much momentum expected to switch to next/prev images
  switch (dir){
    case 'left':
    case 'right':
      currImage+= Math.round(distance/momentum);
      break;
  }
    figure.style.transform = `rotateY(${currImage * -theta}rad)`;
}
document.getElementById('wrapper').ondragstart = function() { return false; }; // prevent image dragged on mouse drag
window.addEventListener('load', function() {
  var dir, phase, el = document.getElementById('wrapper'),
    position = {
      X: 0,
      Y: 0
    };

  el.onmousedown = function(down) {
    position.X = down.clientX;
    position.Y = down.clientY;
  };

  el.onmouseup = function(up) {
    distX = up.clientX - position.X; // get horizontal dist traveled by finger while in contact with surface
    distY = position.Y - up.clientY; // get vertical dist traveled by finger while in contact with surface
    if (Math.abs(distX) > Math.abs(distY)) { // if distance traveled horizontally is greater than vertically, consider this a horizontal movement
      dir = (distX < 0) ? 'left' : 'right';
      distance = distX;
    } else { // else consider this a vertical movement
      dir = (distY < 0) ? 'down' : 'up';
      distance = distY;
    }
    dir = (distance == 0) ? 'none' : dir;
    DoSomething(dir, distance); // simulate touch from mouse control
  }; 
  ontouch(el, function(evt, dir, phase, swipetype, distance){
 // evt: contains original Event object
 // dir: contains "none", "left", "right", "top", or "down"
 // phase: contains "start", "move", or "end"
 // swipetype: contains "none", "left", "right", "top", or "down"
 // distance: distance traveled either horizontally or vertically, depending on dir value

 if ( phase == 'end' && (dir =='left' || dir == 'right') ) // on succesful swipe
   DoSomething(dir, distance);
})
}, false)

Getestet in Android 9 und Windows 10 Browsern.

Mukyuu
quelle
3
uhhh .. Ich wische von links nach rechts und das Rad dreht sich nach links .... sieht aber cool aus
Tschallacka
2
In der Zwischenzeit sehr, sehr danke für Ihre Antwort, aber es reagiert nicht auf viele Anforderungen: 1) Wie von @Tschallacka angegeben, dreht es sich in umgekehrter Richtung. 2) Die Folien folgen nicht dem Wischen. Die Folien sollten die Wischbewegungen während des Wischens bewegen (wie dies bei Swiper der Fall ist). 3) Mit einem schnellen Wischen sollten viele Folien mit Schwung gescrollt werden (wie es Swiper tut). 4) Wenn sich das Rad nicht mehr dreht, rastet es auf einem Schlitten ein (wie es Swiper tut). 5) Ich brauche einen Rückruf bei einem Ereignis wie slideChanged(wie Swiper). Aus all diesen Gründen dachte ich, Swiper wäre ein guter Ausgangspunkt ...
Fred K
Notiert. Ich habe die Drehungen in umgekehrter Richtung geändert und etwas Schwung hinzugefügt. Ich werde versuchen zu sehen, was ich mit den Swiperjs anfangen könnte. Sagen Sie mir, wenn etwas verbessert werden muss.
Mukyuu