Compare commits

...

2 Commits

Author SHA1 Message Date
Alain Vasquez Ramirez e80bfbcd77 Mis cambios locales 2025-05-07 07:27:37 -06:00
Alain Vasquez Ramirez f00c01838e crearFormacion 2025-05-07 07:23:02 -06:00
5 changed files with 233 additions and 0 deletions

View File

@ -0,0 +1,44 @@
/* editorPiscina.css */
#canvasFormacion {
width: 100%;
height: 400px;
background-color: #e3f4ff;
border-radius: 12px;
box-shadow: 0 0 8px rgba(0,0,0,0.1);
position: relative;
margin-bottom: 20px;
border: 2px solid #007bff;
background-image: linear-gradient(to right, transparent 49%, #999 50%, transparent 51%);
background-size: 100% 100%;
}
.atleta-icono {
position: absolute;
width: 34px;
height: 34px;
border-radius: 50%;
font-size: 12px;
color: white;
font-weight: bold;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
user-select: none;
}
.atleta-volador { background-color: #a259ff; }
.atleta-pilar { background-color: #007bff; }
.atleta-grupoA { border: 2px solid #28a745; }
.atleta-grupoB { border: 2px solid #ffc107; }
.flecha-mirada {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 10px solid #444;
position: absolute;
transform-origin: center center;
}

11
public/css/piscina.css Normal file
View File

@ -0,0 +1,11 @@
#poolCanvas {
background-color: #cceeff;
border: 2px solid #007bff;
border-radius: 6px;
cursor: crosshair;
}
.info {
font-weight: bold;
margin-top: 1rem;
}

104
public/js/piscina.js Normal file
View File

@ -0,0 +1,104 @@
const canvas = document.getElementById("poolCanvas");
const ctx = canvas.getContext("2d");
let currentAtleta = null;
let rutinaId = new URLSearchParams(window.location.search).get("routineId");
let atletas = [];
let colocados = [];
function drawPool() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#cceeff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.moveTo(canvas.width / 2, 0);
ctx.lineTo(canvas.width / 2, canvas.height);
ctx.strokeStyle = "#555";
ctx.setLineDash([6, 4]);
ctx.stroke();
ctx.setLineDash([]);
colocados.forEach(({ x, y, atleta }) => drawAthlete(x, y, atleta));
}
function drawAthlete(x, y, atleta) {
ctx.beginPath();
ctx.arc(x, y, 14, 0, Math.PI * 2);
ctx.fillStyle = "#ff4444";
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = "#fff";
ctx.stroke();
ctx.fillStyle = "#fff";
ctx.font = "bold 12px sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(atleta.idPersonalizado, x, y);
}
canvas.addEventListener("click", (e) => {
if (!currentAtleta) return;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
if (x < 0 || y < 0 || x > canvas.width || y > canvas.height) return;
if (colocados.find(a => a.atleta.idPersonalizado === currentAtleta.idPersonalizado)) {
alert("Este atleta ya fue colocado.");
return;
}
colocados.push({ x, y, atleta: currentAtleta });
updateLegend(currentAtleta);
drawPool();
currentAtleta = null;
});
function updateLegend(atleta) {
const li = document.createElement("li");
li.textContent = `${atleta.idPersonalizado}: ${atleta.atletaId?.name || 'Desconocido'} (${atleta.rol})`;
document.getElementById("legend").appendChild(li);
}
function enablePlacement() {
const index = document.getElementById("athleteSelect").value;
if (index >= 0) {
currentAtleta = atletas[index];
}
}
async function loadRoutine() {
try {
const res = await fetch(`/routines/${rutinaId}`);
const data = await res.json();
document.getElementById("routineTitle").textContent = data.nombreCompetencia;
document.getElementById("routineType").textContent = data.tipoCompetencia;
document.getElementById("routineMode").textContent = data.modalidad;
atletas = data.participantes;
const select = document.getElementById("athleteSelect");
if (!atletas || atletas.length === 0) {
select.innerHTML = `<option disabled>No hay atletas</option>`;
return;
}
atletas.forEach((a, i) => {
const opt = document.createElement("option");
opt.value = i;
opt.textContent = `${a.idPersonalizado} - ${a.atletaId?.name || 'Desconocido'} (${a.rol})`;
select.appendChild(opt);
});
drawPool();
} catch (err) {
console.error("Error cargando rutina:", err);
}
}
window.addEventListener("DOMContentLoaded", loadRoutine);

View File

@ -1,6 +1,67 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Editor de Formación</title>
<link rel="stylesheet" href="css/editorPiscina.css">
<link rel="stylesheet" href="css/piscina.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top">
<div class="container-fluid">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="coach.html">Inicializar Rutina</a>
</li>
<li class="nav-item">
<a class="nav-link" href="equipoDisponibles.html">Equipos Disponibles</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#otroLink2">Catalogo de formaciones</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-5 pt-5">
<h2 id="routineTitle">Cargando nombre...</h2>
<p><strong>Tipo:</strong> <span id="routineType">Cargando...</span></p>
<p><strong>Modalidad:</strong> <span id="routineMode">Cargando...</span></p>
<div class="mb-3">
<label for="athleteSelect" class="form-label">Selecciona atleta:</label>
<select id="athleteSelect" class="form-select"></select>
</div>
<button class="btn btn-success mb-3" onclick="enablePlacement()">Añadir atleta a la formación</button>
<canvas id="poolCanvas" width="1000" height="300"></canvas>
<button class="btn btn-primary mt-3">Guardar Formación</button>
<div class="info">
<ul id="legend" class="mt-3"></ul>
</div>
<h5 class="mt-4">Simbología</h5>
<ul>
<li><strong>1</strong>: Axel</li>
<li><strong>axel, =</strong>: Pilar</li>
</ul>
</div>
<script src="js/piscina.js"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Detalles de la Rutina</title>

View File

@ -71,3 +71,16 @@ router.post('/', async (req, res) => {
});
module.exports = router;
// Ruta para obtener una rutina específica por ID
router.get('/:id', async (req, res) => {
try {
const routine = await Routine.findById(req.params.id)
.populate('participantes.atletaId', 'name'); // para obtener nombres
res.json(routine);
} catch (error) {
console.error('❌ Error al obtener rutina por ID:', error);
res.status(500).json({ error: 'Error cargando rutina' });
}
});