172 lines
7.8 KiB
JavaScript
172 lines
7.8 KiB
JavaScript
const nodosData = [
|
|
// Reemplaza el src con la ruta real de tus logos
|
|
{ id: 'tl', x0: 220, y0: 140, r: 52, color: '#16a085', html: '<img src="assets/logos/excellence_b.png" alt="EXCELLENCE">' },
|
|
{ id: 'bl', x0: 200, y0: 420, r: 52, color: '#f39200', html: '<img src="assets/logos/projects_b.png" alt="PROJECTS">' },
|
|
{ id: 'tr', x0: 780, y0: 110, r: 52, color: '#c41230', html: '<img src="assets/logos/academy_b.png" alt="ACADEMY">' },
|
|
{ id: 'br', x0: 750, y0: 400, r: 52, color: '#0061a0', html: '<img src="assets/logos/digital_b.png" alt="DIGITAL">' },
|
|
{ id: 'c', x0: 500, y0: 280, r: 70, color: '#ffffff', html: '<img src="assets/logos/ide.png" alt="EL TODO">' }
|
|
];
|
|
|
|
const conexiones = [
|
|
{ id: 'arcL', from: 'tl', to: 'bl', type: 'vertical', curveOut: -180 },
|
|
{ id: 'c1', from: 'tl', to: 'c', type: 'horizontal', curveOut: 0 },
|
|
{ id: 'c2', from: 'bl', to: 'c', type: 'horizontal', curveOut: 0 },
|
|
{ id: 'arcR', from: 'tr', to: 'br', type: 'vertical', curveOut: 180 },
|
|
{ id: 'c3', from: 'tr', to: 'c', type: 'horizontal', curveOut: 0 },
|
|
{ id: 'c4', from: 'br', to: 'c', type: 'horizontal', curveOut: 0 }
|
|
];
|
|
|
|
const contenedorNodos = document.getElementById('grupo-nodos');
|
|
const grupoLineas = document.getElementById('grupo-lineas');
|
|
const svgDefs = document.getElementById('svg-defs');
|
|
const nodosMap = {};
|
|
|
|
// 1. Renderizado de Nodos HTML (AHORA FIJOS)
|
|
nodosData.forEach(nodo => {
|
|
nodosMap[nodo.id] = nodo;
|
|
|
|
const el = document.createElement('div');
|
|
el.className = 'nodo-circulo';
|
|
el.id = `node-${nodo.id}`;
|
|
el.style.backgroundColor = nodo.color; // Lo comento para que el fondo sea blanco y se vea bien tu logo, descomenta si prefieres el fondo de color
|
|
//el.style.border = `4px solid ${nodo.color}`; // Agrego un borde con el color corporativo
|
|
el.style.width = `${(nodo.r * 2 / 1000) * 100}%`;
|
|
el.style.height = `${(nodo.r * 2 / 500) * 100}%`;
|
|
|
|
// Asignamos la posición una única vez
|
|
nodo.x = nodo.x0;
|
|
nodo.y = nodo.y0;
|
|
el.style.left = `${(nodo.x / 1000) * 100}%`;
|
|
el.style.top = `${(nodo.y / 500) * 100}%`;
|
|
|
|
const content = document.createElement('div');
|
|
content.className = 'nodo-contenido';
|
|
content.innerHTML = nodo.html;
|
|
|
|
el.appendChild(content);
|
|
contenedorNodos.appendChild(el);
|
|
nodo.el = el;
|
|
});
|
|
|
|
const offsetsLineas = [-12, -6, 0, 6, 12];
|
|
|
|
// 2. Pre-calcular rutas y gradientes (UNA SOLA VEZ)
|
|
conexiones.forEach(conn => {
|
|
const n1 = nodosMap[conn.from];
|
|
const n2 = nodosMap[conn.to];
|
|
const isHoriz = conn.type === 'horizontal';
|
|
|
|
conn.rutasCache = {}; // Diccionario para guardar las rutas
|
|
|
|
// Crear y fijar Gradiente
|
|
const gradId = `grad-${conn.from}-${conn.to}`;
|
|
const grad = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient');
|
|
grad.setAttribute('id', gradId);
|
|
grad.setAttribute('gradientUnits', 'userSpaceOnUse');
|
|
grad.setAttribute('x1', n1.x);
|
|
grad.setAttribute('y1', n1.y);
|
|
grad.setAttribute('x2', n2.x);
|
|
grad.setAttribute('y2', n2.y);
|
|
|
|
const stop1 = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
|
|
stop1.setAttribute('offset', '0%');
|
|
stop1.setAttribute('stop-color', n1.color);
|
|
|
|
const stop2 = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
|
|
stop2.setAttribute('offset', '100%');
|
|
const colorTarget = n2.id === 'c' ? '#0e626e' : n2.color;
|
|
stop2.setAttribute('stop-color', colorTarget);
|
|
|
|
grad.appendChild(stop1);
|
|
grad.appendChild(stop2);
|
|
svgDefs.appendChild(grad);
|
|
|
|
// Función matemática
|
|
const calcularRuta = (offsetX, offsetY) => {
|
|
let cp1x, cp1y, cp2x, cp2y;
|
|
if (isHoriz) {
|
|
const distanciaX = n2.x - n1.x;
|
|
cp1x = n1.x + distanciaX * 0.5;
|
|
cp1y = n1.y;
|
|
cp2x = n2.x - distanciaX * 0.5;
|
|
cp2y = n2.y;
|
|
} else {
|
|
cp1x = n1.x + conn.curveOut;
|
|
cp1y = n1.y;
|
|
cp2x = n2.x + conn.curveOut;
|
|
cp2y = n2.y;
|
|
}
|
|
return `M ${n1.x + offsetX} ${n1.y + offsetY} C ${cp1x + offsetX} ${cp1y + offsetY}, ${cp2x + offsetX} ${cp2y + offsetY}, ${n2.x + offsetX} ${n2.y + offsetY}`;
|
|
};
|
|
|
|
// Dibujar y Cachear las 5 líneas base
|
|
conn.pathsBase = [];
|
|
offsetsLineas.forEach(offset => {
|
|
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
path.classList.add('linea-base');
|
|
path.setAttribute('stroke', `url(#${gradId})`);
|
|
|
|
const rutaCalculada = calcularRuta(isHoriz ? 0 : offset, isHoriz ? offset : 0);
|
|
path.setAttribute('d', rutaCalculada);
|
|
conn.rutasCache[offset] = rutaCalculada; // Guardado en caché
|
|
|
|
grupoLineas.appendChild(path);
|
|
conn.pathsBase.push({ el: path, offset: offset });
|
|
});
|
|
|
|
// Crear pulsos
|
|
conn.pulsos = [];
|
|
const cantPulsos = 10;
|
|
|
|
for (let i = 0; i < cantPulsos; i++) {
|
|
const pathPulso = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
pathPulso.classList.add('linea-pulso');
|
|
|
|
const carrilInicial = offsetsLineas[Math.floor(Math.random() * offsetsLineas.length)];
|
|
pathPulso.setAttribute('d', conn.rutasCache[carrilInicial]); // Le asignamos su ruta desde la caché
|
|
|
|
grupoLineas.appendChild(pathPulso);
|
|
|
|
conn.pulsos.push({
|
|
el: pathPulso,
|
|
currentOffset: carrilInicial,
|
|
needsPathUpdate: false, // Bandera de optimización
|
|
dash: (1200 / cantPulsos) * i + Math.random() * 50,
|
|
speed: 2.0 + Math.random() * 1.5
|
|
});
|
|
}
|
|
});
|
|
|
|
// 3. Lógica de salto entre carriles
|
|
setInterval(() => {
|
|
conexiones.forEach(conn => {
|
|
conn.pulsos.forEach(p => {
|
|
if (Math.random() > 0.8) {
|
|
p.currentOffset = offsetsLineas[Math.floor(Math.random() * offsetsLineas.length)];
|
|
p.needsPathUpdate = true; // Avisamos que en el próximo frame debe cambiar de ruta
|
|
}
|
|
});
|
|
});
|
|
}, 1200);
|
|
|
|
// 4. Motor de Animación Ultraligero
|
|
function animarFrame() {
|
|
conexiones.forEach(conn => {
|
|
conn.pulsos.forEach(p => {
|
|
p.dash -= p.speed;
|
|
|
|
// OPTIMIZACIÓN EXTREMA: Solo interactuamos con el DOM si el pulso saltó de carril
|
|
if (p.needsPathUpdate) {
|
|
p.el.setAttribute('d', conn.rutasCache[p.currentOffset]);
|
|
p.needsPathUpdate = false;
|
|
}
|
|
|
|
// Lo único que se actualiza contínuamente es el desplazamiento
|
|
p.el.style.strokeDashoffset = p.dash;
|
|
});
|
|
});
|
|
|
|
requestAnimationFrame(animarFrame);
|
|
}
|
|
|
|
animarFrame(); |