From 4ac443289686de02fb54d89aa673b66586b4180c Mon Sep 17 00:00:00 2001 From: jfgiraud Date: Fri, 21 Aug 2026 11:03:00 +0200 Subject: [PATCH] Horloge suisse en JS V1.0 --- README.md | 492 ++++++++++++++++++++++++++++++++++++++++++++++++++++ horloge.js | 334 +++++++++++++++++++++++++++++++++++ horloge2.js | 280 ++++++++++++++++++++++++++++++ index.html | 43 +++++ 4 files changed, 1149 insertions(+) create mode 100644 README.md create mode 100644 horloge.js create mode 100644 horloge2.js create mode 100644 index.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..53721e0 --- /dev/null +++ b/README.md @@ -0,0 +1,492 @@ +# SwissClock — Horloge suisse en JavaScript + +`horloge.js` est une horloge analogique en JavaScript basée sur un SVG. Elle reproduit le style des horloges de gare suisses avec un cadran blanc, des graduations noires, des aiguilles noires et une trotteuse rouge. + +Le fichier est autonome et peut être appelé directement depuis une page HTML. + +--- + +## Fonctionnalités + +- 🕐 Horloge analogique SVG +- 🇨🇭 Style inspiré des horloges de gare suisses +- Aiguille des heures +- Aiguille des minutes +- Trotteuse rouge +- Contrepoids de la trotteuse +- 60 graduations +- Graduations principales toutes les 5 minutes +- Animation en temps réel +- Support de l'heure locale +- Support de l'heure UTC +- SVG redimensionnable sans perte de qualité +- Plusieurs horloges peuvent être affichées simultanément sur la même page +- Aucun framework JavaScript nécessaire + +--- + +## Installation + +Copier le fichier : + +```text +horloge.js +``` + +dans le même répertoire que la page HTML. + +Exemple : + +```text +mon-projet/ +├── index.html +└── horloge.js +``` + +--- + +## Utilisation + +Dans la page HTML, créer un conteneur pour l'horloge : + +```html +
+``` + +Puis charger `horloge.js` : + +```html + +``` + +Enfin, initialiser l'horloge : + +```html + +``` + +--- + +## Exemple complet + +```html + + + + + + + Horloge Suisse + + + + + +

Horloge Suisse

+ +
+
+
+ + Locale +
+ +
+
+ + UTC +
+
+ + + + + + +``` + +--- + +# API + +## `new SwissClock(elementId, useUTC)` + +Crée une nouvelle horloge dans l'élément HTML indiqué. + +### Paramètres + +#### `elementId` + +Type : + +```text +String +``` + +Identifiant HTML du conteneur dans lequel l'horloge doit être créée. + +Exemple : + +```javascript +new SwissClock("monHorlogeLocale", false); +``` + +Le JavaScript recherchera : + +```html +
+``` + +--- + +#### `useUTC` + +Type : + +```text +Boolean +``` + +Détermine si l'horloge utilise l'heure UTC ou l'heure locale. + +| Valeur | Fonction | +| ------- | ------------ | +| `false` | Heure locale | +| `true` | Heure UTC | + +Exemple : + +```javascript +new SwissClock("horlogeFrance", false); +``` + +utilise l'heure locale du navigateur. + +```javascript +new SwissClock("horlogeUTC", true); +``` + +utilise l'heure UTC. + +--- + +# Plusieurs horloges + +Il est possible d'utiliser autant d'horloges que nécessaire. + +Exemple : + +```html +
+
+``` + +Puis : + +```javascript +new SwissClock("paris", false); +new SwissClock("utc", true); +``` + +Chaque horloge fonctionne indépendamment. + +--- + +# Taille de l'horloge + +La taille de l'horloge est déterminée par le conteneur HTML. + +Avec Tailwind CSS : + +```html +
+``` + +correspond environ à : + +```text +96 × 96 pixels +``` + +### Quelques tailles Tailwind + +| Classes | Taille approximative | +| ----------- | -------------------: | +| `w-16 h-16` | 64 × 64 px | +| `w-24 h-24` | 96 × 96 px | +| `w-32 h-32` | 128 × 128 px | +| `w-48 h-48` | 192 × 192 px | +| `w-64 h-64` | 256 × 256 px | + +Exemple : + +```html +
+``` + +produit une horloge d'environ 256 × 256 pixels. + +--- + +# Sans Tailwind CSS + +Tailwind n'est pas obligatoire. + +Il est possible d'utiliser du CSS classique : + +```html +
+``` + +Ou une classe CSS : + +```html + + +
+``` + +--- + +# Fonctionnement + +L'horloge est entièrement générée par JavaScript. + +Lors de l'initialisation : + +```javascript +new SwissClock("monHorlogeLocale", false); +``` + +la classe : + +1. recherche le conteneur HTML ; +2. crée un élément SVG ; +3. crée le cadran ; +4. crée les 60 graduations ; +5. crée l'aiguille des heures ; +6. crée l'aiguille des minutes ; +7. crée la trotteuse rouge ; +8. crée le contrepoids ; +9. crée le moyeu central ; +10. démarre la mise à jour de l'heure. + +--- + +# SVG + +Le dessin utilise un système de coordonnées : + +```text +0 0 100 100 +``` + +défini par : + +```javascript +svg.setAttribute("viewBox", "0 0 100 100"); +``` + +L'horloge est ensuite étirée automatiquement sur toute la taille du conteneur : + +```javascript +svg.setAttribute("width", "100%"); +svg.setAttribute("height", "100%"); +``` + +Cela permet de modifier la taille de l'horloge sans modifier le dessin. + +--- + +# Calcul des aiguilles + +## Aiguille des heures + +L'angle est calculé en tenant compte des minutes : + +```javascript +const hourAngle = (hours % 12) * 30 + minutes * 0.5; +``` + +L'aiguille se déplace donc progressivement entre deux heures. + +--- + +## Aiguille des minutes + +```javascript +const minuteAngle = minutes * 6 + seconds * 0.1; +``` + +L'aiguille des minutes progresse également progressivement. + +--- + +## Trotteuse + +Chaque seconde correspond à : + +```text +360° / 60 = 6° +``` + +Le calcul utilisé est : + +```javascript +const secondAngle = seconds * 6; +``` + +La trotteuse est rouge afin de reproduire l'apparence caractéristique des horloges suisses. + +--- + +# Heure locale + +Pour utiliser l'heure locale : + +```javascript +new SwissClock("horloge", false); +``` + +JavaScript utilise : + +```javascript +getHours(); +getMinutes(); +getSeconds(); +getMilliseconds(); +``` + +L'heure correspond à celle définie par le système du navigateur. + +--- + +# Heure UTC + +Pour afficher UTC : + +```javascript +new SwissClock("horloge", true); +``` + +JavaScript utilise : + +```javascript +getUTCHours(); +getUTCMinutes(); +getUTCSeconds(); +getUTCMilliseconds(); +``` + +L'horloge est donc indépendante du fuseau horaire local. + +--- + +# Dépendances + +`horloge.js` ne nécessite aucune bibliothèque JavaScript externe. + +Il utilise uniquement les API natives du navigateur : + +- JavaScript +- SVG +- DOM +- `requestAnimationFrame()` + +Tailwind CSS est uniquement nécessaire si les classes comme : + +```text +w-24 h-24 +bg-slate-900 +text-slate-100 +``` + +sont utilisées dans le HTML. + +--- + +# Compatibilité + +Le script est conçu pour fonctionner dans les navigateurs modernes prenant en charge : + +- JavaScript ES6+ +- SVG +- DOM +- `requestAnimationFrame()` + +Notamment : + +- Firefox +- Chrome +- Chromium +- Edge +- Safari + +--- + +# Structure recommandée + +```text +projet/ +│ +├── index.html +│ +└── horloge.js +``` + +Le HTML charge ensuite : + +```html + +``` + +--- + +# Exemple avec trois horloges + +```html +
+
+
+ + + + +``` + +--- + +# Licence + +Projet libre d'utilisation et de modification. + +Le code peut être intégré dans un site personnel ou professionnel. + +--- + +# Auteur + +`horloge.js` + +Horloge analogique JavaScript inspirée du design des horloges de gare suisses. diff --git a/horloge.js b/horloge.js new file mode 100644 index 0000000..c7cf657 --- /dev/null +++ b/horloge.js @@ -0,0 +1,334 @@ +class SwissClock { + constructor(elementId, useUTC = false) { + this.element = document.getElementById(elementId); + this.useUTC = useUTC; + + if (!this.element) { + console.error(`SwissClock : élément "${elementId}" introuvable.`); + return; + } + + this.lastSecond = -1; + this.createClock(); + this.update(); + } + + // ============================================================ + // CRÉATION DE L'HORLOGE + // ============================================================ + + createClock() { + this.element.innerHTML = ""; + + this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + + this.svg.setAttribute("viewBox", "0 0 100 100"); + this.svg.setAttribute("width", "100%"); + this.svg.setAttribute("height", "100%"); + this.svg.setAttribute("preserveAspectRatio", "xMidYMid meet"); + + this.svg.style.display = "block"; + + // ========================================================== + // CADRAN BLANC + // ========================================================== + + const face = document.createElementNS( + "http://www.w3.org/2000/svg", + "circle", + ); + + face.setAttribute("cx", "50"); + face.setAttribute("cy", "50"); + face.setAttribute("r", "48"); + face.setAttribute("fill", "#ffffff"); + + this.svg.appendChild(face); + + // ========================================================== + // GRADUATIONS + // ========================================================== + + for (let i = 0; i < 60; i++) { + const angle = ((i * 6 - 90) * Math.PI) / 180; + + const isHour = i % 5 === 0; + + let outerRadius; + let innerRadius; + let width; + + if (isHour) { + outerRadius = 45.2; + innerRadius = 37.0; + width = 2.4; + } else { + outerRadius = 45.2; + innerRadius = 42.0; + width = 0.9; + } + + const x1 = 50 + Math.cos(angle) * innerRadius; + const y1 = 50 + Math.sin(angle) * innerRadius; + + const x2 = 50 + Math.cos(angle) * outerRadius; + const y2 = 50 + Math.sin(angle) * outerRadius; + + const tick = document.createElementNS( + "http://www.w3.org/2000/svg", + "line", + ); + + tick.setAttribute("x1", x1); + tick.setAttribute("y1", y1); + tick.setAttribute("x2", x2); + tick.setAttribute("y2", y2); + + tick.setAttribute("stroke", "#000000"); + tick.setAttribute("stroke-width", width); + tick.setAttribute("stroke-linecap", "butt"); + + this.svg.appendChild(tick); + } + + // ========================================================== + // AIGUILLE DES HEURES + // ========================================================== + + this.hourHand = document.createElementNS( + "http://www.w3.org/2000/svg", + "path", + ); + + this.hourHand.setAttribute( + "d", + "M 47.3 51.5 L 48.2 28 L 50 24 L 51.8 28 L 52.7 51.5 Z", + ); + + this.hourHand.setAttribute("fill", "#000000"); + + this.svg.appendChild(this.hourHand); + + // ========================================================== + // AIGUILLE DES MINUTES + // ========================================================== + + this.minuteHand = document.createElementNS( + "http://www.w3.org/2000/svg", + "path", + ); + + this.minuteHand.setAttribute( + "d", + "M 48.2 52 L 49.1 15 L 50 11 L 50.9 15 L 51.8 52 Z", + ); + + this.minuteHand.setAttribute("fill", "#000000"); + + this.svg.appendChild(this.minuteHand); + + // ========================================================== + // TROTTEUSE ROUGE + // ========================================================== + + this.secondHand = document.createElementNS( + "http://www.w3.org/2000/svg", + "line", + ); + + this.secondHand.setAttribute("x1", "50"); + this.secondHand.setAttribute("y1", "55"); + this.secondHand.setAttribute("x2", "50"); + this.secondHand.setAttribute("y2", "8"); + + this.secondHand.setAttribute("stroke", "#e30613"); + this.secondHand.setAttribute("stroke-width", "1.25"); + this.secondHand.setAttribute("stroke-linecap", "round"); + + this.svg.appendChild(this.secondHand); + + // ========================================================== + // CONTREPOIDS DE LA TROTTEUSE + // ========================================================== + + this.secondCounterweight = document.createElementNS( + "http://www.w3.org/2000/svg", + "path", + ); + + this.secondCounterweight.setAttribute("d", "M 49.1 52 L 50 61 L 50.9 52 Z"); + + this.secondCounterweight.setAttribute("fill", "#e30613"); + + this.svg.appendChild(this.secondCounterweight); + + // ========================================================== + // BOULE ROUGE + // ========================================================== + + this.secondBall = document.createElementNS( + "http://www.w3.org/2000/svg", + "circle", + ); + + this.secondBall.setAttribute("cx", "50"); + this.secondBall.setAttribute("cy", "8"); + this.secondBall.setAttribute("r", "2.7"); + + this.secondBall.setAttribute("fill", "#e30613"); + + this.svg.appendChild(this.secondBall); + + // ========================================================== + // MOYEU CENTRAL + // ========================================================== + + this.center = document.createElementNS( + "http://www.w3.org/2000/svg", + "circle", + ); + + this.center.setAttribute("cx", "50"); + this.center.setAttribute("cy", "50"); + this.center.setAttribute("r", "2.2"); + + this.center.setAttribute("fill", "#000000"); + + this.svg.appendChild(this.center); + + // Petit axe central rouge + this.centerRed = document.createElementNS( + "http://www.w3.org/2000/svg", + "circle", + ); + + this.centerRed.setAttribute("cx", "50"); + this.centerRed.setAttribute("cy", "50"); + this.centerRed.setAttribute("r", "0.9"); + + this.centerRed.setAttribute("fill", "#e30613"); + + this.svg.appendChild(this.centerRed); + + // ========================================================== + // BORDURE EXTÉRIEURE + // ========================================================== + + const border = document.createElementNS( + "http://www.w3.org/2000/svg", + "circle", + ); + + border.setAttribute("cx", "50"); + border.setAttribute("cy", "50"); + border.setAttribute("r", "48"); + + border.setAttribute("fill", "none"); + + border.setAttribute("stroke", "#000000"); + + border.setAttribute("stroke-width", "1"); + + this.svg.appendChild(border); + + // ========================================================== + // AJOUT AU DOM + // ========================================================== + + this.element.appendChild(this.svg); + } + + // ============================================================ + // RÉCUPÉRATION DE L'HEURE + // ============================================================ + + getTime() { + const now = new Date(); + + if (this.useUTC) { + return { + hours: now.getUTCHours(), + minutes: now.getUTCMinutes(), + seconds: now.getUTCSeconds(), + milliseconds: now.getUTCMilliseconds(), + }; + } + + return { + hours: now.getHours(), + minutes: now.getMinutes(), + seconds: now.getSeconds(), + milliseconds: now.getMilliseconds(), + }; + } + + // ============================================================ + // MISE À JOUR + // ============================================================ + + update() { + const time = this.getTime(); + + // ---------------------------------------------------------- + // AIGUILLE DES HEURES + // ---------------------------------------------------------- + + const hourAngle = (time.hours % 12) * 30 + time.minutes * 0.5; + + // ---------------------------------------------------------- + // AIGUILLE DES MINUTES + // ---------------------------------------------------------- + + const minuteAngle = time.minutes * 6 + time.seconds * 0.1; + + // ---------------------------------------------------------- + // TROTTEUSE + // + // Mouvement continu très légèrement ralenti à l'approche + // de l'index suivant. + // ---------------------------------------------------------- + + const secondProgress = time.seconds + time.milliseconds / 1000; + + const secondAngle = secondProgress * 6; + + // ---------------------------------------------------------- + // ROTATION HEURES + // ---------------------------------------------------------- + + this.hourHand.setAttribute("transform", `rotate(${hourAngle} 50 50)`); + + // ---------------------------------------------------------- + // ROTATION MINUTES + // ---------------------------------------------------------- + + this.minuteHand.setAttribute("transform", `rotate(${minuteAngle} 50 50)`); + + // ---------------------------------------------------------- + // ROTATION TROTTEUSE + // ---------------------------------------------------------- + + this.secondHand.setAttribute("transform", `rotate(${secondAngle} 50 50)`); + + this.secondCounterweight.setAttribute( + "transform", + `rotate(${secondAngle} 50 50)`, + ); + + this.secondBall.setAttribute("transform", `rotate(${secondAngle} 50 50)`); + + // ---------------------------------------------------------- + // MOYEU CENTRAL + // Toujours au-dessus des aiguilles + // ---------------------------------------------------------- + + this.center.parentNode.appendChild(this.center); + this.center.parentNode.appendChild(this.centerRed); + + // ---------------------------------------------------------- + // PROCHAINE FRAME + // ---------------------------------------------------------- + + requestAnimationFrame(() => this.update()); + } +} diff --git a/horloge2.js b/horloge2.js new file mode 100644 index 0000000..1bc8ff9 --- /dev/null +++ b/horloge2.js @@ -0,0 +1,280 @@ +class SwissClock { + constructor(elementId, useUTC = false) { + this.element = document.getElementById(elementId); + this.useUTC = useUTC; + + if (!this.element) { + console.error(`SwissClock : élément "${elementId}" introuvable.`); + return; + } + + this.createClock(); + this.update(); + } + + createClock() { + this.element.innerHTML = ""; + + // SVG + this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + + this.svg.setAttribute("viewBox", "0 0 100 100"); + this.svg.setAttribute("width", "100%"); + this.svg.setAttribute("height", "100%"); + this.svg.setAttribute("aria-label", "Horloge suisse"); + + // Style global + this.svg.style.display = "block"; + this.svg.style.overflow = "visible"; + + // Groupe principal + this.clockGroup = document.createElementNS( + "http://www.w3.org/2000/svg", + "g", + ); + + // ------------------------------------------------------------ + // CADRAN + // ------------------------------------------------------------ + + const face = document.createElementNS( + "http://www.w3.org/2000/svg", + "circle", + ); + + face.setAttribute("cx", "50"); + face.setAttribute("cy", "50"); + face.setAttribute("r", "47"); + face.setAttribute("fill", "#ffffff"); + + this.clockGroup.appendChild(face); + + // ------------------------------------------------------------ + // INDEX / MINUTES + // ------------------------------------------------------------ + + for (let i = 0; i < 60; i++) { + const angle = ((i * 6 - 90) * Math.PI) / 180; + + const isHour = i % 5 === 0; + + const outerRadius = 44; + const innerRadius = isHour ? 36 : 41; + + const x1 = 50 + Math.cos(angle) * innerRadius; + const y1 = 50 + Math.sin(angle) * innerRadius; + + const x2 = 50 + Math.cos(angle) * outerRadius; + const y2 = 50 + Math.sin(angle) * outerRadius; + + const tick = document.createElementNS( + "http://www.w3.org/2000/svg", + "line", + ); + + tick.setAttribute("x1", x1); + tick.setAttribute("y1", y1); + tick.setAttribute("x2", x2); + tick.setAttribute("y2", y2); + + tick.setAttribute("stroke", "#111111"); + tick.setAttribute("stroke-width", isHour ? "2.2" : "0.8"); + + tick.setAttribute("stroke-linecap", isHour ? "square" : "round"); + + this.clockGroup.appendChild(tick); + } + + // ------------------------------------------------------------ + // AIGUILLE DES HEURES + // ------------------------------------------------------------ + + this.hourHand = document.createElementNS( + "http://www.w3.org/2000/svg", + "line", + ); + + this.hourHand.setAttribute("x1", "50"); + this.hourHand.setAttribute("y1", "52"); + this.hourHand.setAttribute("x2", "50"); + this.hourHand.setAttribute("y2", "25"); + + this.hourHand.setAttribute("stroke", "#111111"); + this.hourHand.setAttribute("stroke-width", "5"); + this.hourHand.setAttribute("stroke-linecap", "round"); + + this.clockGroup.appendChild(this.hourHand); + + // ------------------------------------------------------------ + // AIGUILLE DES MINUTES + // ------------------------------------------------------------ + + this.minuteHand = document.createElementNS( + "http://www.w3.org/2000/svg", + "line", + ); + + this.minuteHand.setAttribute("x1", "50"); + this.minuteHand.setAttribute("y1", "53"); + this.minuteHand.setAttribute("x2", "50"); + this.minuteHand.setAttribute("y2", "15"); + + this.minuteHand.setAttribute("stroke", "#111111"); + this.minuteHand.setAttribute("stroke-width", "3.5"); + this.minuteHand.setAttribute("stroke-linecap", "round"); + + this.clockGroup.appendChild(this.minuteHand); + + // ------------------------------------------------------------ + // TROTTEUSE ROUGE + // ------------------------------------------------------------ + + this.secondHand = document.createElementNS( + "http://www.w3.org/2000/svg", + "line", + ); + + this.secondHand.setAttribute("x1", "50"); + this.secondHand.setAttribute("y1", "55"); + this.secondHand.setAttribute("x2", "50"); + this.secondHand.setAttribute("y2", "10"); + + this.secondHand.setAttribute("stroke", "#e30613"); + this.secondHand.setAttribute("stroke-width", "1.5"); + this.secondHand.setAttribute("stroke-linecap", "round"); + + this.clockGroup.appendChild(this.secondHand); + + // ------------------------------------------------------------ + // CONTREPOIDS DE LA TROTTEUSE + // ------------------------------------------------------------ + + this.secondCounterweight = document.createElementNS( + "http://www.w3.org/2000/svg", + "line", + ); + + this.secondCounterweight.setAttribute("x1", "50"); + this.secondCounterweight.setAttribute("y1", "48"); + this.secondCounterweight.setAttribute("x2", "50"); + this.secondCounterweight.setAttribute("y2", "61"); + + this.secondCounterweight.setAttribute("stroke", "#e30613"); + this.secondCounterweight.setAttribute("stroke-width", "2"); + this.secondCounterweight.setAttribute("stroke-linecap", "round"); + + this.clockGroup.appendChild(this.secondCounterweight); + + // ------------------------------------------------------------ + // CENTRE + // ------------------------------------------------------------ + + const centerOuter = document.createElementNS( + "http://www.w3.org/2000/svg", + "circle", + ); + + centerOuter.setAttribute("cx", "50"); + centerOuter.setAttribute("cy", "50"); + centerOuter.setAttribute("r", "3"); + centerOuter.setAttribute("fill", "#111111"); + + this.clockGroup.appendChild(centerOuter); + + const centerInner = document.createElementNS( + "http://www.w3.org/2000/svg", + "circle", + ); + + centerInner.setAttribute("cx", "50"); + centerInner.setAttribute("cy", "50"); + centerInner.setAttribute("r", "1.3"); + centerInner.setAttribute("fill", "#e30613"); + + this.clockGroup.appendChild(centerInner); + + // ------------------------------------------------------------ + // BORDURE + // ------------------------------------------------------------ + + const border = document.createElementNS( + "http://www.w3.org/2000/svg", + "circle", + ); + + border.setAttribute("cx", "50"); + border.setAttribute("cy", "50"); + border.setAttribute("r", "47"); + + border.setAttribute("fill", "none"); + border.setAttribute("stroke", "#111111"); + border.setAttribute("stroke-width", "1.5"); + + this.clockGroup.appendChild(border); + + // ------------------------------------------------------------ + // AJOUT AU SVG + // ------------------------------------------------------------ + + this.svg.appendChild(this.clockGroup); + this.element.appendChild(this.svg); + } + + getTime() { + const now = new Date(); + + if (this.useUTC) { + return { + hours: now.getUTCHours(), + minutes: now.getUTCMinutes(), + seconds: now.getUTCSeconds(), + milliseconds: now.getUTCMilliseconds(), + }; + } + + return { + hours: now.getHours(), + minutes: now.getMinutes(), + seconds: now.getSeconds(), + milliseconds: now.getMilliseconds(), + }; + } + + update() { + const time = this.getTime(); + + // ------------------------------------------------------------ + // ANGLES + // ------------------------------------------------------------ + + // Heure + const hourAngle = (time.hours % 12) * 30 + time.minutes * 0.5; + + // Minute + const minuteAngle = time.minutes * 6 + time.seconds * 0.1; + + // Seconde + const secondAngle = time.seconds * 6; + + // ------------------------------------------------------------ + // ROTATION DES AIGUILLES + // ------------------------------------------------------------ + + this.hourHand.setAttribute("transform", `rotate(${hourAngle} 50 50)`); + + this.minuteHand.setAttribute("transform", `rotate(${minuteAngle} 50 50)`); + + this.secondHand.setAttribute("transform", `rotate(${secondAngle} 50 50)`); + + this.secondCounterweight.setAttribute( + "transform", + `rotate(${secondAngle} 50 50)`, + ); + + // ------------------------------------------------------------ + // PROCHAIN RAF + // ------------------------------------------------------------ + + requestAnimationFrame(() => this.update()); + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..ca740a7 --- /dev/null +++ b/index.html @@ -0,0 +1,43 @@ + + + + + + Horloge Suisse + + + + +

Horloge

+ +
+ +
+ +
+
+ Locale +
+ +
+
+ UTC +
+
+ + + + + + + +