Dessiner un secteur circulaire en CSS
/* Cercle de base */
.cercle-base {
width: 100px;
height: 100px;
border-radius: 50%;
background: #e74c3c;
position: relative;
}
/* Premier masque pour créer le secteur */
.masque-premier {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 50px;
background: white;
transform-origin: 50px 50px;
transform: rotate(75deg);
}
/* Second masque avec rotation différente */
.masque-second {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 50px;
background: white;
transform-origin: 50px 50px;
transform: rotate(150deg);
}
Chargement paresseux des images
document.addEventListener('DOMContentLoaded', () => {
const imagesParesseuses = Array.from(document.querySelectorAll('img[data-src]'));
if (!('IntersectionObserver' in window)) {
// Fallback pour les navigateurs anciens
imagesParesseuses.forEach(img => {
img.src = img.dataset.src;
});
return;
}
const observateur = new IntersectionObserver((entrees) => {
entrees.forEach(entree => {
if (entree.isIntersecting) {
const image = entree.target;
image.src = image.dataset.src;
observateur.unobserve(image);
}
});
});
imagesParesseuses.forEach(img => observateur.observe(img));
});
Glisser-déposer de la souris
const elementDeplacable = document.querySelector('.deplacable');
let decalageX, decalageY;
elementDeplacable.addEventListener('mousedown', debutDeplacement);
function debutDeplacement(evenement) {
decalageX = evenement.clientX - elementDeplacable.offsetLeft;
decalageY = evenement.clientY - elementDeplacable.offsetTop;
document.addEventListener('mousemove', deplacerElement);
document.addEventListener('mouseup', arreterDeplacement);
}
function deplacerElement(evenement) {
let nouvelleGauche = evenement.clientX - decalageX;
let nouveauHaut = evenement.clientY - decalageY;
// Limites de l'écran
const limiteDroite = window.innerWidth - elementDeplacable.offsetWidth;
const limiteBas = window.innerHeight - elementDeplacable.offsetHeight;
nouvelleGauche = Math.max(0, Math.min(nouvelleGauche, limiteDroite));
nouveauHaut = Math.max(0, Math.min(nouveauHaut, limiteBas));
elementDeplacable.style.left = `${nouvelleGauche}px`;
elementDeplacable.style.top = `${nouveauHaut}px`;
}
function arreterDeplacement() {
document.removeEventListener('mousemove', deplacerElement);
document.removeEventListener('mouseup', arreterDeplacement);
}
Addition de nombres flottants
function multiplicationPrecise(premier, second) {
const chainePremier = premier.toString();
const chaineSecond = second.toString();
let decimales = 0;
try { decimales += chainePremier.split('.')[1].length; } catch (e) {}
try { decimales += chaineSecond.split('.')[1].length; } catch (e) {}
const nombreEntierPremier = Number(chainePremier.replace('.', ''));
const nombreEntierSecond = Number(chaineSecond.replace('.', ''));
return (nombreEntierPremier * nombreEntierSecond) / Math.pow(10, decimales);
}
// Exemple d'utilisation
console.log(multiplicationPrecise(0.1, 0.2)); // 0.02
Planificateur de tâches concurrentes
class PlanificateurTaches {
constructor(maxSimultanees = 3) {
this.maximum = maxSimultanees;
this.enCours = 0;
this.fileAttente = [];
}
ajouter(tache) {
return new Promise((resolution, rejet) => {
const travail = { tache, resolution, rejet };
this.fileAttente.push(travail);
this.executer();
});
}
async executer() {
while (this.fileAttente.length > 0 && this.enCours < this.maximum) {
this.enCours++;
const travail = this.fileAttente.shift();
try {
const resultat = await travail.tache();
travail.resolution(resultat);
} catch (erreur) {
travail.rejet(erreur);
} finally {
this.enCours--;
this.executer();
}
}
}
}
// Exemple d'utilisation
const planificateur = new PlanificateurTaches(2);
const simulerRequete = (delai, identifiant) => {
return new Promise(resolution => {
setTimeout(() => {
console.log(`Tâche ${identifiant} terminée`);
resolution(identifiant);
}, delai);
});
};
planificateur.ajouter(() => simulerRequete(1000, 'A'));
planificateur.ajouter(() => simulerRequete(500, 'B'));
planificateur.ajouter(() => simulerRequete(800, 'C'));
planificateur.ajouter(() => simulerRequete(300, 'D'));
Chaînage asynchrone avec temporisation
class Actionneur {
constructor() {
this.chaine = Promise.resolve();
}
executer(action) {
this.chaine = this.chaine.then(() => action());
return this;
}
attendre(secondes) {
return this.executer(() =>
new Promise(resolution =>
setTimeout(resolution, secondes * 1000)
)
);
}
afficher(message) {
return this.executer(() => {
console.log(message);
return Promise.resolve();
});
}
}
// Exemple d'utilisation
const actionneur = new Actionneur();
actionneur
.afficher('Début')
.attendre(2)
.afficher('Après 2 secondes')
.attendre(3)
.afficher('Fin');
Modèles de conception
Adaptateur
// Interface incompatible avec le système
const cartographieNouvelle = {
dessiner() {
console.log('Rendu de la nouvelle carte');
}
};
// Adaptateur pour l'interface attendue
const adaptateurCarte = {
afficher() {
cartographieNouvelle.dessiner();
}
};
// Le client utilise l'adaptateur comme s'il utilisait l'ancienne interface
function utiliserCarte(adaptateur) {
adaptateur.afficher();
}
utiliserCarte(adaptateurCarte);
Observateur (Éditeur-Abonné)
class BusEvenements {
constructor() {
this.abonnes = new Map();
}
sAbonner(nomEvenement, callback) {
if (!this.abonnes.has(nomEvenement)) {
this.abonnes.set(nomEvenement, new Set());
}
this.abonnes.get(nomEvenement).add(callback);
// Retourne une fonction de désabonnement
return () => this.abonnes.get(nomEvenement)?.delete(callback);
}
publier(nomEvenement, ...donnees) {
const callbacks = this.abonnes.get(nomEvenement);
if (callbacks) {
callbacks.forEach(callback => callback(...donnees));
}
}
sAbonnerUneFois(nomEvenement, callback) {
const desabonnement = this.sAbonner(nomEvenement, (...args) => {
callback(...args);
desabonnement();
});
return desabonnement;
}
}
// Exemple d'utilisation
const bus = new BusEvenements();
const desabonnement = bus.sAbonner('message', contenu => {
console.log('Message reçu:', contenu);
});
bus.publier('message', 'Bonjour le monde!');
desabonnement(); // Se désabonner
Singleton
class GestionnaireConfig {
static instance = null;
constructor() {
if (GestionnaireConfig.instance) {
return GestionnaireConfig.instance;
}
this.parametres = {};
GestionnaireConfig.instance = this;
}
definir(cle, valeur) {
this.parametres[cle] = valeur;
return this;
}
obtenir(cle) {
return this.parametres[cle];
}
}
// Partout dans l'application, on obtient la même instance
const config1 = new GestionnaireConfig();
config1.definir('langue', 'fr');
const config2 = new GestionnaireConfig();
console.log(config2.obtenir('langue')); // 'fr' - même instance
Distribution aléatoire de mnotants
function distribuerMontant(total, nombrePersonnes) {
if (total < nombrePersonnes) {
throw new Error('Montant insuffisant');
}
const resultats = [];
let restant = total;
let personnesRestantes = nombrePersonnes;
// Distribution aléatoire pour n-1 personnes
for (let i = 0; i < nombrePersonnes - 1; i++) {
// Minimum 1 centime, maximum (restant - personnesRestantes + 1)
const maximum = restant - personnesRestantes + 1;
const montant = Math.floor(Math.random() * maximum) + 1;
resultats.push(montant);
restant -= montant;
personnesRestantes--;
}
// La dernière personne reçoit le reste
resultats.push(restant);
// Mélanger pour plus d'équité
return melangerTableau(resultats);
}
function melangerTableau(tableau) {
const copie = [...tableau];
for (let i = copie.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[copie[i], copie[j]] = [copie[j], copie[i]];
}
return copie;
}
// Exemple d'utilisation
const montants = distribuerMontant(1000, 5); // 10€ pour 5 personnes
console.log(montants.map(m => (m / 100).toFixed(2) + '€'));
Formatage de nombres avec séparateurs
function formaterNombre(nombre) {
const [entier, decimal] = nombre.toString().split('.');
let resultat = '';
let compteur = 0;
// Parcourir de droite à gauche
for (let i = entier.length - 1; i >= 0; i--) {
compteur++;
resultat = entier[i] + resultat;
// Ajouter un séparateur tous les 3 chiffres
if (compteur % 3 === 0 && i !== 0) {
resultat = ' ' + resultat;
}
}
return decimal ? `${resultat},${decimal}` : resultat;
}
// Exemples
console.log(formaterNombre(1234567.89)); // "1 234 567,89"
console.log(formaterNombre(100000)); // "100 000"
Algorithmes de tri
Tri à bulles optimisé
function triABullesOptimise(tableau) {
const n = tableau.length;
let permutationEffectuee = true;
for (let i = 0; i < n - 1 && permutationEffectuee; i++) {
permutationEffectuee = false;
for (let j = 0; j < n - 1 - i; j++) {
if (tableau[j] > tableau[j + 1]) {
// Échange des éléments
[tableau[j], tableau[j + 1]] = [tableau[j + 1], tableau[j]];
permutationEffectuee = true;
}
}
}
return tableau;
}
Tri par fusion
function triParFusion(tableau) {
if (tableau.length <= 1) return tableau;
const milieu = Math.floor(tableau.length / 2);
const gauche = tableau.slice(0, milieu);
const droite = tableau.slice(milieu);
return fusionner(
triParFusion(gauche),
triParFusion(droite)
);
}
function fusionner(gauche, droite) {
let i = 0, j = 0;
const resultat = [];
while (i < gauche.length && j < droite.length) {
if (gauche[i] <= droite[j]) {
resultat.push(gauche[i++]);
} else {
resultat.push(droite[j++]);
}
}
return resultat
.concat(gauche.slice(i))
.concat(droite.slice(j));
}
Tri rapide (Quicksort)
function triRapide(tableau, debut = 0, fin = tableau.length - 1) {
if (debut < fin) {
const pivotIndex = partitionner(tableau, debut, fin);
triRapide(tableau, debut, pivotIndex - 1);
triRapide(tableau, pivotIndex + 1, fin);
}
return tableau;
}
function partitionner(tableau, debut, fin) {
// Choisir un pivot aléatoire
const pivotAleatoire = debut + Math.floor(Math.random() * (fin - debut + 1));
[tableau[debut], tableau[pivotAleatoire]] = [tableau[pivotAleatoire], tableau[debut]];
const pivot = tableau[debut];
let gauche = debut + 1;
let droite = fin;
while (gauche <= droite) {
while (gauche <= droite && tableau[gauche] <= pivot) gauche++;
while (gauche <= droite && tableau[droite] > pivot) droite--;
if (gauche < droite) {
[tableau[gauche], tableau[droite]] = [tableau[droite], tableau[gauche]];
}
}
[tableau[debut], tableau[droite]] = [tableau[droite], tableau[debut]];
return droite;
}
Conversion tableau arborescent
const donneesPlates = [
{ id: 1, parent: null, libelle: 'Racine' },
{ id: 2, parent: 1, libelle: 'Enfant A' },
{ id: 3, parent: 1, libelle: 'Enfant B' },
{ id: 4, parent: 2, libelle: 'Petit-enfant A1' },
{ id: 5, parent: 2, libelle: 'Petit-enfant A2' },
];
function construireArborescence(elements, parentId = null) {
const noeuds = elements.filter(el => el.parent === parentId);
return noeuds.map(noeud => ({
...noeud,
enfants: construireArborescence(elements, noeud.id)
}));
}
// Exemple d'utilisation
const arbre = construireArborescence(donneesPlates);
console.log(JSON.stringify(arbre, null, 2));
Parcours d'arbre DOM
function parcourirLargeur(racine) {
if (!racine) return;
const file = [racine];
const etiquettes = [];
while (file.length > 0) {
const noeudCourant = file.shift();
if (noeudCourant.tagName) {
etiquettes.push(noeudCourant.tagName.toLowerCase());
}
// Ajouter les enfants à la file
const enfants = Array.from(noeudCourant.children);
file.push(...enfants);
}
return etiquettes;
}
// Exemple d'utilisation
// const tousTags = parcourirLargeur(document.body);
Comparaison profonde d'objets
function comparerEnProfondeur(objet1, objet2, visites = new WeakMap()) {
// Vérification identité stricte
if (objet1 === objet2) return true;
// Gestion des valeurs nulles/undefined
if (objet1 == null || objet2 == null) {
return objet1 === objet2;
}
// Vérification des types
if (typeof objet1 !== typeof objet2) return false;
// Détection des références circulaires
if (visites.has(objet1) && visites.get(objet1) === objet2) {
return true;
}
visites.set(objet1, objet2);
// Comparaison des dates
if (objet1 instanceof Date && objet2 instanceof Date) {
return objet1.getTime() === objet2.getTime();
}
// Comparaison des expressions régulières
if (objet1 instanceof RegExp && objet2 instanceof RegExp) {
return objet1.toString() === objet2.toString();
}
// Comparaison des tableaux
if (Array.isArray(objet1) && Array.isArray(objet2)) {
if (objet1.length !== objet2.length) return false;
return objet1.every((element, index) =>
comparerEnProfondeur(element, objet2[index], visites)
);
}
// Comparaison des objets
const cles1 = Object.keys(objet1);
const cles2 = Object.keys(objet2);
if (cles1.length !== cles2.length) return false;
return cles1.every(cle =>
Object.prototype.hasOwnProperty.call(objet2, cle) &&
comparerEnProfondeur(objet1[cle], objet2[cle], visites)
);
}
Fonction anti-rebond (debounce)
function antiRebonction(fonction, delai) {
let temporisateur;
return function(...args) {
const contexte = this;
clearTimeout(temporisateur);
temporisateur = setTimeout(() => {
fonction.apply(contexte, args);
}, delai);
};
}
// Exemple d'utilisation
const rechercher = antiRebonction((terme) => {
console.log('Recherche pour:', terme);
}, 300);
// input.addEventListener('input', e => rechercher(e.target.value));
Fonction d'étranglement (throttle)
function etrangleur(fonction, intervalle) {
let dernierAppel = 0;
let temporisateur;
return function(...args) {
const maintenant = Date.now();
const delaiRestant = intervalle - (maintenant - dernierAppel);
clearTimeout(temporisateur);
if (delaiRestant <= 0) {
dernierAppel = maintenant;
fonction.apply(this, args);
} else {
temporisateur = setTimeout(() => {
dernierAppel = Date.now();
fonction.apply(this, args);
}, delaiRestant);
}
};
}
// Exemple d'utilisation avec scroll
// window.addEventListener('scroll', etrangleur(() => {
// console.log('Position:', window.scrollY);
// }, 200));
Copie superifcielle et profonde
// Copie superficielle
function copieSuperficielle(objet) {
if (typeof objet !== 'object' || objet === null) {
return objet;
}
return Array.isArray(objet)
? [...objet]
: { ...objet };
}
// Copie profonde avec gestion des références circulaires
function copieProfonde(objet, memoire = new WeakMap()) {
if (typeof objet !== 'object' || objet === null) {
return objet;
}
// Vérifier si déjà copié (référence circulaire)
if (memoire.has(objet)) {
return memoire.get(objet);
}
// Créer la copie vide
const copie = Array.isArray(objet) ? [] : {};
memoire.set(objet, copie);
// Copier chaque propriété
for (const cle of Object.keys(objet)) {
copie[cle] = copieProfonde(objet[cle], memoire);
}
return copie;
}
// Exemple d'objet avec référence circulaire
const original = { a: 1, b: { c: 2 } };
original.b.d = original; // Référence circulaire
const copie = copieProfonde(original);
console.log(copie.a); // 1
console.log(copie.b.d === copie); // true - référence préservée
Implémentation de promesses
const ETAT_EN_ATTENTE = 'en_attente';
const ETAT_RESOLU = 'resolu';
const ETAT_REJETE = 'rejete';
class PromessePersonnalisee {
constructor(executeur) {
this.etat = ETAT_EN_ATTENTE;
this.valeur = null;
this.observateurs = [];
try {
executeur(
this._resoudre.bind(this),
this._rejeter.bind(this)
);
} catch (erreur) {
this._rejeter(erreur);
}
}
_resoudre(valeur) {
setTimeout(() => {
if (this.etat === ETAT_EN_ATTENTE) {
this.etat = ETAT_RESOLU;
this.valeur = valeur;
this._notifierObservateurs();
}
});
}
_rejeter(raison) {
if (this.etat === ETAT_EN_ATTENTE) {
this.etat = ETAT_REJETE;
this.valeur = raison;
this._notifierObservateurs();
}
}
_notifierObservateurs() {
this.observateurs.forEach(({ quandResolu, quandRejete }) => {
const executer = this.etat === ETAT_RESOLU ? quandResolu : quandRejete;
if (typeof executer === 'function') {
executer(this.valeur);
}
});
}
alors(quandResolu, quandRejete) {
return new PromessePersonnalisee((resoudre, rejeter) => {
const observateur = {
quandResolu: valeur => {
try {
const resultat = quandResolu(valeur);
resoudre(resultat);
} catch (erreur) {
rejeter(erreur);
}
},
quandRejete: raison => {
try {
const resultat = quandRejete(raison);
resoudre(resultat);
} catch (erreur) {
rejeter(erreur);
}
}
};
if (this.etat === ETAT_EN_ATTENTE) {
this.observateurs.push(observateur);
} else {
setTimeout(() => executer(this.valeur));
}
});
}
static tous(promesses) {
return new PromessePersonnalisee((resoudre, rejeter) => {
const resultats = [];
let compteur = 0;
promesses.forEach((promesse, index) => {
promesse.alors(
valeur => {
resultats[index] = valeur;
compteur++;
if (compteur === promesses.length) {
resoudre(resultats);
}
},
rejeter
);
});
});
}
}
Implémentation de JSON.stringify
function serialiserJSON(donnees) {
// Gestion des types primitifs
if (donnees === null || donnees === undefined) {
return String(donnees);
}
if (typeof donnees === 'number') {
return Number.isFinite(donnees) ? String(donnees) : 'null';
}
if (typeof donnees === 'boolean') {
return String(donnees);
}
if (typeof donnees === 'string') {
return `"${donnees}"`;
}
// Gestion des fonctions et symboles (ignorés)
if (typeof donnees === 'function' || typeof donnees === 'symbol') {
return undefined;
}
// Gestion des tableaux
if (Array.isArray(donnees)) {
const elements = donnees.map(element =>
serialiserJSON(element) || 'null'
);
return `[${elements.join(',')}]`;
}
// Gestion des objets
if (typeof donnees === 'object') {
const proprietes = Object.keys(donnees)
.filter(cle => typeof donnees[cle] !== 'function' && typeof donnees[cle] !== 'symbol')
.map(cle => {
const valeur = serialiserJSON(donnees[cle]);
if (valeur !== undefined) {
return `"${cle}":${valeur}`;
}
return null;
})
.filter(Boolean);
return `{${proprietes.join(',')}}`;
}
return String(donnees);
}
// Exemple d'utilisation
console.log(serialiserJSON({ a: 1, b: [2, 3], c: null }));
Implémentation de new
function creerNouvelleInstance(constructeur, ...args) {
// 1. Créer un nouvel objet avec le prototype du constructeur
const nouvelObjet = Object.create(constructeur.prototype);
// 2. Appliquer le constructeur à l'objet
const resultat = constructeur.apply(nouvelObjet, args);
// 3. Retourner l'objet si le constructeur ne retourne pas d'objet
return (typeof resultat === 'object' && resultat !== null)
? resultat
: nouvelObjet;
}
// Exemple d'utilisation
function Personne(nom, age) {
this.nom = nom;
this.age = age;
}
Personne.prototype.saluer = function() {
console.log(`Bonjour, je suis ${this.nom}`);
};
const personne = creerNouvelleInstance(Personne, 'Alice', 30);
personne.saluer(); // "Bonjour, je suis Alice"
Implémentation de call, apply et bind
Function.prototype.appelPersonnalise = function(contexte, ...args) {
contexte = contexte || globalThis;
const cleUnique = Symbol('fonctionTemporaire');
contexte[cleUnique] = this;
const resultat = contexte[cleUnique](...args);
delete contexte[cleUnique];
return resultat;
};
Function.prototype.applicationPersonnalisee = function(contexte, args) {
contexte = contexte || globalThis;
const cleUnique = Symbol('fonctionTemporaire');
contexte[cleUnique] = this;
const resultat = contexte[cleUnique](...args);
delete contexte[cleUnique];
return resultat;
};
Function.prototype.liaisonPersonnalisee = function(contexte, ...argsIniciaux) {
const fonctionOriginale = this;
return function(...argsNouveaux) {
return fonctionOriginale.apply(
contexte,
argsIniciaux.concat(argsNouveaux)
);
};
};
File d'attente asynchrone
class FileAttenteAsynchrone {
constructor(concurrence = 1) {
this.maximum = concurrence;
this.enCours = 0;
this.taches = [];
this.resultats = [];
}
ajouter(tacheAsynchrone) {
return new Promise((resolution, rejet) => {
this.taches.push({
executer: tacheAsynchrone,
resolution,
rejet
});
this._traiter();
});
}
async _traiter() {
while (this.taches.length > 0 && this.enCours < this.maximum) {
this.enCours++;
const tache = this.taches.shift();
try {
const resultat = await tache.executer();
tache.resolution(resultat);
this.resultats.push(resultat);
} catch (erreur) {
tache.rejet(erreur);
} finally {
this.enCours--;
this._traiter();
}
}
}
obtenirResultats() {
return this.resultats;
}
}
// Exemple d'utilisation
const file = new FileAttenteAsynchrone(2);
file.ajouter(() => new Promise(r => setTimeout(() => r('A'), 1000)));
file.ajouter(() => new Promise(r => setTimeout(() => r('B'), 500)));
file.ajouter(() => new Promise(r => setTimeout(() => r('C'), 800)));
Implémentation de lodash.get
function obtenirValeur(objet, chemin, valeurDefaut = undefined) {
if (typeof chemin === 'string') {
chemin = chemin.replace(/\[(\d+)\]/g, '.$1').split('.');
}
let courant = objet;
for (const segment of chemin) {
if (courant === null || courant === undefined) {
return valeurDefaut;
}
courant = courant[segment];
}
return courant !== undefined ? courant : valeurDefaut;
}
// Exemple d'utilisation
const donnees = {
utilisateur: {
adresses: [
{ ville: 'Paris', code: '75001' },
{ ville: 'Lyon', code: '69001' }
]
}
};
console.log(obtenirValeur(donnees, 'utilisateur.adresses[1].ville')); // "Lyon"
console.log(obtenirValeur(donnees, 'utilisateur.age', 25)); // 25