Galerie qui défile au scroll de molette
Créer la galerie
Avant de remplir notre galerie, nous allons rapidement créer la structure html qu'il nous faut.
Une simple <section> dans notre <body> et un bloc (ici un <aside>) pour afficher de l'info. Ce bloc pourra servir à indiquer le numéro de l'image encours (la pagination quoi).
<body>
<section></section>
<aside>scroll to slide</aside>
</body>
Pour remplir la galerie d'images en js, il nous faut une liste d'image dans une table, un array new Array().
const listeImg = ["image1.jpg","image2.jpg","image3.jpg"];
La technique est simple, on crée un élement, un <article>, on lui attribue l'image en background et on l'ajoute à la section.
Et on répète l'opération sur la longueur de la table (sur chaque élément de la table).
for (const img of listeImg) {
// crée un article
const article = document.createElement("article");
// attibue l'image en bckgrnd
article.style.backgroundImage = "url(medias_book/"+img+")";
// ajoute l'article à la section
document.querySelector("section").append(article);
}
La galerie est une suite d'images placée sur une bande horizontale qui défile au scroll. Il y a une image par écran, donc on donne comme largeur à l'article :article { width: 100vw;}.
Pour que toutes les images soient sur une bande horizontale, il faut donner la largeur de la bande (<section>). On la calcule en multipliant la longueur length de la table par 100vw.
document.querySelector("section").style.width = (listeImg.length*100)+"vw";
Ce qui nous donne au final un petit bout de code :
const listeImg = ["image1.jpg","image2.jpg","image3.jpg"];
!function(){
// itère sur la listeImg
for (const i of listeImg) {
// crée un article
const article = document.createElement("article");
// attibue l'image en bckgrnd
article.style.backgroundImage = "url(medias_galerie/"+i+")";
// ajoute l'article à la section
document.querySelector("section").append(article);
}
// calcule la largeur totale que doit avoir la section pour contenir toutes les images
document.querySelector("section").style.width = (listeImg.length*100)+"vw";
}();
une fonction anonyme auto-invoquée
L'interêt de cette technique est que la fonction va s'exécuter immédiatement après sa création, donc dès le début.
Le navigateur charge la page au fur et à mesure, ligne par ligne, avec cette technique on attend donc que la totalité du code de la fonction soit chargé, pour qu'il s'exécute immédiatement.
!function(){ // fonction autoexecutable // des trucs à éxecuter quand la page est chargée }();Pour, peut-être, mieux comprendre, je vous renvoie à l'article de Pierre Giraud
Capturer la molette
La molette de la souris possède un évenement onwheel et une propriété deltaYqui permet de connaitre la direction de la molette et la "quantité" tournée.
On peut capturer cette information en plaçant sur la fenêtre (window), un écouteur d'évenement et afficher dans la console, la propriété deltaY.
window.addEventListener("wheel",(e) => {
document.body.innerHTML = e.deltaY;
});
Testez ce code, sur mon portable, donc avec le trackpad, j'obtiens une valeur deltaY, qui oscille entre -100 et 150 env.
Pour la galerie, j'ai arbitrairement décidé que le delta minimum pour déclencher le changement d'image, doit être de 50. Vous testerez avec une vraie souris pour ajuster les valeurs plancher.
gérer la navigation
L'évenement wheel déclenche à répétition tant que la molette tourne. Nous n'avons besoin que d'une seule valeur supérieure à 40 pour changer l'image, donc nous allons arrêter d'écouter quand on a obtenu notre déclenchement.
Pour ça, nous allons utiliser un drapeau, une variable booléenne, qui va passer de faux à vrai et empêcher de changer d'image encore et encore.
Variable Booléenne
Du nom du Mathématicien George Boole, fondateur dans le milieu du XIXe siècle de l'algèbre portant son nom. un booléen est un type de variable à deux états (généralement notés vrai et faux), destiné à représenter les valeurs de vérité de la logique et l'algèbre booléenne. Le type de données booléen est principalement associé à des états conditionnels.
let drapeau = true;
let _fait = false;
[…]
window.addEventListener("wheel",(e) => {
if (e.deltaY > 40 && !_fait) {
// le deltaY (variation de la roulette) est > 40
// change l'index de l'image ecours
_indexImg++;
// le changement d'image est fait
_fait = true;
console.log("image suivante");
}
}
Si on teste ce bout de code, ça ne déclenche qu'une seule fois.
Il faut réamorcer l'interrupteur en repassant le drapeau à faux quand le deltaY redevient presque nul (quand il est nul, il n'y a pas d'évenement wheel).
if (e.deltaY < 20 && e.deltaY > -20) {
_fait = false;
console.log("reset _fait");
}
Voilà maintenant ça réinitialise le drapeau.
Il faut maintenant gérer le défilement inverse (le retour en arrière).
if (e.deltaY < -40 && !_fait) {
_indexImg--;
_fait = true;
console.log("image précedente");
}
Maintenant il reste à rassembler le bazar.
// init des variables
let _fait = false;
let _indexImg = 0;
// écouteur de molette souris (scroll au pad / variation de la roulette) placé sur window
window.addEventListener("wheel",(e) => {
// arrête la propagation de l'évenement
e.stopImmediatePropagation();
// bloque le comportement par défaut
e.preventDefault();
if (e.deltaY > 40 && !_fait && _indexImg < listeImg.length-1) {
// si deltaY est > 40 et pas au bout de la section (_indexImg < nbr img)
_indexImg++;
// la mesure est faite
_fait = true;
console.log("image suivante");
// déplace la section d'une largeur d'écran (change d'image)
document.querySelector("section").style.transform = "translateX(-"+_indexImg*100+"vw)";
} else if (e.deltaY < -40 && !_fait && _indexImg > 0) {
_indexImg--;
_fait = true;
console.log("image précédente");
document.querySelector("section").style.transform = "translateX(-"+_indexImg*100+"vw)";
}
// réinit booleenne _fait
if (e.deltaY < 20 && e.deltaY > -20) {_fait = false; console.log("reset _fait")}
});
Toute la navigation fonctionne avec un "index" (IndexImg : l'image encours) qui se déplace à l'intérieur des bornes de la table. Si l'index est égal ou supérieur à la longueur de la tablelisteImg, il n'y a plus d'images après.
Si l'index est à 0, il n'y en a plus avant.
On est aux bords.
Dans cette dernière étape du code, on teste donc les bords de la table (si on atteint la dernière [l'avant dernière puisque qu'il va changer l'image] ou la premiere image).
if […] _indexImg > 0 et if […] _indexImg < listeImg.length-1
Voilà. c'est perfectible, mais c'est fonctionnel en l'état.
Une dernière chose, les images en background sont ajustées en contain (le navigateur ajuste sur la hauteur du bloc) pour ne pas cropper une partie des images. vous pouvez changer cela.
[click droit > enregistrer le fichier source]
Vous trouverez vos images et ferez votre propre galerie.
ressources
Pour comprendre certaines parties du code que je n'ai pas expliquées, je vous renvoie vers le cours de Pierre Giraud, que GLG avait référencé pour le workshop intégration web