From 6ce0720379e25c5ef6d08fdc36cd35f88f8aa419 Mon Sep 17 00:00:00 2001 From: rodpena <rodrigo.pena22@estudiantes.uva.es> Date: Wed, 11 Dec 2024 17:38:57 +0100 Subject: [PATCH] comentarios finales --- script.js | 476 ++++++++++++++++++++++++++--------------------------- styles.css | 74 ++++----- 2 files changed, 268 insertions(+), 282 deletions(-) diff --git a/script.js b/script.js index 74c1fbe..3b6da3e 100644 --- a/script.js +++ b/script.js @@ -1,8 +1,33 @@ -// Array global para almacenar los jugadores seleccionados +// Array global para almacenar los jugadores seleccionados y los maximos globales de sus estadisticas let jugadoresSeleccionados = []; - let maximosGlobales = {}; +//Ejecuta al iniciar la pagina web el apartado de Datos de temporada +document.addEventListener("DOMContentLoaded", () => { + restaurarFormaOriginal(); + datosTemporada(); + cargarDatosTemporada(); + cargarGraficosTemporada(); + resaltarBotonActivo("#div-superior"); +}); + +//Evento que abre el apartado de datos de temporada al clickar en su div +d3.select("#div-superior").on("click", () => { + restaurarFormaOriginal(); + datosTemporada(); + cargarDatosTemporada(); + cargarGraficosTemporada(); + resaltarBotonActivo("#div-superior"); +}); + +//Evento que abre el apartado de rendimiento de jugadores al clickar en su div +d3.select("#div-inferior").on("click", () => { + restaurarFormaOriginal(); + rendimientoJugadores(); + cargarJugadoresDesdeArchivo(); + resaltarBotonActivo("#div-inferior"); +}); + // Función para restaurar el div #resto-pantalla a su forma original function restaurarFormaOriginal() { d3.select("#resto-pantalla") @@ -12,7 +37,16 @@ function restaurarFormaOriginal() { .remove(); } -// Nueva función: datosTemporada +// Función para resaltar el div(boton) del apartado que se esta visualizando +function resaltarBotonActivo(selector) { + d3.selectAll("#div-superior, #div-inferior").style("background-color", "#B3E5FC").style("color", "#333"); + d3.select(selector).style("background-color", "#0288D1").style("color", "#FFF").style("font-weight", "bold"); +} + + +//Funciones del apartado "Datos temporada" + +//Modifica el div resto de pantalla para el apartado "Datos de temporada" añadiendole cuatro divs con sus titulos function datosTemporada() { const restoPantalla = d3.select("#resto-pantalla"); @@ -37,9 +71,7 @@ function datosTemporada() { .enter() .append("div") .attr("class", "sector") - .style("border", "1px solid black") .style("background-color", "#4FC3F7") - .style("display", "flex") .style("flex-direction", "column") .style("align-items", "flex-start") .style("justify-content", "flex-start") @@ -61,7 +93,194 @@ function datosTemporada() { }); } -// Función para mostrar la estructura de rendimiento de jugadores +//Carga los datos de la temporada actualizando el contenido de la PosicionFinal y el Número Total de Puntos +function cargarDatosTemporada() { + const csvPath = "assets/estadisticasDatosTemporada.csv"; + + // Leer el archivo CSV + d3.csv(csvPath).then((data) => { + console.log("Datos cargados del CSV:", data); + + // Ajustar las claves según las columnas del CSV + const numeroTotalPuntos = parseInt(data[0]["Número total de puntos"], 10); + const posicionFinal = data[0]["Clasificación"]; + + // Actualizar el sector "Numero Total de Puntos" + d3.select("#resto-pantalla") + .selectAll(".sector") + .filter((d) => d.title === "Número total de puntos") + .select(".sector-content") + .html(`<div class="animated-points" style="font-size: 4em; font-weight: bold;">${numeroTotalPuntos}</div>`); + + + // Actualizar el sector "Posición Final" + d3.select("#resto-pantalla") + .selectAll(".sector") + .filter((d) => d.title === "Posición Final") + .select(".sector-content") + .html(`<div style="text-align: center; font-size: 3em; font-weight: bold;">${posicionFinal}º</div>`); + }).catch((error) => { + console.error("Error cargando el archivo CSV:", error); + }); +} + +//Carga los datos de la temporada actualizando el contenido de los sectores Victorias/Derrotas y Porcentaje de tiro +function cargarGraficosTemporada() { + const csvPath = "assets/estadisticasDatosTemporada.csv"; + + // Leer el archivo CSV + d3.csv(csvPath).then((data) => { + console.log("Datos cargados del CSV:", data); + + + const victorias = parseInt(data[0]["Partidos ganados"], 10); + const derrotas = parseInt(data[0]["Partidos perdidos"], 10); + const porcentajeTiroDos = parseFloat(data[0]["% de tiros de dos"]); + const porcentajeTiroTres = parseFloat(data[0]["% de tiros de tres"]); + const porcentajeTiroLibres = parseFloat(data[0]["% de tiros libres"]); + + const totalPartidos = victorias + derrotas; + const porcentajeVictorias = (victorias / totalPartidos) * 100; + + // Actualizar sector "Victorias/Derrotas" con gráfico de anillo + const sectorVictorias = d3.select("#resto-pantalla .sector:nth-child(1) .sector-content"); + agregarGraficoAnillo( + sectorVictorias.node(), + porcentajeVictorias, + ["#0288D1", "#B3E5FC"], // Colores + `${porcentajeVictorias.toFixed(1)}%` + ); + + // Añadir texto informativo al lado del gráfico + sectorVictorias.selectAll(".texto-informativo").remove(); + sectorVictorias.append("div") + .attr("class", "texto-informativo") + .style("margin", "40px") + .style("text-align", "left") + .style("font-size", "0.6em") + .html(` + - Partidos jugados: ${totalPartidos} <br><br> + - Partidos ganados: ${victorias} <br><br> + - Partidos perdidos: ${derrotas} + `); + + // Actualizar sector "Porcentaje de tiro" con gráfico de anillo y checkboxes + const sectorPorcentajeTiro = d3.select("#resto-pantalla .sector:nth-child(4) .sector-content"); + + // Contenedor para el gráfico inicial + agregarGraficoAnillo( + sectorPorcentajeTiro.node(), + porcentajeTiroDos, + ["#0288D1", "#B3E5FC"], + `${porcentajeTiroDos.toFixed(1)}%` + ); + + // Contenedor para checkboxes + let checkboxesContainer = sectorPorcentajeTiro.select(".checkboxes-tiro"); + if (checkboxesContainer.empty()) { + checkboxesContainer = sectorPorcentajeTiro.append("div") + .attr("class", "checkboxes-tiro") + .style("margin", "40px") + .style("display", "flex") + .style("flex-direction", "column") + .style("align-items", "flex-start") + .style("font-size", "0.6em"); + } + + checkboxesContainer.selectAll("*").remove(); // Limpiar checkboxes previos + + ["% de tiros de dos", "% de tiros de tres", "% de tiros libres"].forEach((label, index) => { + const checkbox = checkboxesContainer.append("label") + .style("display", "flex") + .style("align-items", "center") + .style("margin-bottom", "10px"); + + const input = checkbox.append("input") + .attr("type", "radio") + .attr("name", "tipo-tiro") + .attr("value", index === 0 ? porcentajeTiroDos : index === 1 ? porcentajeTiroTres : porcentajeTiroLibres) + .style("margin-right", "10px") + .on("change", function () { + const selectedValue = parseFloat(this.value); + agregarGraficoAnillo( + sectorPorcentajeTiro.node(), + selectedValue, + ["#0288D1", "#B3E5FC"], + `${selectedValue.toFixed(1)}%` + ); + }); + + // Marcar el checkbox de "% de tiros de dos" como seleccionado por defecto + if (index === 0) { + input.attr("checked", true); + } + + checkbox.append("span").text(label); + }); + }).catch((error) => { + console.error("Error cargando el archivo CSV:", error); + }); +} + +// Función que crea loa graficos anillos de los sectores victorias/derrotas y Porcentaje tiro +function agregarGraficoAnillo(containerSelector, porcentaje, colores, textoInterno) { + const container = d3.select(containerSelector); + + let graficoContainer = container.select(".grafico-anillo"); + if (graficoContainer.empty()) { + graficoContainer = container.append("div").attr("class", "grafico-anillo"); + } + + graficoContainer.selectAll("*").remove(); + + const width = 350; + const height = 350; + const radius = Math.min(width, height) / 2; + + const svg = graficoContainer + .append("svg") + .attr("width", width) + .attr("height", height) + .append("g") + .attr("transform", `translate(${width / 2}, ${height / 2})`); + + + const arc = d3.arc() + .innerRadius(radius * 0.7) + .outerRadius(radius) + .startAngle(0) + .endAngle((2 * Math.PI) * (porcentaje / 100)); + + // Dibuja la sección "rellena" + svg.append("path") + .attr("d", arc) + .style("fill", colores[0]); + + // Dibuja la sección "restante" + svg.append("path") + .attr("d", d3.arc() + .innerRadius(radius * 0.7) + .outerRadius(radius) + .startAngle((2 * Math.PI) * (porcentaje / 100)) + .endAngle(2 * Math.PI)) + .style("fill", colores[1]); + + // Agregar texto en el centro + svg.append("text") + .attr("text-anchor", "middle") + .attr("dy", ".35em") + .style("font-size", "0.8em") + .style("font-weight", "bold") + .text(textoInterno); +} + + +//Funciones del apartado "Rendimiento Jugadores" + +/*Modifica el div resto de pantalla para el apartado "RendimientoJugadores" añadiendole dos divs: + lado-izquierdo(Para almacenar la lista de los jugadores) + lado-derecho(Para mostrar el grafico radar) +*/ function rendimientoJugadores() { const restoPantalla = d3.select("#resto-pantalla"); @@ -76,7 +295,6 @@ function rendimientoJugadores() { .attr("id", "lado-derecho") .style("flex", "1") .style("background-color", "#F5F5F5") - .style("display", "flex") .style("align-items", "center") .style("justify-content", "center") .style("position", "relative"); @@ -84,7 +302,7 @@ function rendimientoJugadores() { crearGraficoRadar("#lado-derecho"); } -// Calcular los máximos para cada estadÃstica +// Calcular los máximos para cada estadÃstica de los jugadores function calcularMaximos(datos) { return { "Puntos/Partido": d3.max(datos, (d) => +d["Puntos/Partido"]), @@ -98,6 +316,8 @@ function calcularMaximos(datos) { }; } + +// Funcion que crea el grafico radar function crearGraficoRadar(containerSelector, jugadoresSeleccionados = [], maximos = null) { const container = d3.select(containerSelector); @@ -124,7 +344,6 @@ function crearGraficoRadar(containerSelector, jugadoresSeleccionados = [], maxim "Minutos/Partido", ]; - // Usa los máximos globales si no se pasan como argumento const rScale = d3.scaleLinear().range([0, radius]).domain([0, 100]); const svg = container @@ -134,7 +353,6 @@ function crearGraficoRadar(containerSelector, jugadoresSeleccionados = [], maxim .append("g") .attr("transform", `translate(${width / 2}, ${height / 2})`); - // Dibujar niveles y etiquetas aquÃ... for (let level = 1; level <= levels; level++) { const levelRadius = (level / levels) * radius; @@ -239,7 +457,7 @@ function crearGraficoRadar(containerSelector, jugadoresSeleccionados = [], maxim }); } - +//Funcion que carga las estadisticas de los jugadores function cargarJugadoresDesdeArchivo() { const csvPath = "assets/estadisticasRendimientoJugadores.csv"; const ladoIzquierdo = d3.select("#lado-izquierdo"); @@ -336,6 +554,7 @@ function cargarJugadoresDesdeArchivo() { }); } +//Funcion que gestiona los jugadores selecionados y actualiza el grafico radar en base a estos function gestionarCheckboxes(data, maximos) { const jugadoresSeleccionados = []; @@ -359,237 +578,4 @@ function gestionarCheckboxes(data, maximos) { // Actualiza el gráfico de radar crearGraficoRadar("#lado-derecho", jugadoresSeleccionados, maximos); -} - - - -function cargarDatosTemporada() { - const csvPath = "assets/estadisticasDatosTemporada.csv"; - - // Leer el archivo CSV - d3.csv(csvPath).then((data) => { - console.log("Datos cargados del CSV:", data); - - // Ajustar las claves según las columnas del CSV - const numeroTotalPuntos = parseInt(data[0]["Número total de puntos"], 10); - const posicionFinal = data[0]["Clasificación"]; - - // Animar el sector "Número total de puntos" - d3.select("#resto-pantalla") - .selectAll(".sector") - .filter((d) => d.title === "Número total de puntos") - .select(".sector-content") - .html(`<div class="animated-points" style="font-size: 4em; font-weight: bold;">0</div>`); - - animatePoints(".animated-points", numeroTotalPuntos, 2000); // Animar puntos en 1 segundo - - // Actualizar el sector "Posición Final" - d3.select("#resto-pantalla") - .selectAll(".sector") - .filter((d) => d.title === "Posición Final") - .select(".sector-content") - .html(`<div style="text-align: center; font-size: 3em; font-weight: bold;">${posicionFinal}º</div>`); - }).catch((error) => { - console.error("Error cargando el archivo CSV:", error); - }); -} - -// Función para animar los puntos -function animatePoints(selector, finalValue, duration) { - const element = document.querySelector(selector); - let startValue = 0; - const step = (timestamp, startTimestamp) => { - const elapsed = timestamp - startTimestamp; - const progress = Math.min(elapsed / duration, 1); // Progresar de 0 a 1 - const currentValue = Math.floor(progress * finalValue); - element.textContent = currentValue; - if (progress < 1) { - requestAnimationFrame((newTimestamp) => step(newTimestamp, startTimestamp)); - } - }; - requestAnimationFrame((timestamp) => step(timestamp, timestamp)); -} - - -function resaltarBotonActivo(selector) { - d3.selectAll("#div-superior, #div-inferior").style("background-color", "#B3E5FC").style("color", "#333"); - d3.select(selector).style("background-color", "#0288D1").style("color", "#FFF").style("font-weight", "bold"); -} - -function agregarGraficoAnillo(containerSelector, porcentaje, colores, textoInterno) { - const container = d3.select(containerSelector); - - // Asegurarse de que existe un subcontenedor exclusivo para el gráfico - let graficoContainer = container.select(".grafico-anillo"); - if (graficoContainer.empty()) { - graficoContainer = container.append("div").attr("class", "grafico-anillo"); - } - - graficoContainer.selectAll("*").remove(); // Limpiar solo el gráfico, no otros elementos - - const width = 350; // Tamaño reducido para adaptarse al layout - const height = 350; - const radius = Math.min(width, height) / 2; - - const svg = graficoContainer - .append("svg") - .attr("width", width) - .attr("height", height) - .append("g") - .attr("transform", `translate(${width / 2}, ${height / 2})`); - - // Configuración del arco - const arc = d3.arc() - .innerRadius(radius * 0.7) // Radio interno para crear el "anillo" - .outerRadius(radius) // Radio externo del anillo - .startAngle(0) - .endAngle((2 * Math.PI) * (porcentaje / 100)); // Proporcional al porcentaje - - // Dibuja la sección "rellena" - svg.append("path") - .attr("d", arc) - .style("fill", colores[0]); // Color principal - - // Dibuja la sección "restante" - svg.append("path") - .attr("d", d3.arc() - .innerRadius(radius * 0.7) - .outerRadius(radius) - .startAngle((2 * Math.PI) * (porcentaje / 100)) - .endAngle(2 * Math.PI)) - .style("fill", colores[1]); // Color secundario - - // Agregar texto en el centro - svg.append("text") - .attr("text-anchor", "middle") - .attr("dy", ".35em") - .style("font-size", "0.8em") // Texto más pequeño para adaptarse - .style("font-weight", "bold") - .text(textoInterno); -} - - - -function cargarGraficosTemporada() { - const csvPath = "assets/estadisticasDatosTemporada.csv"; - - // Leer el archivo CSV - d3.csv(csvPath).then((data) => { - console.log("Datos cargados del CSV:", data); - - // Ajustar las claves según las columnas del CSV - const victorias = parseInt(data[0]["Partidos ganados"], 10); - const derrotas = parseInt(data[0]["Partidos perdidos"], 10); - const porcentajeTiroDos = parseFloat(data[0]["% de tiros de dos"]); - const porcentajeTiroTres = parseFloat(data[0]["% de tiros de tres"]); - const porcentajeTiroLibres = parseFloat(data[0]["% de tiros libres"]); - - const totalPartidos = victorias + derrotas; - const porcentajeVictorias = (victorias / totalPartidos) * 100; - - // Actualizar sector "Victorias/Derrotas" con gráfico de anillo - const sectorVictorias = d3.select("#resto-pantalla .sector:nth-child(1) .sector-content"); - agregarGraficoAnillo( - sectorVictorias.node(), - porcentajeVictorias, - ["#0288D1", "#B3E5FC"], // Colores - `${porcentajeVictorias.toFixed(1)}%` - ); - - // Añadir texto informativo al lado del gráfico - sectorVictorias.selectAll(".texto-informativo").remove(); - sectorVictorias.append("div") - .attr("class", "texto-informativo") - .style("margin", "40px") - .style("text-align", "left") - .style("font-size", "0.6em") - .html(` - - Partidos jugados: ${totalPartidos} <br><br> - - Partidos ganados: ${victorias} <br><br> - - Partidos perdidos: ${derrotas} - `); - - // Actualizar sector "Porcentaje de tiro" con gráfico de anillo y checkboxes - const sectorPorcentajeTiro = d3.select("#resto-pantalla .sector:nth-child(4) .sector-content"); - - // Contenedor para el gráfico inicial - agregarGraficoAnillo( - sectorPorcentajeTiro.node(), - porcentajeTiroDos, - ["#0288D1", "#B3E5FC"], - `${porcentajeTiroDos.toFixed(1)}%` - ); - - // Contenedor para checkboxes - let checkboxesContainer = sectorPorcentajeTiro.select(".checkboxes-tiro"); - if (checkboxesContainer.empty()) { - checkboxesContainer = sectorPorcentajeTiro.append("div") - .attr("class", "checkboxes-tiro") - .style("margin", "40px") - .style("display", "flex") - .style("flex-direction", "column") - .style("align-items", "flex-start") - .style("font-size", "0.6em"); - } - - checkboxesContainer.selectAll("*").remove(); // Limpiar checkboxes previos - - ["% de tiros de dos", "% de tiros de tres", "% de tiros libres"].forEach((label, index) => { - const checkbox = checkboxesContainer.append("label") - .style("display", "flex") - .style("align-items", "center") - .style("margin-bottom", "10px"); - - const input = checkbox.append("input") - .attr("type", "radio") - .attr("name", "tipo-tiro") - .attr("value", index === 0 ? porcentajeTiroDos : index === 1 ? porcentajeTiroTres : porcentajeTiroLibres) - .style("margin-right", "10px") - .on("change", function () { - const selectedValue = parseFloat(this.value); - agregarGraficoAnillo( - sectorPorcentajeTiro.node(), - selectedValue, - ["#0288D1", "#B3E5FC"], - `${selectedValue.toFixed(1)}%` - ); - }); - - // Marcar el checkbox de "% de tiros de dos" como seleccionado por defecto - if (index === 0) { - input.attr("checked", true); - } - - checkbox.append("span").text(label); - }); - }).catch((error) => { - console.error("Error cargando el archivo CSV:", error); - }); -} - - - -// Ejecutar automáticamente la función de datos de temporada al cargar la página -document.addEventListener("DOMContentLoaded", () => { - restaurarFormaOriginal(); - datosTemporada(); - cargarDatosTemporada(); - cargarGraficosTemporada(); - resaltarBotonActivo("#div-superior"); -}); - -// Eventos de clic en los botones de datos -d3.select("#div-superior").on("click", () => { - restaurarFormaOriginal(); - datosTemporada(); - cargarDatosTemporada(); - cargarGraficosTemporada(); - resaltarBotonActivo("#div-superior"); -}); - -d3.select("#div-inferior").on("click", () => { - restaurarFormaOriginal(); - rendimientoJugadores(); - cargarJugadoresDesdeArchivo(); - resaltarBotonActivo("#div-inferior"); -}); +} \ No newline at end of file diff --git a/styles.css b/styles.css index 4211d5e..47fe743 100644 --- a/styles.css +++ b/styles.css @@ -78,23 +78,23 @@ body { margin-right: 10px; color: white; font-size: 1.5em; - display: flex; /* Establece flex para dividir en fila */ - flex-direction: row; /* Divide los hijos en una fila horizontal */ - align-items: stretch; /* Los hijos ocupan toda la altura */ - justify-content: stretch; /* Los hijos ocupan todo el ancho */ + display: flex; + flex-direction: row; + align-items: stretch; + justify-content: stretch; border: 1px solid black; - overflow: hidden; /* Evita que el contenido exceda el tamaño del contenedor */ - box-sizing: border-box; /* Asegura que padding y bordes se incluyan en el tamaño */ - width: 100%; /* Asegura que no exceda el ancho del contenedor principal */ + overflow: hidden; + box-sizing: border-box; + width: 100%; .sector { - width: 100%; /* Ancho completo */ - height: 100%; /* Alto completo */ - display: flex; /* Centra el contenido */ + width: 100%; + height: 100%; + display: flex; align-items: center; justify-content: center; font-size: 1.2em; font-weight: bold; - border: 1px solid black; /* Opcional, para mejor visualización */ + border: 1px solid black; } .sector-title { font-size: 1.2em; @@ -103,30 +103,30 @@ body { } .sector-content { - font-size: 1.5em; /* Aumentar tamaño del contenido */ - color: black; /* Color del texto */ - display: flex; /* Activar Flexbox */ - align-items: center; /* Centrar contenido verticalmente */ - justify-content: center; /* Centrar contenido horizontalmente */ - text-align: left; /* Centrar texto dentro del contenedor */ - margin: 0; /* Eliminar márgenes que podrÃan desalinear */ - height: 100%; /* Asegura que ocupe toda la altura del contenedor */ - width: 100%; /* Asegura que ocupe todo el ancho del contenedor */ + font-size: 1.5em; + color: black; + display: flex; + align-items: center; + justify-content: center; + text-align: left; + margin: 0; + height: 100%; + width: 100%; } } /* Div izquierdo (ocupa de arriba a abajo) */ #lado-izquierdo { - flex: 1; /* Ocupa el 30% del espacio */ - background-color: #0288D1; /* Fondo lila claro */ - border: 1px solid black; /* Borde de separación */ - display: flex; /* Si tiene contenido, lo organiza con flex */ - flex-direction: column; /* Coloca los elementos en columna */ - height: 100%; /* Asegura que ocupe toda la altura */ - padding: 10px; /* Espaciado interno */ - box-sizing: border-box; /* Incluye padding en el tamaño total */ - max-width: 30%; /* Garantiza que no exceda el 30% del ancho */ + flex: 1; + background-color: #0288D1; + border: 1px solid black; + display: flex; + flex-direction: column; + height: 100%; + padding: 10px; + box-sizing: border-box; + max-width: 30%; .jugador-rect { flex: 1; margin: 2px 0; @@ -143,15 +143,15 @@ body { /* Div derecho (ocupa el resto del espacio) */ #lado-derecho { - flex: 3; /* Ocupa el 70% restante del espacio */ - background-color: #FFFFFF; /* Fondo blanco */ + flex: 3; + background-color: #FFFFFF; border: 1px solid black; - display: flex; /* Si tiene contenido, lo organiza con flex */ - flex-direction: column; /* Coloca los elementos en columna */ - height: 100%; /* Asegura que ocupe toda la altura */ - padding: 10px; /* Espaciado interno */ - box-sizing: border-box; /* Incluye padding en el tamaño total */ - max-width: 70%; /* Garantiza que no exceda el 70% del ancho */ + display: flex; + flex-direction: column; + height: 100%; + padding: 10px; + box-sizing: border-box; + max-width: 70%; } -- GitLab