Ajout d'un exemple d'utilisation de vCarousel associé à Flickity (carrousel d'images).

This commit is contained in:
Fabrice PENHOËT 2021-04-08 12:41:47 +02:00
parent 3ec8ecbd65
commit 4d3ed007c0
14 changed files with 252 additions and 40 deletions

View File

@ -9,6 +9,7 @@ Lorsque la lecture d'une vidéo est achevée, elle disparaît pour faire appara
Il ne s'agit donc pas d'un carrousel servant à faire défiler horizontalement des balises vidéos. Il ne s'agit donc pas d'un carrousel servant à faire défiler horizontalement des balises vidéos.
Mais on peut très bien utiliser ce type de carrousel en parallèle pour naviguer entre les vidéos. Mais on peut très bien utiliser ce type de carrousel en parallèle pour naviguer entre les vidéos.
Un exemple d'utilisation avec [Flickity](https://www.npmjs.com/package/flickity) est fourni.
## Les grandes lignes de l'algorithme ## Les grandes lignes de l'algorithme

52
package-lock.json generated
View File

@ -1296,6 +1296,11 @@
"minimalistic-assert": "^1.0.0" "minimalistic-assert": "^1.0.0"
} }
}, },
"desandro-matches-selector": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/desandro-matches-selector/-/desandro-matches-selector-2.0.2.tgz",
"integrity": "sha1-cXvu1NwT59jzdi9wem1YpndCGOE="
},
"destroy": { "destroy": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
@ -1515,6 +1520,11 @@
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
"dev": true "dev": true
}, },
"ev-emitter": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ev-emitter/-/ev-emitter-1.1.1.tgz",
"integrity": "sha512-ipiDYhdQSCZ4hSbX4rMW+XzNKMD1prg/sTvoVmSLkuQ1MVlwjJQQA+sW8tMYR3BLUr9KjodFV4pvzunvRhd33Q=="
},
"eventemitter3": { "eventemitter3": {
"version": "4.0.7", "version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@ -1834,6 +1844,27 @@
"resolve-dir": "^1.0.1" "resolve-dir": "^1.0.1"
} }
}, },
"fizzy-ui-utils": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/fizzy-ui-utils/-/fizzy-ui-utils-2.0.7.tgz",
"integrity": "sha512-CZXDVXQ1If3/r8s0T+v+qVeMshhfcuq0rqIFgJnrtd+Bu8GmDmqMjntjUePypVtjHXKJ6V4sw9zeyox34n9aCg==",
"requires": {
"desandro-matches-selector": "^2.0.0"
}
},
"flickity": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/flickity/-/flickity-2.2.2.tgz",
"integrity": "sha512-yiPMuP8tw/zN7ARgeSLZNvzK11GkzI2mp/zlYBsyttguSCROAqxj6wiN2sSfPfW3xMG3hcUHxWUXNQMlk/wYcg==",
"requires": {
"desandro-matches-selector": "^2.0.0",
"ev-emitter": "^1.1.1",
"fizzy-ui-utils": "^2.0.7",
"get-size": "^2.0.3",
"unidragger": "^2.3.0",
"unipointer": "^2.3.0"
}
},
"flush-write-stream": { "flush-write-stream": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
@ -1935,6 +1966,11 @@
"has-symbols": "^1.0.1" "has-symbols": "^1.0.1"
} }
}, },
"get-size": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/get-size/-/get-size-2.0.3.tgz",
"integrity": "sha512-lXNzT/h/dTjTxRbm9BXb+SGxxzkm97h/PCIKtlN/CBCxxmkkIVV21udumMS93MuVTDX583gqc94v3RjuHmI+2Q=="
},
"get-stream": { "get-stream": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
@ -4575,6 +4611,14 @@
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
"dev": true "dev": true
}, },
"unidragger": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/unidragger/-/unidragger-2.3.1.tgz",
"integrity": "sha512-u+IgG7AG0MXJTKcdzAIYxCm+W5FcnA9M28203Awl6jIcE3/+9OtEyUX4Wv64y7XNKEVRKPot52IV4V6x7FlF5Q==",
"requires": {
"unipointer": "^2.3.0"
}
},
"union-value": { "union-value": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@ -4587,6 +4631,14 @@
"set-value": "^2.0.1" "set-value": "^2.0.1"
} }
}, },
"unipointer": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/unipointer/-/unipointer-2.3.0.tgz",
"integrity": "sha512-m85sAoELCZhogI1owtJV3Dva7GxkHk2lI7A0otw3o0OwCuC/Q9gi7ehddigEYIAYbhkqNdri+dU1QQkrcBvirQ==",
"requires": {
"ev-emitter": "^1.0.1"
}
},
"unique-filename": { "unique-filename": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "vCarousel", "name": "vCarousel",
"version": "0.1.0", "version": "0.2.0",
"description": "Video carousel, a new video appears when the previous one finishes playing.", "description": "Video carousel, a new video appears when the previous one finishes playing.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@ -24,5 +24,8 @@
"webpack": "^4.46.0", "webpack": "^4.46.0",
"webpack-cli": "^3.3.12", "webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2" "webpack-dev-server": "^3.11.2"
},
"dependencies": {
"flickity": "^2.2.2" // dépendance pouvant être retirée si vous n'utilisez pas Flickity dans votre application
} }
} }

4
public/CSS/flickity.min.css vendored Normal file
View File

@ -0,0 +1,4 @@
/*! Flickity v2.2.2
https://flickity.metafizzy.co
---------------------------------------------- */
.flickity-enabled{position:relative}.flickity-enabled:focus{outline:0}.flickity-viewport{overflow:hidden;position:relative;height:100%}.flickity-slider{position:absolute;width:100%;height:100%}.flickity-enabled.is-draggable{-webkit-tap-highlight-color:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.flickity-enabled.is-draggable .flickity-viewport{cursor:move;cursor:-webkit-grab;cursor:grab}.flickity-enabled.is-draggable .flickity-viewport.is-pointer-down{cursor:-webkit-grabbing;cursor:grabbing}.flickity-button{position:absolute;background:hsla(0,0%,100%,.75);border:none;color:#333}.flickity-button:hover{background:#fff;cursor:pointer}.flickity-button:focus{outline:0;box-shadow:0 0 0 5px #19f}.flickity-button:active{opacity:.6}.flickity-button:disabled{opacity:.3;cursor:auto;pointer-events:none}.flickity-button-icon{fill:currentColor}.flickity-prev-next-button{top:50%;width:44px;height:44px;border-radius:50%;transform:translateY(-50%)}.flickity-prev-next-button.previous{left:10px}.flickity-prev-next-button.next{right:10px}.flickity-rtl .flickity-prev-next-button.previous{left:auto;right:10px}.flickity-rtl .flickity-prev-next-button.next{right:auto;left:10px}.flickity-prev-next-button .flickity-button-icon{position:absolute;left:20%;top:20%;width:60%;height:60%}.flickity-page-dots{position:absolute;width:100%;bottom:-25px;padding:0;margin:0;list-style:none;text-align:center;line-height:1}.flickity-rtl .flickity-page-dots{direction:rtl}.flickity-page-dots .dot{display:inline-block;width:10px;height:10px;margin:0 8px;background:#333;border-radius:50%;opacity:.25;cursor:pointer}.flickity-page-dots .dot.is-selected{opacity:1}

21
public/CSS/vcarousel.css Normal file
View File

@ -0,0 +1,21 @@
body
{
text-align:center;
background-color:#C0D6D2;
}
#videos
{
border:1px solid;
width:800px;
margin:auto;
padding:1em;
text-align:center;
}
#video figure
{
padding-top:2em;
}
#videos video
{
width:600px;
}

48
public/flickity.html Normal file
View File

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Page d'exemple pour le script vCarousel avec un menu utilisant Flickity.">
<meta name="robots" content="noindex">
<link rel="stylesheet" href="CSS/vcarousel.css" media="screen">
<link rel="stylesheet" href="CSS/flickity.min.css" media="screen">
<script src="JS/exampleFlickity.app.js" defer></script>
<title>vCarousel (démo avec Flickity)</title>
</head>
<body>
<div id="videos">
<h1 id="title">vCarousel</h1>
<p>Dans cet exemple vCarousel est associé à un carrousel d'images plus classique gèré via <a href="https://flickity.metafizzy.co/" target="_blank" rel="noopener">flickity</a> servant de menu pour choisir la première vidéo à visionner. Ensuite vCarousel enchaîne les vidéos et synchronise l'affichage de flickity.</p>
<figure id="vFunanbule">
<video controls preload="metadata">
<source src="videos/Lizio-Poete-Ferrailleur-clownfunanbule.m4v" type="video/mp4"></source>
<p>Votre navigateur ne prend pas en charge les vidéos HTML5.</p>
</video>
<figcaption>Un clown funanbule !</figcaption>
</figure>
<figure id="vForgeron">
<video controls preload="metadata">
<source src="videos/Lizio-Poete-Ferrailleur-forgeron.m4v" type="video/mp4"></source>
<p>Votre navigateur ne prend pas en charge les vidéos HTML5.</p>
</video>
<figcaption>Il faut forger pour devenir forgeron !</figcaption>
</figure>
<figure id="vCircuit">
<video controls preload="metadata">
<source src="videos/Lizio-Poete-Ferrailleur-drole-de-circuit.m4v" type="video/mp4"></source>
<p>Votre navigateur ne prend pas en charge les vidéos HTML5.</p>
</video>
<figcaption>Drôle de circuit !</figcaption>
</figure>
<nav class="img-carousel">
<div class="carousel-cell"><a href="#vFunanbule" class="selectVideo"><img src="img/clownfunanbule.png" alt="Le funanbule"></a></div>
<div class="carousel-cell"><a href="#vForgeron" class="selectVideo"><img src="img/forgeron.png" alt="Le forgeron"></a></div>
<div class="carousel-cell"><a href="#vCircuit" class="selectVideo"><img src="img/drole-de-circuit.png" alt="Le drôle de circuit"></a></div>
</nav>
</div>
<aside><p>Les courtes vidéos de cette page d'exemple ont été enregistrées le 11 août 2016 au <a href="https://www.poeteferrailleur.com/" target="_blank">Poète ferrailleur</a> à Lizio dans le Morbihan.</p></aside>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
public/img/forgeron.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -2,43 +2,48 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>vCarousel (démo)</title> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Page d'exemple pour le script vCarousel."> <meta name="description" content="Page d'exemple simple d'utilisaion du script vCarousel.">
<meta name="robots" content="noindex"> <meta name="robots" content="noindex">
<link rel="stylesheet" href="CSS/vcarousel.css" media="screen">
<script src="JS/example.app.js" defer></script> <script src="JS/example.app.js" defer></script>
<title>vCarousel (démo utilisation simple)</title>
</head> </head>
<body> <body>
<h1 id="title">vCarousel</h1> <div id="videos">
<p>Lorsqu'une vidéo se termine, la suivante la remplace, prête à être lancée.</p> <h1>vCarousel</h1>
<figure id="vFunanbule"> <p>Exemple d'utilisation simple : lorsqu'une vidéo se termine, la suivante la remplace, prête à être lancée. <a href="/flickity.html">Voir un autre exemple d'utilisation où VCarousel est associé à un carrousel d'images</a>.</p>
<video controls="controls" preload="metadata" width="800">
<source src="videos/Lizio-Poete-Ferrailleur-clownfunanbule.m4v" type="video/mp4"></source> <figure id="vFunanbule">
<p>Votre navigateur ne prend pas en charge les vidéos HTML5.</p> <video controls="controls" preload="metadata" width="800">
</video> <source src="videos/Lizio-Poete-Ferrailleur-clownfunanbule.m4v" type="video/mp4"></source>
<figcaption>Un clown funanbule !</figcaption> <p>Votre navigateur ne prend pas en charge les vidéos HTML5.</p>
</figure> </video>
<figure id="vForgeron"> <figcaption>Un clown funanbule !</figcaption>
<video controls="controls" preload="metadata" width="800"> </figure>
<source src="videos/Lizio-Poete-Ferrailleur-forgeron.m4v" type="video/mp4"></source> <figure id="vForgeron">
<p>Votre navigateur ne prend pas en charge les vidéos HTML5.</p> <video controls="controls" preload="metadata" width="800">
</video> <source src="videos/Lizio-Poete-Ferrailleur-forgeron.m4v" type="video/mp4"></source>
<figcaption>Il faut forger pour devenir forgeron !</figcaption> <p>Votre navigateur ne prend pas en charge les vidéos HTML5.</p>
</figure> </video>
<figure id="vCircuit"> <figcaption>Il faut forger pour devenir forgeron !</figcaption>
<video controls="controls" preload="metadata" width="800"> </figure>
<source src="videos/Lizio-Poete-Ferrailleur-drole-de-circuit.m4v" type="video/mp4"></source> <figure id="vCircuit">
<p>Votre navigateur ne prend pas en charge les vidéos HTML5.</p> <video controls="controls" preload="metadata" width="800">
</video> <source src="videos/Lizio-Poete-Ferrailleur-drole-de-circuit.m4v" type="video/mp4"></source>
<figcaption>Drôle de circuit !</figcaption> <p>Votre navigateur ne prend pas en charge les vidéos HTML5.</p>
</figure> </video>
<nav> <figcaption>Drôle de circuit !</figcaption>
<h3>Au menu</h3> </figure>
<ul> <nav>
<li><a href="#vFunanbule" class="selectVideo">Le funanbule</a></li> <h3>Au menu</h3>
<li><a href="#vForgeron" class="selectVideo">Le forgeron</a></li> <ul>
<li><a href="#vCircuit" class="selectVideo">Le circuit</a></li> <li><a href="#vFunanbule" class="selectVideo">Le funanbule</a></li>
</ul> <li><a href="#vForgeron" class="selectVideo">Le forgeron</a></li>
</nav> <li><a href="#vCircuit" class="selectVideo">Le circuit</a></li>
<aside><p>Les courtes vidéos de cette page d'exemple ont été enregistrées le 11 août 2016 au <a href="https://www.poeteferrailleur.com/">Poète ferrailleur</a> à Lizio dans le Morbihan.</p></aside> </ul>
</nav>
</div>
<aside><p>Les courtes vidéos de cette page d'exemple ont été enregistrées le 11 août 2016 au <a href="https://www.poeteferrailleur.com/" target="_blank">Poète ferrailleur</a> à Lizio dans le Morbihan.</p></aside>
</body> </body>
</html> </html>

View File

@ -1,15 +1,15 @@
/// Exemple d'utilisation de vCarousel avec 3 vidéos /// Exemple d'utilisation simple de vCarousel avec 3 vidéos
import { vCarousel } from "./vCarousel"; import { vCarousel } from "./vCarousel";
try try
{ {
// Liste des id des contenants des vidéos à afficher : // Liste des id des contenants des vidéos à faire tourner :
const videosContainers=["vFunanbule", "vForgeron", "vCircuit"]; const videosContainers=["vFunanbule", "vForgeron", "vCircuit"];
// Si un id est fourni par l'url, on affiche cette vidéo en premier : // Si un id est fourni par l'url, on affiche cette vidéo en premier :
if(window.location.hash!==undefined && window.location.hash!=="") if(window.location.hash!==undefined && window.location.hash!=="")
vCarousel(videosContainers, window.location.hash.replace("#","")); vCarousel(videosContainers, window.location.hash.replace("#",""));
else else
vCarousel(videosContainers);// le deuxième paramètre est facultatif sauf si on souhaite qu'une des vidéos soit affichée par défaut vCarousel(videosContainers);// le deuxième paramètre est facultatif, sauf si on souhaite qu'une vidéo autre que la première soit affichée par défaut
// Dans le cas où l'utilisateur clique pour sélectionner une vidéo à afficher, on actualise l'affichage : // Dans le cas où l'utilisateur clique pour sélectionner une vidéo à afficher, on actualise l'affichage :
let selectLinks=document.querySelectorAll(".selectVideo"); let selectLinks=document.querySelectorAll(".selectVideo");

76
src/exampleFlickity.ts Normal file
View File

@ -0,0 +1,76 @@
/// Exemple d'utilisation de vCarousel avec 3 vidéos, proposées via un carrousel d'images Flickity
const Flickity = require("flickity");
import { vCarousel } from "./vCarousel";
// Cette fonction sert à synchroniser si besoin l'image sélectionnée dans le carrousel Flickity avec le hash de l'url.
const selectFlickityForHash = (flickityCarousel:any, urlHash:string) : void =>
{
let nb=0, find=false;
// On parcourt les items du carrousel pour trouver celui contenant le lien vers ce hash.
for(let cel of flickityCarousel.cells)
{
let childrens = cel.element.childNodes;
for (let i = 0, c = childrens.length; i < c; i++)
{
if (childrens[i].nodeType === Node.ELEMENT_NODE)
{
if(childrens[i].hash!=undefined && childrens[i].hash===urlHash)
{
flickityCarousel.select(nb);// API Flickity : https://flickity.metafizzy.co/api.html
find=true;
break;
}
}
}
nb++;
}
if(find===false)
console.error("L'ancre fournie par l'url n'a pas été trouvée dans le carrousel Flickity.");
}
try
{
// Carrousel Flickity :
const imgCarousel = document.querySelector(".img-carousel");
const flktyCarousel = new Flickity(imgCarousel,
{
// options : https://flickity.metafizzy.co/options.html
accessibility: true,
cellAlign: "center",
contain: true,
rightToLeft: true,
wrapAround: true,
});
// Liste des id des contenants des vidéos à faire tourner :
const videosContainers=["vFunanbule", "vForgeron", "vCircuit"];
// Si un id est fourni par l'url, on affiche cette vidéo en premier :
if(window.location.hash!==undefined && window.location.hash!=="")
{
vCarousel(videosContainers, window.location.hash.replace("#",""));
selectFlickityForHash(flktyCarousel, location.hash);
}
else
vCarousel(videosContainers, ""); // dans cet exemple, on cache toutes les vidéos avant que l'utilisateur ne fasse son choix dans le carrousel d'images.
// Lorsque l'utilisateur clique sur une des images pour sélectionner une vidéo à afficher, on actualise l'affichage :
let selectLinks=document.querySelectorAll(".selectVideo");
for (let i = 0; i < selectLinks.length; i++)
{
let link=<HTMLAnchorElement>selectLinks[i];
link.addEventListener("click", function(e)
{
vCarousel(videosContainers, link.hash.replace("#",""));
});
}
// De même quand le hash change, on adapte l'item sélectionné de flickity
// Ceci permet de suivre le parcours des vidéos par vCarousel
window.addEventListener('hashchange', function()
{
selectFlickityForHash(flktyCarousel, location.hash);
});
}
catch(e)
{
console.error(e);
}

View File

@ -1,9 +1,10 @@
const Flickity = require("flickity");
/// La fonction vCarousel reçoit un tableau d'ids des conteneurs HTML des vidéos à afficher successivement. /// La fonction vCarousel reçoit un tableau d'ids des conteneurs HTML des vidéos à afficher successivement.
/// Le tableau n'est pas dédoublonné, pour rester libre d'afficher plusieurs fois la même vidéo durant un tour du carrousel. /// Le tableau n'est pas dédoublonné, pour rester libre d'afficher plusieurs fois la même vidéo durant un tour du carrousel.
/// On peut éventuellement fournir l'id du conteneur de la première vidéo à afficher lors de l'appel /// On peut éventuellement fournir l'id du conteneur de la première vidéo à afficher lors de l'appel
/// Ou encore indiqué qu'aucune ne doit être affichée sans action en passant une chaîne vide /// Ou encore indiqué qu'aucune ne doit être affichée sans action en passant une chaîne vide
/// Par défaut la première vidéo de la liste sera affichée /// Par défaut la première vidéo de la liste sera affichée
export const vCarousel = (vContainers:string[], firstVideoId?:string) : void => export const vCarousel = (vContainers:string[], firstVideoId?:string) : void =>
{ {
interface videoDOM interface videoDOM

View File

@ -6,7 +6,8 @@ module.exports =
devtool: "inline-source-map", devtool: "inline-source-map",
entry: entry:
{ {
example: "./src/example.ts" example: "./src/example.ts",
exampleFlickity: "./src/exampleFlickity.ts"
}, },
output: output:
{ {