102 lines
2.9 KiB
JavaScript
102 lines
2.9 KiB
JavaScript
/* Alliance Boréale — champ d'étoiles + constellation.
|
|
Vanilla JS, aucune dépendance. Désactivé si l'utilisateur préfère moins
|
|
d'animation. La métaphore : chaque artisan est une étoile ; reliés, ils
|
|
forment la constellation. */
|
|
|
|
(function () {
|
|
"use strict";
|
|
|
|
/* ---- Menu mobile ---- */
|
|
var nav = document.querySelector(".site-nav");
|
|
var toggle = document.querySelector(".nav-toggle");
|
|
if (nav && toggle) {
|
|
toggle.addEventListener("click", function () {
|
|
var open = nav.classList.toggle("open");
|
|
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
|
});
|
|
}
|
|
|
|
/* ---- Constellation ---- */
|
|
var canvas = document.getElementById("constellation");
|
|
if (!canvas) return;
|
|
|
|
var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
var ctx = canvas.getContext("2d");
|
|
var stars = [];
|
|
var w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
var LINK_DIST = 130;
|
|
|
|
function resize() {
|
|
w = canvas.clientWidth;
|
|
h = canvas.clientHeight;
|
|
canvas.width = w * dpr;
|
|
canvas.height = h * dpr;
|
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
seed();
|
|
}
|
|
|
|
function seed() {
|
|
var count = Math.round((w * h) / 14000);
|
|
count = Math.max(40, Math.min(160, count));
|
|
stars = [];
|
|
for (var i = 0; i < count; i++) {
|
|
stars.push({
|
|
x: Math.random() * w,
|
|
y: Math.random() * h,
|
|
r: Math.random() * 1.3 + 0.4,
|
|
vx: (Math.random() - 0.5) * 0.12,
|
|
vy: (Math.random() - 0.5) * 0.12,
|
|
tw: Math.random() * Math.PI * 2
|
|
});
|
|
}
|
|
}
|
|
|
|
function draw() {
|
|
ctx.clearRect(0, 0, w, h);
|
|
|
|
// liens de constellation
|
|
for (var i = 0; i < stars.length; i++) {
|
|
for (var j = i + 1; j < stars.length; j++) {
|
|
var dx = stars[i].x - stars[j].x;
|
|
var dy = stars[i].y - stars[j].y;
|
|
var d = Math.sqrt(dx * dx + dy * dy);
|
|
if (d < LINK_DIST) {
|
|
var a = (1 - d / LINK_DIST) * 0.22;
|
|
ctx.strokeStyle = "rgba(120, 200, 255," + a + ")";
|
|
ctx.lineWidth = 1;
|
|
ctx.beginPath();
|
|
ctx.moveTo(stars[i].x, stars[i].y);
|
|
ctx.lineTo(stars[j].x, stars[j].y);
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
|
|
// étoiles
|
|
for (var k = 0; k < stars.length; k++) {
|
|
var s = stars[k];
|
|
s.tw += 0.02;
|
|
var glow = 0.6 + Math.sin(s.tw) * 0.4;
|
|
ctx.beginPath();
|
|
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
|
|
ctx.fillStyle = "rgba(255,255,255," + glow + ")";
|
|
ctx.shadowColor = "rgba(160,220,255,0.9)";
|
|
ctx.shadowBlur = 6;
|
|
ctx.fill();
|
|
ctx.shadowBlur = 0;
|
|
|
|
if (!reduce) {
|
|
s.x += s.vx;
|
|
s.y += s.vy;
|
|
if (s.x < 0 || s.x > w) s.vx *= -1;
|
|
if (s.y < 0 || s.y > h) s.vy *= -1;
|
|
}
|
|
}
|
|
|
|
if (!reduce) requestAnimationFrame(draw);
|
|
}
|
|
|
|
window.addEventListener("resize", resize);
|
|
resize();
|
|
draw(); // un rendu statique si reduce, sinon animé
|
|
})();
|