281 lines
8.1 KiB
JavaScript
281 lines
8.1 KiB
JavaScript
|
|
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());
|
||
|
|
}
|
||
|
|
}
|