319 lines
9.5 KiB
JavaScript
319 lines
9.5 KiB
JavaScript
// mode : terrain de vie, proximité, superposition....
|
|
// profondeur : atlas, carte
|
|
|
|
let modeAmount = 0,
|
|
curentMode = 1, prevMode,
|
|
currentProfondeur = "atlas",
|
|
colors = {
|
|
bg: {
|
|
h: 29,
|
|
s: 48,
|
|
l: 48
|
|
}
|
|
};
|
|
|
|
document.querySelectorAll('.mode').forEach(function(node, index) {
|
|
modeAmount++;
|
|
node.addEventListener('click', function() {
|
|
document.querySelectorAll('.active').forEach(function(el) {
|
|
el.classList.remove('active');
|
|
if (currentProfondeur == "carte") { el.classList.add('collapsed'); }
|
|
});
|
|
node.classList.toggle('active');
|
|
prevMode = curentMode;
|
|
curentMode = index + 1;
|
|
|
|
if (curentMode != prevMode) {
|
|
changeColors(curentMode - prevMode);
|
|
}
|
|
|
|
})
|
|
});
|
|
|
|
function toggleProfondeur(el) {
|
|
if (el.classList.contains("selected")) {
|
|
return;
|
|
} else {
|
|
for (let sibling of el.parentNode.children) {
|
|
sibling.classList.remove('selected');
|
|
}
|
|
}
|
|
el.classList.add("selected");
|
|
if(el.innerHTML == "L'atlas") {
|
|
currentProfondeur = "atlas";
|
|
document.querySelectorAll('.mode').forEach(function(node) {
|
|
if(node.classList.contains("collapsed")) {
|
|
node.classList.remove("collapsed");
|
|
}
|
|
});
|
|
} else {
|
|
currentProfondeur = "carte";
|
|
document.querySelectorAll('.mode').forEach(function(node) {
|
|
if(!node.classList.contains("active")) {
|
|
node.classList.add("collapsed");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function changeColors(diffAmount) {
|
|
let prevPaletteIndex = (prevMode + (prevMode - 1)); // cf commentaire palette à la fin
|
|
let baseColors = [];
|
|
baseColors.push(
|
|
colorPalette[prevPaletteIndex - 1],
|
|
colorPalette[prevPaletteIndex],
|
|
colorPalette[prevPaletteIndex + 1] ? colorPalette[prevPaletteIndex + 1] : colorPalette[0]
|
|
);
|
|
|
|
let paletteIndex = (curentMode + (curentMode - 1));
|
|
let targetColors = [];
|
|
|
|
targetColors.push(
|
|
colorPalette[paletteIndex - 1],
|
|
colorPalette[paletteIndex],
|
|
colorPalette[paletteIndex + 1 ] ? colorPalette[paletteIndex + 1] : colorPalette[0]
|
|
);
|
|
|
|
function hexToRgba(color) {
|
|
let colorRgba = {
|
|
r : parseInt(color.substr(0, 2), 16),
|
|
g : parseInt(color.substr(2, 2), 16),
|
|
b : parseInt(color.substr(4, 2), 16),
|
|
a : parseInt(color.substr(6, 2), 16)
|
|
}
|
|
return colorRgba;
|
|
}
|
|
|
|
function rgbaToHex(color) {
|
|
let colorHexa = {
|
|
r : color.r.toString(16).length != 2 ? 0 + color.r.toString(16) : color.r.toString(16),
|
|
g : color.g.toString(16).length != 2 ? 0 + color.g.toString(16) : color.g.toString(16),
|
|
b : color.b.toString(16).length != 2 ? 0 + color.b.toString(16) : color.b.toString(16),
|
|
a : color.a.toString(16).length != 2 ? 0 + color.a.toString(16) : color.a.toString(16)
|
|
}
|
|
return colorHexa.r + colorHexa.g + colorHexa.b + colorHexa.a;
|
|
}
|
|
|
|
let steps = 10, // vitesse de la transition
|
|
currentFrame = 0;
|
|
|
|
function animate() {
|
|
currentFrame++;
|
|
|
|
// à chaque frame on vide currentColors
|
|
// puis pusher trois couleurs hex de transition
|
|
// lorsque le nombre de steps est atteint envoyer les couleurs def
|
|
// et ne pas réanimer
|
|
|
|
currentColors = [];
|
|
for (i = 0; i < baseColors.length; i++) {
|
|
if (currentFrame == steps) {
|
|
currentColors.push(targetColors[i])
|
|
} else {
|
|
currentColors.push(getTransitionColor(baseColors[i], targetColors[i], currentFrame));
|
|
}
|
|
}
|
|
|
|
if (steps == 0) transitionLaunched++;
|
|
if (currentFrame != steps) {
|
|
window.requestAnimationFrame(() => animate());
|
|
} else {
|
|
currentFrame = 0;
|
|
}
|
|
}
|
|
animate()
|
|
|
|
function getTransitionColor(baseColor, targetColor, currentFrame) {
|
|
let rgbaBase = hexToRgba(baseColor),
|
|
rgbaTarget = hexToRgba(targetColor),
|
|
diff = {
|
|
r : (rgbaBase.r - rgbaTarget.r) * -1,
|
|
g : (rgbaBase.g - rgbaTarget.g) * -1,
|
|
b : (rgbaBase.b - rgbaTarget.b) * -1,
|
|
a : (rgbaBase.a - rgbaTarget.a) * -1
|
|
},
|
|
transitionColor = {
|
|
r : Math.floor(rgbaBase.r + (diff.r / steps) * currentFrame),
|
|
g : Math.floor(rgbaBase.g + (diff.g / steps) * currentFrame),
|
|
b : Math.floor(rgbaBase.b + (diff.b / steps) * currentFrame),
|
|
a : Math.floor(rgbaBase.a + (diff.a / steps) * currentFrame)
|
|
};
|
|
transitionColor = rgbaToHex(transitionColor);
|
|
|
|
return transitionColor;
|
|
}
|
|
}
|
|
|
|
|
|
// COULEURS DE FOND
|
|
// basé sur https://codepen.io/ThreePixDroid/pen/MWeomWp
|
|
|
|
// ajouter un grain fixe : cf
|
|
// https://codepen.io/zadvorsky/pen/PwyoMm
|
|
|
|
let colorPalette = [
|
|
"ff6a0399",
|
|
"c9c4ffff",
|
|
"0796908c",
|
|
"e6ffc4ff",
|
|
"e105054d",
|
|
"aaffa2ff",
|
|
"18b8e64d",
|
|
"ffc4f9ff",
|
|
"9692074d",
|
|
"ffe7c4ff",
|
|
"0629ad4d",
|
|
"fffdbaff"
|
|
]
|
|
|
|
let currentColors = [];
|
|
currentColors.push(
|
|
colorPalette[0],
|
|
colorPalette[1],
|
|
colorPalette[2],
|
|
);
|
|
|
|
|
|
class GradientAnimation {
|
|
constructor() {
|
|
this.cnv = document.querySelector('canvas');
|
|
this.ctx = this.cnv.getContext('2d');
|
|
|
|
// réglages du fond
|
|
this.radius = 1800;
|
|
this.speed = 0.01;
|
|
|
|
// variables du grain
|
|
this.patternSize = 512;
|
|
this.patternAlpha = 10; // int between 0 and 255,
|
|
|
|
this.patternPixelDataLength = this.patternSize * this.patternSize * 4;
|
|
this.patternCanvas;
|
|
this.patternCtx;
|
|
this.patternData;
|
|
this.frame = 0;
|
|
|
|
(window.onresize = () => {
|
|
this.setCanvasSize();
|
|
this.createCircles();
|
|
})();
|
|
this.initGrain();
|
|
this.drawAnimation();
|
|
}
|
|
setCanvasSize() {
|
|
this.w = this.cnv.width = innerWidth * devicePixelRatio;
|
|
this.h = this.cnv.height = innerHeight * devicePixelRatio;
|
|
this.ctx.scale(devicePixelRatio, devicePixelRatio);
|
|
}
|
|
createCircles() {
|
|
this.circles = [];
|
|
// positionnement des cercles directement ici
|
|
this.circles.push(new Circle(this.w, this.h, this.radius, 30, 30, 0));
|
|
this.circles.push(new Circle(this.w, this.h, this.radius, window.innerWidth / 2, window.innerHeight, 1));
|
|
this.circles.push(new Circle(this.w, this.h, this.radius, window.innerWidth - 30, 30, 2));
|
|
}
|
|
drawCircles() {
|
|
this.circles.forEach(circle => circle.draw(this.ctx, this.speed));
|
|
}
|
|
drawBackground() {
|
|
this.ctx.fillStyle = "#aaaaaa";
|
|
this.ctx.fillRect(0, 0, this.w, this.h);
|
|
}
|
|
initGrain() {
|
|
let patternSize = 128; // ça marche pas this.patternSize
|
|
|
|
this.patternCanvas = document.createElement('canvas');
|
|
this.patternCanvas.width = patternSize;
|
|
this.patternCanvas.height = patternSize;
|
|
this.patternCtx = this.patternCanvas.getContext('2d');
|
|
this.patternData = this.patternCtx.createImageData(patternSize, patternSize);
|
|
|
|
let value;
|
|
|
|
for (let i = 0; i < this.patternPixelDataLength; i += 4) {
|
|
value = (Math.random() * 255) | 0;
|
|
|
|
this.patternData.data[i ] = value;
|
|
this.patternData.data[i + 1] = value;
|
|
this.patternData.data[i + 2] = value;
|
|
this.patternData.data[i + 3] = this.patternAlpha;
|
|
}
|
|
|
|
this.patternCtx.putImageData(this.patternData, 0, 0);
|
|
}
|
|
drawAnimation() {
|
|
this.drawBackground();
|
|
this.drawCircles();
|
|
|
|
this.ctx.fillStyle = this.ctx.createPattern(this.patternCanvas, 'repeat');
|
|
this.ctx.fillRect(0, 0, window.innerWidth, window.innerHeight);
|
|
|
|
window.requestAnimationFrame(() => this.drawAnimation());
|
|
}
|
|
}
|
|
|
|
class Circle {
|
|
constructor(w, h, radius, posX, posY, index) {
|
|
this.x = posX;
|
|
this.y = posY;
|
|
this.angle = Math.random() * Math.PI * 2;
|
|
this.radius = radius;
|
|
this.index = index;
|
|
this.firstColor = "#" + currentColors[index];
|
|
this.secondColor = "#ffffff00";
|
|
}
|
|
draw(ctx, speed) {
|
|
this.angle += speed;
|
|
const x = this.x + Math.cos(this.angle) * 200;
|
|
const y = this.y + Math.sin(this.angle) * 200;
|
|
const gradient = ctx.createRadialGradient(x, y, 0, x, y, this.radius);
|
|
gradient.addColorStop(0, "#" + currentColors[this.index]);
|
|
gradient.addColorStop(1, this.secondColor);
|
|
|
|
ctx.fillStyle = gradient;
|
|
ctx.beginPath();
|
|
ctx.arc(x, y, this.radius, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
}
|
|
}
|
|
|
|
window.onload = () => {
|
|
new GradientAnimation();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* palette :
|
|
multiply vers blanc
|
|
|
|
0 #ff6a03 45%
|
|
1 TERRAIN DE VIE
|
|
1 #c9c4ff 100%
|
|
|
|
2 #079690 30%
|
|
2 PROXIMITE
|
|
3 #e6ffc4 100%
|
|
|
|
4 #e10505 30%
|
|
3 SUPPERPOSITION
|
|
5 #aaffa2 100%
|
|
|
|
6 #18b8e6 30%
|
|
4 PUISSANCE
|
|
7 #ffc4f9 100%
|
|
|
|
8 #969207 30%
|
|
5 ACTION
|
|
9 #ffe7c4 100%
|
|
|
|
10 #0629ad 30%
|
|
6 DOLEANCER
|
|
11 #fffdba 100% */
|
|
|
|
|
|
// 1 1, 2 3, 3 5, 4 7, 5 9, 6 11
|
|
// curentMode + (curentMode - 1)
|