IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

scroller dans un élément bloc.


Sujet :

JavaScript

  1. #1
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 275
    Points : 113
    Points
    113
    Par défaut scroller dans un élément bloc.
    Bonjour,

    j'apprends le javascript je suis des tutoriels sur le scrolling avec du javascript.
    Mais je voulais adapter ce que j'ai pu comprendre ( encore un petit niveau ) pour faire du scrolling dans un block !
    Car tous les tutos que j'ai vus se font sur la page web : une barre de navigation et on clique pour scroller à l'endroit voulu.
    Donc on sort un window.scrollTo (x,y) et ça marche , mais je n'arrive pas à adapter (enfin, je pense que mon problème vient de là).

    Attention, la page est moche , mais ce n'est pas ce sur quoi je travaille en ce moment dans mon apprentissage ( il y aura un gros travail à faire là aussi !)

    voici mon HTML:
    Code HTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="fiches.css">
        <title>fiche</title>
    </head>
    <body>
        <div class="wrap">
            <header>
                <h2 class="subcategory">catégorie</h2>
                <div class="title">
                    <h1>titre</h1>
                    <p class="definition">Lorem ipsum dolor sit amet consectetur, adipisicing elit. Et ea nam beatae excepturi modi tempora molestiae 
                        sint rerum, voluptates commodi consequuntur facere sapiente nostrum vero deserunt molestias maxime ducimus explicabo?</p>
                </div>
                <h2 class="type">sous-catégorie</h2>
            </header>
                <div class="content">
                    <nav>
                        <ul>
                            <li><a href="#syntaxe">Syntaxe</a></li>
                            <li><a href="#exemples">Exemples</a></li>
                            <li><a href="#associations">Associations</a></li>
                            <li><a href="#liens">liens</a></li>
                            <li><a href="#illustrations">Illustrations</a></li>
                            <li><a href="#notes">notes</a></li>
                        </ul>
                    </nav>
                    <main class="display">
                        <section id="syntaxe"><h2>Syntaxe</h2></section>
                        <section id="exemples"><h2>Exemples</h2></section>
                        <section id="associations"><h2>Associations</h2></section>
                        <section id="liens"><h2>liens</h2></section>
                        <section id="illustrations"><h2>Illustrations</h2></section>
                        <section id="notes"><h2>Notes</h2></section>
                    </main>
                </div>
                <footer></footer>
        </div>
        <script src="lescroll.js"></script>
    </body>
    </html>

    puis mon CSS:
    Code CSS : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    * {
        margin: 0px;
        padding: 0px;
        box-sizing: border-box;
    }
     
    body {
        height: 100vh;
        width: 100vw;
        display: flex;
        justify-content: center;
        align-items: center;
    }
     
    .wrap {
        height: 60%;
        width: 60%;
        display: flex;
        justify-content: center;
        flex-direction: column;
        border: 2px solid firebrick;
    }
     
    header {
        width: 100%;
        height: 30%;
        margin-left: 5px;
        display: flex;
        justify-content: space-between;
    }
     
    h1 {
        text-transform: uppercase;
    }
     
    .content {
        height: 70%;
        width: 100%;
        margin-left: 5px;
        display: flex;
    }
     
    .title {
        text-align: center;
        width: 60%;
        height: 100%;
    }
     
     
    main {
        border: 2px solid black;
        width: 80%;
        height: 100%;
        margin-left: 5px;
        margin-right: 5px;
        overflow: hidden;
        /*scroll-behavior: smooth;*/
    }
     
    nav {
        width: 20%;
        height: 100%;
    }
     
    ul {
        height: 100%;
        list-style-type: none;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
    }
     
    li {
        border: 2px solid red;
        text-align: center;
        height: 16%;
        line-height: 250%;;
    }
     
    section{
        display: flex;
        align-items: center;
        justify-content: center;
        height: 100%;
        text-transform: uppercase;
    }
     
    section:nth-child(2n+1) {
        background-color: red;
    }
     
    a {
        display: block;
        width: 100%;
        height: 100%;
    }
     
    ul a:hover {
        background-color: #000;
        color: white;
    }
     
    .subcategory, .type {
        width: 20%;
        height: 100%;
        text-align: center;
        padding: 5% 0;
    }

    et enfin mon javascript:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    /* recupération des liens et association au click */
    const links = document.querySelectorAll('ul li a');
    console.log(links);
    for (const link of links) {
        link.addEventListener('click', move);
    };
     
    function move(event) {
        event.preventDefault();
        console.clear();
        console.group("le lien: ", this);
        /* récupération de la position de la cible du lien */
        const ref = this.getAttribute('href');
        console.log("nom dela cible:", ref);
        const target = document.querySelector('main').querySelector(ref);
        console.log("la cible: ", target);
        const targetPosition = target.getBoundingClientRect().top;
        console.log("position de la cible: ", targetPosition);
        /*  récupération de la distance à scroller: celle du main - celle de la cible */
        const finalposition = document.querySelector('main').getBoundingClientRect().top;
        console.log("position du main: ", finalposition);
        const distanceToScroll = targetPosition - finalposition;
        console.log("pixels à parcourrir: ", distanceToScroll);
        let start = null;
        const duration = 2000;
        window.requestAnimationFrame(scrolling);
        function scrolling(timestamp) {
            if (!start) {
                start = timestamp;
            }
            let progress = (timestamp - start);
            const step = distanceToScroll*(progress/duration);
            document.querySelector('main').scrollTo(0, step);
            if (progress<duration) {
                window.requestAnimationFrame(scrolling);
            }
        }
    }
    Le seul truc qui cloche: lorsque je clique sur un lien autre que syntaxe, ça m'affiche la section syntaxe au lieu de scroller !!!
    Et je dois cliquer encore une fois sur le même lien pour scroller , mais du coup les calculs qui se font en partant de la section à scroller sont faux et le scroll n'est pas bon !

    Alors voilà, pourquoi ça ne scrolle pas lorsque je clique sur un lien ? que se passe-t-il justement lorsque je clique ?

    Merci pour vos réponses

    Laurent.

  2. #2
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 667
    Points
    44 667
    Par défaut
    Bonjour,
    tu oublies d'ajouter la position du scroll de ton élément <main> au moment du clic pour connaître la position à atteindre.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    const elMain = document.querySelector('main');
    // ....
    const distanceToScroll = targetPosition - finalposition +elMain.scrollTop;

  3. #3
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 275
    Points : 113
    Points
    113
    Par défaut
    Bonjour,

    Ça fait quelque chose de mieux, mais c'est pas encore ça !
    Mais j'ai déjà :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    const finalposition = document.querySelector('main').getBoundingClientRect().top;
    Ça représente quoi ? Pour moi c'est la position du main ( le haut ) et cette position ne change jamais ! ( j'ai vérifié avec un console.log ) C'est bien là que je veux aller en scrollant !
    si je modifie le code comme tu le proposes, il affiche toujours la section syntaxe ( la première section ) puis scrolle jusqu'à l'élément demandé .
    Il ne reste plus qu'à le faire aller directement à l'élément demandé sans passer par la section syntaxe ... !

    Je comprends de moins en moins les positions

  4. #4
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 667
    Points
    44 667
    Par défaut
    Ça représente quoi ? Pour moi c'est la position du main ( le haut ) et cette position ne change jamais ! ( j'ai vérifié avec un console.log
    Sauf si la page scroll ! donc il importe de prendre les données sur le même bases/références.
    element.getBoundingClientRect.


    si je modifie le code comme tu le proposes, il affiche toujours la section syntaxe ( la première section ) puis scrolle jusqu'à l'élément demandé .
    C'est ton code qui le prévoit dans ta fonction scrolling, tu repars à chaque fois de 0.


    Il ne reste plus qu'à le faire aller directement à l'élément demandé sans passer par la section syntaxe ... !
    Il te faut changer d'approche et calculer le chemin à faire qui sera soit positif soit négatif.

    Je te propose ce code à étudier et à améliorer le cas échéants :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    function anim(e) {
        e.preventDefault();
        const elMain = document.querySelector('main');
        const elMainTop = elMain.getBoundingClientRect().top;
        const elMainScrollTop = elMain.scrollTop;
     
        const ref = this.getAttribute('href');
        const elTarget = elMain.querySelector(ref);
        const elTargetTop = elTarget.getBoundingClientRect().top + elMainScrollTop;
     
        const deltaScroll = elTargetTop - elMainScrollTop - elMainTop;
     
        let start = null;
        const duration = 2000;
     
        function scrolling(timestamp) {
            if (!start) {
                start = timestamp;
            }
            const progress = (timestamp - start);
            const pourCent = (progress / duration);
            const posScroll = elMainScrollTop + (deltaScroll * pourCent);
            elMain.scrollTo(0, posScroll);
            if (progress < duration) {
                window.requestAnimationFrame(scrolling);
            }
        }
        window.requestAnimationFrame(scrolling);
    }
    C'est pas commenté mais cela me semble suffisamment clair, la fonction n'a pas le même nom, tu peux donc faire cohabiter les deux dans ta page pour test.

  5. #5
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 275
    Points : 113
    Points
    113
    Par défaut
    ÇA Y EST , J'AI COMPRIS, MON PROBLÈME SE SITUAIT LÀ:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    const step = distanceToScroll*(progress/duration);
    document.querySelector('main').scrollTo(0, step);
    Car je n'avait pas lu ce lien
    ( Très bien javascript.infos !!! )

    Du coup il suffit juste de mettre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    const step = mainScrollTop + (distanceToScroll*(progress/duration));
    avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    const mainScrollTop = document.querySelector('main').scrollTop;
    et du coup ça va mieux ...
    Je n'avais pas compris comment fonctionnait le scrollTop !

    Merci pour ton aide.
    Je vais m'attaquer maintenant à faire un scroll plus linéaire ! Avec des interpolations linéaires ( évidemment ) parce que j'ai vu ça dans des tutoriels en vidéo. Ça vaut le coup ou pas ?
    Plus précisément dans quelles conditions l'interpolation va servir ?

    Laurent.

  6. #6
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 667
    Points
    44 667
    Par défaut
    et du coup ça va mieux ...
    Je n'avais pas compris comment fonctionnait le scrollTop !
    Voilà donc qui est fait


    Je vais m'attaquer maintenant à faire un scroll plus linéaire ! Avec des interpolations linéaires ( évidemment ) parce que j'ai vu ça dans des tutoriels en vidéo. Ça vaut le coup ou pas ?
    Plus précisément dans quelles conditions l'interpolation va servir ?
    Le principal soucis qu'il y a avec le « défilement automatique » outre que c'est très souvent chiant et soulant, c'est le choix de la vitesse.

    Dans ton cas tu réalises un défilement en 2s que tu scrolles 200px ou 3000px ce qui tu l’avoueras n'est pas super agréable visuellement !

    Perso je trouve préférable de fixer une vitesse de défilement comme par exemple en déclarant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // speed : 1s pour 2000px
    const speed = 1000 / 2000;
    const duration = speed * Math.abs(distanceToScroll);
    tu auras de la sorte quelque chose de plus homogène.

    Concernant les effets de défilement, je te conseille de regarder du côté de : Easing Functions Cheat Sheet.
    La mise en oeuvre est des plus simple, tu passes le pourcentage d'avancement à la fonction et elle te retourne celui à appliquer pour obtenir ton effet.

    En reprenant, plus ou moins, le code vu cela donnerait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const progress = (timestamp - start);
    const pourCent = easeInOutCubic(progress / duration);
    const posScroll = elMainScrollTop + (distanceToScroll * pourCent);
    elMain.scrollTop = posScroll;
    avec la déclaration de la fonction easeInOutCubic suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    function easeInOutCubic(x) {
      return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
    }
    Après les goûts et les couleurs ...

  7. #7
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 275
    Points : 113
    Points
    113
    Par défaut
    Merci , pour le easeInOutCubic, j'allais y jeter in coup d'oeil !!
    on se sert de ça donc pour faire un débute scroll lent et une fin également => ce qu'on appelle un scroll "doux"

    et pour la durée du scroll: on adapte la durée en fonction de la distance à scroller !!
    C'était bien mon intention mais je voulais d'abord savoir scroller où je voulais pour peaufiner le rendu ensuite.

    Le plus drôle, c'est q'il m'est arrivé un truc après tous ces changements: si je clique deux fois sur le même lien,
    la deuxième fois m'affiche la dernière section ! ( un scroll très rapide, donc pas visible );
    Je me suis presque retrouvé avec le même problème qu'au début

    Mais heureusement , j'ai fait des progrès et j'ai trouvé assez rapidement:
    si je reclique , la durée du scroll est très faible, le pourCent est élevé car
    progress / duration très grand et du coup easeInOutCubic très très grand => mon step énorme => on srcolle directement vers la dernière section.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    function scrolling(timestamp) {
            if (!start) {
                start = timestamp;
            }
            let progress = (timestamp - start);
     
            const pourCent = duration < 1 ? 0 : easeInOutCubic(progress/duration); 
            const step = mainScrollTop + (distanceToScroll*(pourCent));
            document.querySelector('main').scrollTo(0, step);
            if (progress<duration) {
                window.requestAnimationFrame(scrolling);
    je fais une condition ternaire pour éviter ça et ça marche !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const pourcent = duration < 1 ? 0 : easeInOutCubic(progress/duration);
    Merci encore pour tout,

    Laurent.

  8. #8
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 667
    Points
    44 667
    Par défaut
    Le plus drôle, c'est q'il m'est arrivé un truc après tous ces changements: si je clique deux fois sur le même lien,
    la deuxième fois m'affiche la dernière section ! ( un scroll très rapide, donc pas visible );
    ( ... )
    je fais une condition ternaire pour éviter ça et ça marche !
    ce n'est pas comme cela que l'on résout un problème de multi-appui sur un bouton, d'autant que chaque nouvel appui entraine exécution de la fonction mais dans un contexte d’exécution différent.

    Plusieurs techniques existent pour pallier à cela :
    • interdire un autre appui, disabled du bouton par exemple, tant qu'une animation est en cours et attendre que celle-ci soit complète pour réactiver l'appui, la gestion peut s’avérer parfois délicate. Cela n'autorise pas le droit à l'erreur ;
    • gérer un « flag », qui, si il est posé, interdit une relance de la fonction gérant l'animation. Même chose que ci-dessus en fait avec une gestion plus simple ;
    • la plus propre à mon sens, est de stopper l'animation en cours et d'en relancer une autre, on a donc le droit à l'erreur et de plus il existe une méthode qui fait cela très bien : cancelAnimationFrame(requestId), il y a juste à gérer le requestId correctement.

    Dans ce dernier cas on peut schématiser cela comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // en début de fonction
    // supprime animation en cours
    cancelAnimationFrame(elMain.requestId);
    // ...
    // le reste du code
    // ...
    // et dans la fonction scrolling
    function scrolling(timestamp) {
      // ...
      // le début du code
      // ...
       if (progress < duration) {
        elMain.requestId = window.requestAnimationFrame(scrolling);
      }
      else {
        // autorise prochain scroll
        delete elMain.requestId;
      }
    }
    elMain.requestId = window.requestAnimationFrame(scrolling);
    il faut simplement bien penser à garder la référence pour elMain.requestId qui change à chaque appel.

  9. #9
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 275
    Points : 113
    Points
    113
    Par défaut
    Bonjour,

    Je ne trouve pas beaucoup d'explications sur cancelAnimationFrame !!!
    à part des choses basiques.

    Donc j'ai fais quelque chose de simple, avant ma fonction scrolling:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    const duration = speed * Math.abs(distanceToScroll);
    var requestID = window.requestAnimationFrame(scrolling);
    if (duration < 1) { window.cancelAnimationFrame(requestID);}
    Mais j'ai 'osé' ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    const duration = speed * Math.abs(distanceToScroll);
    if (duration < 1) return;
    Et je sors de ma fonction move sans faire de scrolling.

    Les deux codes marchent mais je me dis que c'est peut-être pas la bonne manière de faire !

    j'avoue ne pas trop avoir compris le code que tu m'a fournis !
    Encore débutant sur javascript ( et la programmation en général )je ne comprends pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    elMain.requestID = window.requestAnimationFrame()
    mais plutôt:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let requestID = window.requestAnimationFrame()
    Lorsque mon scrolling est fini, l'animation aussi ?
    Du coup, il faut juste ne pas relancer l'animation si je clique sur la section actuelle plutôt que de la lancer et stopper ! et faire cette condition avant la fonction scrolling.

    Sinon, s'il y a de la (bonne) documentation sur le cancelAnimationFrame, je suis preneur !

    Laurent.

  10. #10
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 667
    Points
    44 667
    Par défaut
    Je ne trouve pas beaucoup d'explications sur cancelAnimationFrame !!!
    à part des choses basiques.
    simplement car c'est on ne peut plus basique, tu killes le processus prévu en cours en passant simplement l'ID de celui-ci.


    Donc j'ai fais quelque chose de simple, avant ma fonction scrolling:
    cela n'a pas grand sens, ta condition if (duration < 1) ayant peu de chance d'être appelée.
    Idem pour ta solution suivante où l'animation continue jusqu'à ce qu'elle soit terminée.


    Les deux codes marchent mais je me dis que c'est peut-être pas la bonne manière de faire !
    on ne dit pas qu'un «  code marche » car souvent en fait il ne dysfonctionne pas


    Encore débutant sur javascript ( et la programmation en général )je ne comprends pas
    J'ai « finalisé », enfin presque, une page où ton besoin est mis en oeuvre : Défilement fluide (smooth-scrolling), regarde et reviens dire ce que tu ne comprends pas dans le fonctionnement.


    Sinon, s'il y a de la (bonne) documentation sur le cancelAnimationFrame, je suis preneur !
    Ressources :

  11. #11
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 275
    Points : 113
    Points
    113
    Par défaut
    Bonsoir,
    voici mon code pour la fonction de scrolling:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    function move(e) {
        e.preventDefault();
        const ref = this.getAttribute('href');
        const targetposition = document.querySelector('main').querySelector(ref).getBoundingClientRect().top;
     
        const mainPosition = document.querySelector('main').getBoundingClientRect().top;
     
        const mainScrollTop = document.querySelector('main').scrollTop;
     
        const distanceToScroll = targetposition - mainPosition;
        document.querySelector('main').bonjour = 'bonjour';
        let start = null;
        const speed = 1100/1000;
        const duration = speed * Math.abs(distanceToScroll);
        console.log("la distance: ", distanceToScroll);
        console.log("la durée: ", duration);
        if (duration < 1) { console.log("tu y es déjà !!");} 
        else { window.requestAnimationFrame(scrolling);}
        function scrolling(timestamp) {
            console.log("ça scrolle !!!");
            if (!start) {
                start = timestamp;
            }
            let progress = (timestamp - start);
            const pourCent = easeInOutCubic(progress/duration); 
            const step = mainScrollTop + (distanceToScroll*(pourCent));
            document.querySelector('main').scrollTo(0, step);
            if (progress<duration) {
                window.requestAnimationFrame(scrolling);
            }
        }
    }
    Pour moi, ce code ne " dysfonctionne " pas !
    Disons qu'il fait ce que je demande: ma condition if (duration < 1 ) est exécutée !

    Du coup, je ne comprends pas cette histoire d'arrêter l'animation : lorsque le scroll est terminé , l'animation aussi !
    Et elle se relance seulement si on ne clique pas sur la section actuelle .

    Le window.CancelAnimationFrame est effectivement facile à comprendre: il arrête l'animation " en cours " , si j'en crois tous les exemples que j'ai vus .

    Sinon, je découvre qu'on peut écrire un truc comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    document.querySelector('main').bonjour = 'bonjour'
    on crée un attribut bonjour pour l'élément main. Pas dans mes habitudes de débutant !
    Mais, dans le code, pourquoi pas une simple variable ? du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    requestId = window.requestAnimationFrame()
    Après , je comprends bien tout le reste ( même si je vais par la site peaufiner les positions, borderTopWidth, marginTop, ...)
    Sinon, toi " scrollTop " et moi " scrollTo " ! Pas de préférences ?

  12. #12
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 667
    Points
    44 667
    Par défaut
    voici mon code pour la fonction de scrolling:
    J'étais resté dans la logique où ton code était ajouté dans la fonction scrolling, donc oublie !


    Pour moi, ce code ne " dysfonctionne " pas !
    C’était une boutade !


    Disons qu'il fait ce que je demande: ma condition if (duration < 1 ) est exécutée !
    Dans le pire des cas la fonction de scrolling ne fait rien donc il n’est pas vraiment utile de tester s’il y a quelque chose à faire, la fonction va prendre quelques ms.


    Du coup, je ne comprends pas cette histoire d'arrêter l'animation (…)
    Il est important de stopper l’animation en cours, si elle est terminée il n’y a pas de soucis, dans le cas, que tu as d’ailleurs indirectement rencontré, où après avoir cliqué sur le dernier bouton, par exemple, tu cliques sur le deuxième alors que l’animation est en cours. Rien ne te garantie qu’au final tu seras sur la cible du deuxième bouton cela dépendra de l’état d’avancement de tes animations, laquelle se terminera la dernière et gagnera donc.


    Sinon, je découvre qu'on peut écrire un truc comme ça:
    (…)
    on crée un attribut bonjour pour l'élément main. Pas dans mes habitudes de débutant !
    Ce n’est pas un attribut, mais une propriété, la différence est tenue mais existe.

    En JavaScript tout est objet donc tu peux effectivement ajouter une propriété à un objet, la seule chose à faire attention est de ne pas écraser une propriété existante cela pourrait engendrer des conflits.

    Une autre façon de faire est de passer par les attributs data-xxxx qui reste peut être une solution plus propre.


    Mais, dans le code, pourquoi pas une simple variable ? du genre:
    Passer par des variables globales n’est pas considéré comme une bonne pratique, on pollue l’espace global et on risque des conflits avec d’autres scripts présents.

    En passant par une variable/propriété attitrée cela te permet de gérer éventuellement plusieurs animations sur différent élément de ta page et de ne pas interférer avec les autres. Ton code est mieux cloisonné.

    En parlant de bonne pratique, et comme tu débutes, il en est une qui consiste à mettre en cache les données que l’on réutilise à savoir dans ton cas tu utilises document.querySelector('main') plusieurs fois dans ta fonction donc autant avoir une variable const elementMain = document.querySelector('main') et réutiliser celle-ci.
    Les moteurs JavaScript sont capables de faire certaines optimisations mais cela ne mange pas de pain et apporte de la simplicité et de la lisibilité au code, donc de la maintenance aisée, imagine que tu changes l'ID par exemple.


    Sinon, toi " scrollTop " et moi " scrollTo " ! Pas de préférences ?
    C’est historique, la méthode scrollTo sur les éléments à était introduite pour homogénéiser les méthodes sur les différents éléments et permet ainsi de supporter la déclaration scroll-behavior: smooth pour un défilement en douceur.
    Si tu dois supporter des anciens navigateurs alors il est préférable d’utiliser les propriétés plutôt que les méthodes, après côté performance je dirais que l’on s’en fout un peu.
    Scroll methods on elements (scroll, scrollTo, scrollBy)

  13. #13
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 275
    Points : 113
    Points
    113
    Par défaut
    bon, j'arrive à stopper l'animation et donc effectivement , je n'ai plus le souci lorsque je clique
    sur un autre lien et que l'animation n'est pas finie. En fait , j'avais pas vu ce problème tout simplement
    parce que j'en réglais d'autres ...

    Il reste encore des trucs que je ne comprends pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    getBoundingClientRect().top
    La méthode appliquée sur le main donne toujours le même résultat ( ok pour ça )
    mais si appliquée sur la section visible ( si je relique sur le lien ) ne donne pas la même valeur que pour le main ?
    Il y a une différence de 0.5 en moyenne !!
    Je n'arrive pas à savoir d'où ça vient, j'ai supprimé toutes mes marges, bordures ...etc.

    Est-ce que je peux faire une condition pour lancer le scrolling : du genre seulement si la distance à parcourir est 0 ?
    Parce que pour l'instant , en cliquant à nouveau sur le lien, l'animation se lance mais rien ne bouge .Ce serait bien qu'elle ne se lance pas.
    Donc , mettre une condition pour le lancement ?

  14. #14
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 667
    Points
    44 667
    Par défaut
    ( ... )
    Il y a une différence de 0.5 en moyenne !!
    Je n'arrive pas à savoir d'où ça vient, j'ai supprimé toutes mes marges, bordures ...etc.
    Toutes les informations numériques que tu traites dans cette fonction sont des « flottants ».
    Voilà ce que te renvoie par exemple la méthode getBoundingClientRect :
    Citation Envoyé par DOMRect interfaces
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    readonly attribute unrestricted double x;
    readonly attribute unrestricted double y;
    readonly attribute unrestricted double width;
    readonly attribute unrestricted double height;
    readonly attribute unrestricted double top;
    readonly attribute unrestricted double right;
    readonly attribute unrestricted double bottom;
    readonly attribute unrestricted double left;
    Comme tu as du t'en apercevoir les centièmes de pixel, voire encore plus petit, existent

    Sachant que :
    • Tout tes calculs sont donc sujet à des erreurs d'arrondi, mais pas les même suivant les navigateurs en cumul, soucis bien connu en JavaScript, mais pas que ;
    • Tout les calculs durant la progression sont donc potentiellement entachés d'une incertitude et ce jusqu'à la fin de l'animation ;
    • Les propriétés comme scrollTop/scrollLeft sont affectées au final en tant qu'entier ;
    • ...

    la solution que j'ai retenu est de placer au final les valeurs initialement calculées dans les variables scrollTop/scrollLeft avec un Math.round pour assurer et je n'ai pas eu de mauvaise surprise, jusqu'à présent !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    if (progress < duration) {
      o.elParent.requestId = window.requestAnimationFrame(scrolling);
    }
    else {
      // recalage propre en fin, si pb arrondi vu sur FF
      o.elParent.scrollTop = o.elParentScrollTop + Math.round(distanceToScrollY);
      o.elParent.scrollLeft = o.elParentScrollLeft + Math.round(distanceToScrollX);
    }
    à me relire, j'aurais pu faire plus propre !



    Est-ce que je peux faire une condition pour lancer le scrolling : du genre seulement si la distance à parcourir est 0 ?
    Voilà le point le plus épineux de l'affaire, faut-il gérer les erreurs ou autres exceptions ?

    Ici aussi il faut constater/savoir plusieurs choses :
    • Une division par zéro ne lève pas d’exception mais retourne Infinity, ce serait le cas avec une duration égale à 0 ;
    • Il faudrait également tester que le pourcent est compris dans [1-0] ;
    • Une addition d'un nombre avec une donnée NaN retourne NaN ;
    • Concernant scrollTop/scrollLeft
      When asked to normalize non-finite values for a value x, if x is one of the three special floating point literal values (Infinity, -Infinity or NaN), then x must be changed to the value 0.
    ... donc oui on peut, on devrait, tout tester avant emploi.

    Mais compte tenu de tout cela l'option que j'ai prise est de laisser faire le moteur JavaScript au mieux et de placer les « bonnes valeurs » en fin d'animation.
    Au pire on perd un voire deux cycles mais tout ce passe bien et cela résous les soucis annoncés.

    Voilà c'est un peu en vrac mais cela t'explique ma démarche.


    Donc , mettre une condition pour le lancement ?
    A toi de voir maintenant

  15. #15
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 275
    Points : 113
    Points
    113
    Par défaut
    Bonjour,

    tout fonctionne comme il faut maintenant,
    j'ai mis la condition pour le lancement du scroll !

    Il me reste une dernière question ( normalement ):
    dans ton code de la fonction scroll tu utilises l'objet O, c'est pour une bonne pratique ? ( mettre les variables dans un objet pour s'en servir )

    Laurent.

  16. #16
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 667
    Points
    44 667
    Par défaut
    Il me reste une dernière question ( normalement ):
    dans ton code de la fonction scroll tu utilises l'objet O, c'est pour une bonne pratique ? ( mettre les variables dans un objet pour s'en servir )
    si je reprend une partie du code, à savoir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
      const o = {};
      // récup. info sur référent
      o.elParent = parent || document.documentElement;
      o.elParentTop = rectParent.top || 0;
      o.elParentLeft = rectParent.left || 0;
      o.elParentBorderTopWidth = parseInt(styleParent.borderTopWidth, 10) || 0;
      o.elParentBorderLeftWidth = parseInt(styleParent.borderLeftWidth, 10) || 0;
      o.elParentScrollTop = o.elParent.scrollTop;
      o.elParentScrollLeft = o.elParent.scrollLeft;
      // récup. infos élément cible
      o.elTargetMarginTop = parseInt(styleTarget.marginTop, 10);
      o.elTargetMarginLeft = parseInt(styleTarget.marginLeft, 10);
      o.elTargetTop = rectTarget.top - o.elTargetMarginTop;
      o.elTargetLeft = rectTarget.left - o.elTargetMarginLeft;
    on va manipuler pas moins de 11 variables dont 9 seraient déclarées en const, non variables, et 2 en let, variables réaffectées.

    Une des raisons et que lors de la phase de test un console.log(/* et les variables qui se suivent */) deviendrait vite fastidieux alors qu'un console.log("datas :", o) est des plus simple à faire.

    De plus si les données devaient être passé à une fonction tiers, ce qui aurait pu être le cas ici, il en serait de même.

    Après rien ne t'empêche de remplacer tous les o. par des const ou let dans la déclaration des variables pour obtenir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const elParent = parent || document.documentElement,
      elParentTop = rectParent.top || 0,
      elParentLeft = rectParent.left || 0,
      elParentBorderTopWidth = parseInt(styleParent.borderTopWidth, 10) || 0,
      elParentBorderLeftWidth = parseInt(styleParent.borderLeftWidth, 10) || 0,
      elParentScrollTop = o.elParent.scrollTop,
      elParentScrollLeft = o.elParent.scrollLeft,
      elTargetMarginTop = parseInt(styleTarget.marginTop, 10),
      elTargetMarginLeft = parseInt(styleTarget.marginLeft, 10),
      elTargetTop = rectTarget.top - elTargetMarginTop,
      elTargetLeft = rectTarget.left - elTargetMarginLeft;
    est-ce plus lisible ou moins, est-ce une bonne pratique ou non, chacun y verra midi à sa porte

    PS : Je ne sais pas si t as vu, mais suite à cette discussion et après donc exhumation de ce script, je l'ai repris afin que la logique soit plus proche de ce que je ferais actuellement.

    [Edit] Correction coquille sur la déclaration des variables

  17. #17
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 275
    Points : 113
    Points
    113
    Par défaut
    Oui, les console.log() , très bonne idée ! Je retiens, je retiens....
    Depuis le temps que j'en fais un peu partout pour tester ! Je vais peut-être changer de méthode !

    Merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. exceptions plsql dans les sous blocs
    Par r83 dans le forum PL/SQL
    Réponses: 3
    Dernier message: 02/04/2007, 23h33
  2. [CSS] Image de fond dans un élément <div>
    Par Yogui dans le forum Mise en page CSS
    Réponses: 5
    Dernier message: 16/05/2006, 13h05
  3. [XML] attribut dans l'élément racine
    Par gabychon dans le forum XML/XSL et SOAP
    Réponses: 2
    Dernier message: 27/04/2006, 14h44
  4. Limiter la saisie dans un élément texte
    Par manou.K dans le forum Oracle
    Réponses: 2
    Dernier message: 28/07/2005, 11h41
  5. comment scroller dans un div avec l'evenement onmousemove.
    Par julien.v dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 13/06/2005, 16h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo