Horloge suisse en JS V1.0
This commit is contained in:
+334
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user