स्क्रॉल पर रिश्तेदार से निश्चित तत्व


9

मैंने एक रैपर बनाया है जिसमें मैंने अपने Airpods प्रो पेज पर Apple जैसा ही प्रभाव डाला है । यह मूल रूप से एक वीडियो है, जब मैं स्क्रॉल करता हूं तो वीडियो बिट द्वारा बिट प्ले करता है। वीडियो की स्थिति तय हो गई है, इसलिए पाठ अच्छी तरह से उस पर स्क्रॉल करता है। हालाँकि, पाठ केवल तभी दिखाई देता है जब किसी विशिष्ट विभाजन (पाठ-प्रदर्शन) की भरपाई के बीच होता है।

वह हिस्सा ठीक काम करता है। अब मैं चाहता हूं कि जब उपयोगकर्ता ने वीडियो के अंत तक स्क्रॉल किया है, और इस तरह एनीमेशन समाप्त हो गया है, तो यह है कि वीडियो-प्रभाव-आवरण एक निश्चित स्थिति से एक सापेक्ष स्थिति में जाता है। तो वह वेबसाइट वीडियो-एनीमेशन के बाद सामान्य रूप से इसे स्क्रॉल कर देगी

JSFIDDLE CODE + DEMO

यह एक उदाहरण है जो मैंने पहले ही कोशिश की थी:

        //If video-animation ended: Make position of video-wrapper relative to continue scrolling
        if ($(window).scrollTop() >= $("#video-effect-wrapper").height()) {
            $(video).css("position", "relative");
            $("#video-effect-wrapper .text").css("display", "none");
        }

इस तरह के काम करता है ... लेकिन चिकनी को छोड़कर सब कुछ है। और वेबपेज को पीछे की तरफ स्क्रॉल करना भी संभव होना चाहिए।

इस समस्या को ठीक करने का प्रयास करते समय मुझे जो समस्याएँ आईं:

  • स्क्रॉलिंग, और निश्चित से रिश्तेदार में संक्रमण प्राकृतिक और सहज महसूस करने की जरूरत है
  • आवरण अपने आप ठीक नहीं होता है और इसमें .text तत्व होते हैं, वीडियो को ठीक किया जाता है। इसलिए .text तत्व वीडियो तत्व पर जा सकते हैं (प्रभाव पैदा कर रहे हैं)। ये .text तत्व समस्या का समाधान खोजने की कोशिश करते हैं

जवाबों:


3

Airpods Pro पेज पर कुछ रिवर्स इंजीनियरिंग करते समय, हम देखते हैं कि एनीमेशन एक का उपयोग नहीं करता है video, लेकिन ए canvas। कार्यान्वयन इस प्रकार है:

  • HTTP2 पर लगभग 1500 छवियों को प्रीलोड करें, वास्तव में एनीमेशन के फ्रेम
  • के रूप में छवियों की एक सरणी बनाएँ HTMLImageElement
  • प्रत्येक scrollDOM ईवेंट पर प्रतिक्रिया करें और निकटतम छवि के अनुरूप एनीमेशन फ़्रेम का अनुरोध करेंrequestAnimationFrame
  • एनिमेशन फ़्रेम अनुरोध में कॉलबैक, छवि का उपयोग करके प्रदर्शित करें ctx.drawImage( तत्व का संदर्भ ctxहोने के नाते )2dcanvas

requestAnimationFrameसमारोह आप एक चिकनी प्रभाव को प्राप्त के रूप में फ्रेम आस्थगित और लक्ष्य स्क्रीन के दर "प्रति सेकंड फ्रेम" के साथ सिंक्रनाइज़ किया जाएगा मदद करनी चाहिए।

स्क्रॉल इवेंट पर फ़्रेम को ठीक से कैसे प्रदर्शित किया जाए, इस बारे में अधिक जानकारी के लिए, आप इसे पढ़ सकते हैं: https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event

कहा जा रहा है, आपकी मुख्य समस्या के विषय में, मेरे पास एक कार्यशील समाधान है जिसमें निम्न शामिल हैं:

  • videoतत्व की तुलना में समान ऊँचाई और चौड़ाई का एक प्लेसहोल्डर बनाना । इसका उद्देश्य absoluteस्थिति में सेट होने पर बाकी HTML को ओवरलैप करने के लिए वीडियो से बचना है
  • में scrollघटना कॉलबैक, जब प्लेसहोल्डर व्यूपोर्ट के शीर्ष तक पहुँच जाता है, करने के लिए वीडियो की स्थिति को सेट absolute, और सही topमूल्य

विचार यह है कि वीडियो हमेशा प्रवाह से बाहर रहता है, और नीचे की ओर स्क्रॉल करने पर सही समय पर प्लेसहोल्डर के ऊपर होता है।

यहाँ जावास्क्रिप्ट है:

//Get video element
let video = $("#video-effect-wrapper video").get(0);
video.pause();

let topOffset;

$(window).resize(onResize);

function computeVideoSizeAndPosition() {
    const { width, height } = video.getBoundingClientRect();
    const videoPlaceholder = $("#video-placeholder");
    videoPlaceholder.css("width", width);
    videoPlaceholder.css("height", height);
    topOffset = videoPlaceholder.position().top;
}

function updateVideoPosition() {
    if ($(window).scrollTop() >= topOffset) {
        $(video).css("position", "absolute");
        $(video).css("left", "0px");
        $(video).css("top", topOffset);
    } else {
        $(video).css("position", "fixed");
        $(video).css("left", "0px");
        $(video).css("top", "0px");
    }
}

function onResize() {
    computeVideoSizeAndPosition();
    updateVideoPosition();
}

onResize();

//Initialize video effect wrapper
$(document).ready(function () {

    //If .first text-element is set, place it in bottom of
    //text-display
    if ($("#video-effect-wrapper .text.first").length) {
        //Get text-display position properties
        let textDisplay = $("#video-effect-wrapper #text-display");
        let textDisplayPosition = textDisplay.offset().top;
        let textDisplayHeight = textDisplay.height();
        let textDisplayBottom = textDisplayPosition + textDisplayHeight;

        //Get .text.first positions
        let firstText = $("#video-effect-wrapper .text.first");
        let firstTextHeight = firstText.height();
        let startPositionOfFirstText = textDisplayBottom - firstTextHeight + 50;

        //Set start position of .text.first
        firstText.css("margin-top", startPositionOfFirstText);
    }
});

//Code to launch video-effect when user scrolls
$(document).scroll(function () {

    //Calculate amount of pixels there is scrolled in the video-effect-wrapper
    let n = $(window).scrollTop() - $("#video-effect-wrapper").offset().top + 408;
    n = n < 0 ? 0 : n;

    //If .text.first is set, we need to calculate one less text-box
    let x = $("#video-effect-wrapper .text.first").length == 0 ? 0 : 1;

    //Calculate how many percent of the video-effect-wrapper is currenlty scrolled
    let percentage = n / ($(".text").eq(1).outerHeight(true) * ($("#video-effect-wrapper .text").length - x)) * 100;
    //console.log(percentage);
    //console.log(percentage);

    //Get duration of video
    let duration = video.duration;

    //Calculate to which second in video we need to go
    let skipTo = duration / 100 * percentage;

    //console.log(skipTo);

    //Skip to specified second
    video.currentTime = skipTo;

    //Only allow text-elements to be visible inside text-display
    let textDisplay = $("#video-effect-wrapper #text-display");
    let textDisplayHeight = textDisplay.height();
    let textDisplayTop = textDisplay.offset().top;
    let textDisplayBottom = textDisplayTop + textDisplayHeight;
    $("#video-effect-wrapper .text").each(function (i) {
        let text = $(this);

        if (text.offset().top < textDisplayBottom && text.offset().top > textDisplayTop) {
            let textProgressPoint = textDisplayTop + (textDisplayHeight / 2);
            let textScrollProgressInPx = Math.abs(text.offset().top - textProgressPoint - textDisplayHeight / 2);
            textScrollProgressInPx = textScrollProgressInPx <= 0 ? 0 : textScrollProgressInPx;
            let textScrollProgressInPerc = textScrollProgressInPx / (textDisplayHeight / 2) * 100;

            //console.log(textScrollProgressInPerc);
            if (text.hasClass("first"))
                textScrollProgressInPerc = 100;

            text.css("opacity", textScrollProgressInPerc / 100);
        } else {
            text.css("transition", "0.5s ease");
            text.css("opacity", "0");
        }
    });

    updateVideoPosition();

});

यहाँ HTML है:

<div id="video-effect-wrapper">
    <video muted autoplay>
        <source src="https://ndvibes.com/test/video/video.mp4" type="video/mp4" id="video">
    </video>
    <div id="text-display"/>
    <div class="text first">
        Scroll down to test this little demo
    </div>
    <div class="text">
        Still a lot to improve
    </div>
    <div class="text">
        So please help me
    </div>
    <div class="text">
        Thanks! :D
    </div>
</div>
<div id="video-placeholder">

</div>
<div id="other-parts-of-website">
    <p>
        Normal scroll behaviour wanted.
    </p>
    <p>
        Normal scroll behaviour wanted.
    </p>
    <p>
        Normal scroll behaviour wanted.
    </p>
    <p>
        Normal scroll behaviour wanted.
    </p>
    <p>
        Normal scroll behaviour wanted.
    </p>
    <p>
        Normal scroll behaviour wanted.
    </p>
</div>

आप यहाँ कोशिश कर सकते हैं: https://jsfiddle.net/crkj1m0v/3/


2
हालांकि इस प्रकार के एनीमेशन को कैसे लागू किया जाए, यह दिलचस्प और उपयोगी पृष्ठभूमि है, यह @ oniel के प्रश्न के लिए विशेष रूप से प्रासंगिक नहीं लगता है, जो कि एनीमेशन के समाप्त होने के बाद पृष्ठ की स्क्रॉलिंग को फिर से शुरू करने के लिए विशिष्ट है। ओ'नील के रूप में, स्क्रॉल और प्लेबैक के बीच जुड़ाव पहले से ही काम कर रहा है।
जेरेमी केन

1
Apple ने यह कैसे किया है, और अच्छी और चिकनी समाधान के लिए एक और भी बड़ा धन्यवाद, अंतर्दृष्टि जानकारी के लिए धन्यवाद!
ओ'नील

1

यदि आप चाहते हैं कि वीडियो आपके बैक अप स्क्रॉल करते समय वापस लॉक हो जाए, तो आपको उस स्थान को चिह्नित करना होगा जहां से आप स्विच fixedकरते हैं relative

//Get video element
let video = $("#video-effect-wrapper video").get(0);
video.pause();

let videoLocked = true;
let lockPoint = -1;
const vidHeight = 408;

//Initialize video effect wrapper
$(document).ready(function() {

  const videoHeight = $("#video-effect-wrapper").height();

  //If .first text-element is set, place it in bottom of
  //text-display
  if ($("#video-effect-wrapper .text.first").length) {
    //Get text-display position properties
    let textDisplay = $("#video-effect-wrapper #text-display");
    let textDisplayPosition = textDisplay.offset().top;
    let textDisplayHeight = textDisplay.height();
    let textDisplayBottom = textDisplayPosition + textDisplayHeight;

    //Get .text.first positions
    let firstText = $("#video-effect-wrapper .text.first");
    let firstTextHeight = firstText.height();
    let startPositionOfFirstText = textDisplayBottom - firstTextHeight + 50;

    //Set start position of .text.first
    firstText.css("margin-top", startPositionOfFirstText);
  }


  //Code to launch video-effect when user scrolls
  $(document).scroll(function() {

    //Calculate amount of pixels there is scrolled in the video-effect-wrapper
    let n = $(window).scrollTop() - $("#video-effect-wrapper").offset().top + vidHeight;
    n = n < 0 ? 0 : n;
    // console.log('n: ' + n);

    //If .text.first is set, we need to calculate one less text-box
    let x = $("#video-effect-wrapper .text.first").length == 0 ? 0 : 1;

    //Calculate how many percent of the video-effect-wrapper is currenlty scrolled
    let percentage = n / ($(".text").eq(1).outerHeight(true) * ($("#video-effect-wrapper .text").length - x)) * 100;
    //console.log(percentage);

    //Get duration of video
    let duration = video.duration;

    //Calculate to which second in video we need to go
    let skipTo = duration / 100 * percentage;

    //console.log(skipTo);

    //Skip to specified second
    video.currentTime = skipTo;

    //Only allow text-elements to be visible inside text-display
    let textDisplay = $("#video-effect-wrapper #text-display");
    let textDisplayHeight = textDisplay.height();
    let textDisplayTop = textDisplay.offset().top;
    let textDisplayBottom = textDisplayTop + textDisplayHeight;
    $("#video-effect-wrapper .text").each(function(i) {
      let text = $(this);

      if (text.offset().top < textDisplayBottom && text.offset().top > textDisplayTop) {
        let textProgressPoint = textDisplayTop + (textDisplayHeight / 2);
        let textScrollProgressInPx = Math.abs(text.offset().top - textProgressPoint - textDisplayHeight / 2);
        textScrollProgressInPx = textScrollProgressInPx <= 0 ? 0 : textScrollProgressInPx;
        let textScrollProgressInPerc = textScrollProgressInPx / (textDisplayHeight / 2) * 100;

        //console.log(textScrollProgressInPerc);
        if (text.hasClass("first"))
          textScrollProgressInPerc = 100;

        text.css("opacity", textScrollProgressInPerc / 100);
      } else {
        text.css("transition", "0.5s ease");
        text.css("opacity", "0");
      }
    });


    //If video-animation ended: Make position of video-wrapper relative to continue scrolling
    if (videoLocked) {
      if ($(window).scrollTop() >= videoHeight) {
        $('video').css("position", "relative");
        videoLocked = false;
        lockPoint = $(window).scrollTop() - 10;
        // I gave it an extra 10px to avoid flickering between locked and unlocked.
      }
    } else if ($(window).scrollTop() < lockPoint) {
      $('video').css("position", "fixed");
      videoLocked = true;
    }

  });




});
body {
  margin: 0;
  padding: 0;
  background-color: green;
}

#video-effect-wrapper {
  height: auto;
  width: 100%;
}

#video-effect-wrapper video {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  z-index: -2;
  object-fit: cover;
}

#video-effect-wrapper::after {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
  background: #000000;
  background: linear-gradient(to top, #434343, #000000);
  opacity: 0.4;
  z-index: -1;
}

#video-effect-wrapper .text {
  color: #FFFFFF;
  font-weight: bold;
  font-size: 3em;
  width: 100%;
  margin-top: 50vh;
  font-family: Arial, sans-serif;
  text-align: center;
  opacity: 0;
  /*
                background-color: blue;
                */
}

#video-effect-wrapper .text.first {
  margin-top: 50vh;
  opacity: 1;
}

#video-effect-wrapper .text:last-child {
  /*margin-bottom: 100vh;*/
  margin-bottom: 50vh;
}

#video-effect-wrapper #text-display {
  display: block;
  width: 100%;
  height: 225px;
  position: fixed;
  top: 50%;
  transform: translate(0, -50%);
  z-index: -1;
  /*
                background-color: red;
                */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="video-effect-wrapper">
  <video muted autoplay>
            <source src="https://ndvibes.com/test/video/video.mp4" type="video/mp4" id="video">
          </video>

  <div id="text-display"></div>
  <div class="text first">
    Scroll down to test this little demo
  </div>
  <div class="text">
    Still a lot to improve
  </div>
  <div class="text">
    So please help me
  </div>
  <div class="text">
    Thanks! :D
  </div>
</div>

<div id="other-parts-of-website">
  <p>
    Normal scroll behaviour wanted.
  </p>
  <p>
    Normal scroll behaviour wanted.
  </p>
  <p>
    Normal scroll behaviour wanted.
  </p>
  <p>
    Normal scroll behaviour wanted.
  </p>
  <p>
    Normal scroll behaviour wanted.
  </p>
  <p>
    Normal scroll behaviour wanted.
  </p>
</div>


नमस्ते आपके उत्तर के लिए धन्यवाद। यह समाधान बंद हो जाता है, लेकिन मैं अभी भी आपके कोड के साथ एक बड़ी समस्या का सामना करता हूं: जैसे ही वीडियो समाप्त होता है, वीडियो-तत्व की स्थिति ठीक हो जाती है, लेकिन हरे रंग की पृष्ठभूमि पर अभी भी सफेद पैराग्राफ एनिमेटेड हैं। वीडियो # एनिमेशन के बाद div # अन्य-भागों की वेबसाइट पहली सामग्री होनी चाहिए जो उपयोगकर्ता देखता है।
ओ'नील
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.