Coder un scrolling parallax en javascript
Voici l’épilogue des articles sur le scrolling parallax, je vous montre comment réaliser un scrolling parallax en html5 et javascript. Je vous montre comme il est simple de faire un scrolling parallax en html5 et javascript.
Prérequis
Avoir lu les articles suivants :
– Coder un scrolling horizontal en html5 et javascript;
– Le principe du scrolling parallax html5 et javascript.
Le canvas html5 nécessaire au scrolling parallax
En html5, on commence par créer un canvas html5 auquel une donne une taille équivalente à celle de nos 4 plans:
<canvas id="theCanvas" width="320" height="240" style="border: 1px solid #000000;"/>
Jusque là, rien de très compliqué. Mais rassurez vous la suite ne l’est pas non plus.
Initialisation
On isole toujours notre code javascript de tout autre code de page par le biais d’une fonction anonyme auto exécutée comme suit.
( function() {
// zone de code protégé
}());
Le code source de notre page html prend donc la forme suivante.
<script>
( function() {
// zone de code protégé
}());
</script>
<body>
<canvas id="theCanvas" width="320" height="240" style="border: 1px solid #000000;"/>
</body>
</html>
Le canvas context
A l’initialisation, il nous faut récupérer notre canvas ainsi que son contexte. Bien entendu, nous aurions pu créer le canvas directement en javascript.
Nous créons une fonction d’initialisation appelée au chargement de la page, sur l’évènement javascript load, qui initialise une variable canvas2DContext comme suit.
let canvas;
let canvas2DContext;
let initialisation = function() {
canvas = document.getElementById("theCanvas");
canvas2DContext = canvas.getContext('2d');
}
Appel de la fonction au chargement de la page.
window.addEventListener('load', function() {
initialisation();
});
Pour plus de détails à ce propos, référez vous à l’article Le canvas html5.
Au final, le code javascript devient.
( function() {
let canvas;
let canvas2DContext;
let initialisation = function() {
canvas = document.getElementById("theCanvas");
canvas2DContext = canvas.getContext('2d');
}
window.addEventListener('load', function() {
initialisation();
});
}());
Déplacement du premier plan du scrolling
Nous enrichissons la fonction d’initialisation par la déclaration de l’image de notre premier plan.
let canvas;
let canvas2DContext;
let imagePlan1 = new Image();
let initialisation = function() {
canvas = document.getElementById("theCanvas");
canvas2DContext = canvas.getContext('2d');
imagePlan1.src = "plan1.png";
}
Nous allons faire scroller la même image 2 fois l’une derrière l’autre de la gauche vers la droite pour simuler la continuité du scrolling : le scrolling tourne en boucle.
A l’initialisation, nous affichons cette image 2 fois : la première recouvre complètement le canvas html5 et la deuxième est affichée en dehors du canvas html5 à la gauche de la première.
La deuxième image a donc une abscisse négative correspondant à sa longueur.
On crée donc deux variables :
– la variable plan1X1 stockant l’abscisse de la première image;
– la variable plan1X2 stockant l’abscisse de la deuxième image.
Elles sont initialisées comme suit.
let plan1X1 = 0;
let plan1X2 = -imagePlan1.width;
On l’intègre à notre code existant.
let canvas;
let canvas2DContext;
let imagePlan1 = new Image();
let plan1X1 = 0;
let plan1X2 = 0;
let initialisation = function() {
canvas = document.getElementById("theCanvas");
canvas2DContext = canvas.getContext('2d');
imagePlan1.src = "plan1.png";
plan1X2 = -imagePlan1.width;
canvas2DContext.drawImage(imagePlan1,plan1X1,0);
canvas2DContext.drawImage(imagePlan1,plan1X2,0);
}
Pour donner l’illusion du déplacement des images, il ne reste plus qu’à :
– les déplacer simultanément de la gauche vers la droite de 5 pixels à la fois;
– et les réafficher chaque fois que les abscisses sont incrémentées.
On crée alors une nouvelle fonction scroll chargée de réaliser ces 2 opérations.
function scroll() {
plan1X1++;
plan1X2++;
canvas2DContext.drawImage(imagePlan1,plan1X1,0);
canvas2DContext.drawImage(imagePlan1,plan1X2,0);
}
Et appeler cette fonction à intervalles réguliers via l’instruction setinterval qui prend en paramètres le nom d’une fonction à appeler et l’intervalle d’appel exprimé en millisecondes.
( function() {
let canvas;
let canvas2DContext;
let imagePlan1 = new Image();
let plan1X1 = 0;
let plan1X2 = 0;
let initialisation = function() {
canvas = document.getElementById("theCanvas");
canvas2DContext = canvas.getContext('2d');
imagePlan1.src = "plan1.png";
plan1X2 = -imagePlan1.width;
canvas2DContext.drawImage(imagePlan1,plan1X1,0);
canvas2DContext.drawImage(imagePlan1,plan1X2,0);
}
function scroll() {
plan1X1++;
plan1X2++;
canvas2DContext.drawImage(imagePlan1,plan1X1,0);
canvas2DContext.drawImage(imagePlan1,plan1X2,0);
}
window.addEventListener('load', function() {
initialisation();
setInterval(scroll, 100);
});
}());
Et voici le rendu.
Le rendu n’est pas satisfaisant puisque nos palmiers laissent des traces en se déplaçant.
Pour pallier à cela, il suffit simplement d’effacer le canvas html5 par le biais de l’instruction clearRect, entre deux affichages. On modifie la fonction scroll en ce sens.
function scroll() {
plan1X1++;
plan1X2++;
canvas2DContext.clearRect(0, 0, canvas.width, canvas.height);
canvas2DContext.drawImage(imagePlan1,plan1X1,0);
canvas2DContext.drawImage(imagePlan1,plan1X2,0);
}
Et là, le rendu est nickel. Mais le travail n’est pas terminé car dès que les 2 images auront scrollé, le canvas html5 deviendra blanc : plus de scrolling.
En réalité, les images continuent d’avancer mais en dehors du canvas html5. Nous devons donc réinitialiser l’abscisse de chacune d’elles dès qu’elle sort du canvas html5 : une image sort de la droite du canvas html5 dès que son abscisse atteint la limite du canvas html5 représentée par sa taille (canvas.width).
Nous ajoutons donc un test qui vérifie que l’abscisse dépasse la limite du canvas et qui dans ce cas la réinitialise.
La réinitialisation consiste à replacer l’image à la gauche de celle affichée à l’écran : une image atteint la limite du canvas html5 lorsque l’image qui la suit y est pleinement affichée.
Pour plus détails, référez vous à l’article scrolling html5 en javascript
Nous ajoutons les 2 tests suivants.
if ( plan1X1 > canvas.width ) {
plan1X1 = -canvas.width;
}
if ( plan1X2 > canvas.width ) {
plan1X2 = -canvas.width;
}
Remarquez que le fait d’incrémenter la position des images puis de tester si elle dépasse la limite du canvas html5 revient en fait à boucler sur une série de valeurs allant de -320 à 320.
Nous pouvons donc simplifier l’incrément et le test en utilisant la fonction modulo (le reste de la division) sur 640, valeur qui correspond au nombre de points qui séparent -320 et 320.
plan1X1 = (plan1X1 + 1) % 640;
plan1X2 = (plan1X2 + 1) % 640;
Avec cette formule, nos valeurs vont boucler de 0 à 640, or nos valeurs d’affichage vont de -320 à 320. Il nous faut donc modifier l’appel de la fonction drawImage pour que l’affichage se fasse correctement.
canvas2DContext.drawImage(imagePlan1,plan1X1-320,0);
canvas2DContext.drawImage(imagePlan1,plan1X2-320,0);
Enfin il faut aussi modifier les valeurs d’affichage de départ de nos 2 images.
plan1X1 = 0;
plan1X2 = canvas.width;
Le code complet.
( function() {
let canvas;
let canvas2DContext;
let imagePlan1 = new Image();
let plan1X1 = 0;
let plan1X2 = 0;
let initialisation = function() {
canvas = document.getElementById("theCanvas");
canvas2DContext = canvas.getContext('2d');
imagePlan1.src = "plan1.png";
plan1X2 = canvas.width;
}
function scroll() {
plan1X1 = (plan1X1 + 1) % 640;
plan1X2 = (plan1X2 + 1) % 640;
canvas2DContext.clearRect(0, 0, canvas.width, canvas.height);
canvas2DContext.drawImage(imagePlan1,plan1X1-320,0);
canvas2DContext.drawImage(imagePlan1,plan1X2-320,0);
}
window.addEventListener('load', function() {
initialisation();
setInterval(scroll, 100);
});
}());
Ajout des 3 autres plans pour l’effet parallax
Il ne reste plus qu’à ajouter nos 3 autres plans, et de faire scroller les 4 plans à des vitesses différentes. La vitesse la plus élévée pour le premier plan et la vitesse la moins élevée pour le quatrième.
3 autres plans donc 3 nouvelles images donc 3 nouvelles instances.
let imagePlan1 = new Image();
let imagePlan2 = new Image();
let imagePlan3 = new Image();
let imagePlan4 = new Image();
associées à 3 fichiers images distincts.
imagePlan1.src = "plan1.png";
imagePlan2.src = "plan2.png";
imagePlan3.src = "plan3.png";
imagePlan4.src = "plan4.png";
Chaque image étant affichée 2 fois, il nous faut ajouter que 3 x 2 variables pour les abscisses.
let plan1X1 = 0;
let plan1X2 = 0;
let plan2X1 = 0;
let plan2X2 = 0;
let plan3X1 = 0;
let plan3X2 = 0;
let plan4X1 = 0;
let plan4X2 = 0;
Et initialisez la moitié d’entre elles à la valeur canvas.width.
plan1X2 = canvas.width;
plan2X2 = canvas.width;
plan3X2 = canvas.width;
plan4X2 = canvas.width;
Et que l’ont fait boucler de -320 à 320 à 4 vitesses différentes.
plan1X1 = (plan1X1 + 4) % 640;
plan1X2 = (plan1X2 + 4) % 640;
plan2X1 = (plan2X1 + 3) % 640;
plan2X2 = (plan2X2 + 3) % 640;
plan3X1 = (plan3X1 + 2) % 640;
plan3X2 = (plan3X2 + 2) % 640;
plan4X1 = (plan4X1 + 1) % 640;
plan4X2 = (plan4X2 + 1) % 640;
Puis afficher chacune des images en prenant soin d’afficher les plans du fond en premier, dans le cas inverse on ne verrait que le quatrième scrollé.
canvas2DContext.drawImage(imagePlan4,plan4X1 - 320,0);
canvas2DContext.drawImage(imagePlan4,plan4X2 - 320,0);
canvas2DContext.drawImage(imagePlan3,plan3X1 - 320,0);
canvas2DContext.drawImage(imagePlan3,plan3X2 - 320,0);
canvas2DContext.drawImage(imagePlan2,plan2X1 - 320,0);
canvas2DContext.drawImage(imagePlan2,plan2X2 - 320,0);
canvas2DContext.drawImage(imagePlan1,plan1X1 - 320,0);
canvas2DContext.drawImage(imagePlan1,plan1X2 - 320,0);
Vous remarquerez que pour chaque plan supplémentaire on ajoute :
– une image du plan à scroller;
– une variable pour l’image;
– deux variables pour les abscisses d’affichage des deux images l’une initialisée à zéro l’autre à la valeur de la taille du canvas html5;
– l’incrémentation des abscisses;
– l’affichage de chacune des images.
Le code complet
( function() {
let canvas;
let canvas2DContext;
let imagePlan1 = new Image();
let imagePlan2 = new Image();
let imagePlan3 = new Image();
let imagePlan4 = new Image();
let plan1X1 = 0;
let plan1X2 = 0;
let plan2X1 = 0;
let plan2X2 = 0;
let plan3X1 = 0;
let plan3X2 = 0;
let plan4X1 = 0;
let plan4X2 = 0;
let initialisation = function() {
canvas = document.getElementById("theCanvas");
canvas2DContext = canvas.getContext('2d');
imagePlan1.src = "plan1.png";
imagePlan2.src = "plan2.png";
imagePlan3.src = "plan3.png";
imagePlan4.src = "plan4.png";
plan1X2 = canvas.width;
plan2X2 = canvas.width;
plan3X2 = canvas.width;
plan4X2 = canvas.width;
}
function scroll() {
plan1X1 = (plan1X1 + 4) % 640;
plan1X2 = (plan1X2 + 4) % 640;
plan2X1 = (plan2X1 + 3) % 640;
plan2X2 = (plan2X2 + 3) % 640;
plan3X1 = (plan3X1 + 2) % 640;
plan3X2 = (plan3X2 + 2) % 640;
plan4X1 = (plan4X1 + 1) % 640;
plan4X2 = (plan4X2 + 1) % 640;
canvas2DContext.clearRect(0, 0, canvas.width, canvas.height);
canvas2DContext.drawImage(imagePlan4,plan4X1 - 320,0);
canvas2DContext.drawImage(imagePlan4,plan4X2 - 320,0);
canvas2DContext.drawImage(imagePlan3,plan3X1 - 320,0);
canvas2DContext.drawImage(imagePlan3,plan3X2 - 320,0);
canvas2DContext.drawImage(imagePlan2,plan2X1 - 320,0);
canvas2DContext.drawImage(imagePlan2,plan2X2 - 320,0);
canvas2DContext.drawImage(imagePlan1,plan1X1 - 320,0);
canvas2DContext.drawImage(imagePlan1,plan1X2 - 320,0);
}
window.addEventListener('load', function() {
initialisation();
setInterval(scroll, 100);
});
}());
Pour la démo c’est ici.