From 6294eaf8a9bd67794a2e34a074ae545f04e872c5 Mon Sep 17 00:00:00 2001 From: = <=> Date: Tue, 10 Dec 2024 22:03:37 +0100 Subject: [PATCH] =?UTF-8?q?A=C3=B1adidos=20varios=20elementos=20de=20inter?= =?UTF-8?q?actividad=20e=20informacion=20al=20mover=20el=20raton=20por=20e?= =?UTF-8?q?ncima=20de=20una=20burbuja.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/style.css | 8 -- src/visualizacion.html | 4 +- src/visualizacion.js | 182 ++++++++++++++++++++++++++++------------- 3 files changed, 129 insertions(+), 65 deletions(-) diff --git a/src/style.css b/src/style.css index c95cb21..8b13789 100644 --- a/src/style.css +++ b/src/style.css @@ -1,9 +1 @@ -.videogame_rect { - opacity: 0.95; -} -.videogame_title { - font-family: Georgia, serif; - font-weight: bolder; - font-size: 17px; -} \ No newline at end of file diff --git a/src/visualizacion.html b/src/visualizacion.html index 40a3b5c..2bf892f 100644 --- a/src/visualizacion.html +++ b/src/visualizacion.html @@ -9,9 +9,9 @@ <body> <div> <label for="color_scheme"> - Filtrado por: + Coloreado por: </label> - <select id="color_scheme" oninput=""> + <select id="color_scheme" onchange="changeSelection(event)"> <option value="platform">Plataforma</option> <option value="developer">Desarrollador</option> </select> diff --git a/src/visualizacion.js b/src/visualizacion.js index 30e8513..719f154 100644 --- a/src/visualizacion.js +++ b/src/visualizacion.js @@ -49,28 +49,44 @@ const colores = { } } + + + + + +let selection = "platform"; + +let elegibleData; + +let xScale; +let yScale; +let xAxis; +let yAxis; + +let radiusScale; + +let min_x = 0; +let min_y = 0; +let max_x = 10; +let max_y = 10; + const width = 1000; const height = 500; const margin_x = 62; const margin_y = 60; const right_margin = 300; - - -let selection = "platform" +const rectAparitionTime = 300; +const radiusTransition = 300; const svg = d3.select('body').append('svg') .attr("width", width + 2 * margin_x).attr("height", height + 2 * margin_y) .append('g').attr("transform", `translate(${margin_x},${margin_y})`); -let xScale; -let yScale; -let radiusScale; - function createAxis() { - const xAxis = d3.axisBottom(xScale).ticks(10); - const yAxis = d3.axisLeft(yScale).ticks(10); + xAxis = d3.axisBottom(xScale).ticks(10); + yAxis = d3.axisLeft(yScale).ticks(10); svg.append("g") .attr("class", "xAxis") @@ -83,16 +99,19 @@ function createAxis() { .style('font-weight', 'bold') .style('font-size', '20px') .style('font-family', 'Georgia, serif') - .text("Calificacion dada por usuarios") + .text("Calificación dada por usuarios") svg.append("g") .attr("class", "yAxis") .call(yAxis); svg.append('text') .attr('class', 'yAxisLabel') - .attr('x', -10) - .attr('y', height/2 + margin_y) + .attr('x', -height*4/5) + .attr('y', -30) + .style('font-weight', 'bold') + .style('font-size', '20px') + .style('font-family', 'Georgia, serif') .attr('transform', 'rotate(-90)') - .text("Calificacion dada por expertos") + .text("Calificación dada por expertos") } d3.csv('files/games-data.csv').then((data) => { @@ -104,87 +123,139 @@ d3.csv('files/games-data.csv').then((data) => { // Los datos estan entre 0 y 100, asi que normalizo a entre 0 y 10 elem["critics"] = +elem["critics"]; elem["users"] = +elem["users"]; + elem.genre = [...new Set(elem.genre.split(','))]; elem.id = elem.name.replaceAll(/[ :'"()\[\]]*/g, ''); }); - xScale = d3.scaleLinear().domain([0, 10]).range([0, width-right_margin]); - yScale = d3.scaleLinear().domain([0, 10]).range([height, 0]); - - - radiusScale = d3.scaleSqrt().domain([0, d3.max(data, elem => elem["critics"]) || 1]).range([5, 20]); + xScale = d3.scaleLinear().domain([min_x, max_x]).range([0, width-right_margin]); + yScale = d3.scaleLinear().domain([min_y, max_y]).range([height, 0]); + radiusScale = d3.scaleSqrt().domain([0, d3.max(data, elem => elem["critics"]) || 1]).range([5, 15]); - - - let elegibleData = data.sort((a, b) => { + elegibleData = data.sort((a, b) => { return (b["critics"] + b["users"]) - (a["critics"] + a["users"]) }).slice(0, 50); createAxis(); - appendBubbles(elegibleData); + createBubbles(elegibleData); }); function handleMouseOver(event, elem) { - - const rectAparitionTime = 300; - d3.select(this) .transition() - .duration(300) + .duration(radiusTransition) .ease(d3.easeQuadInOut) .attr("r", radiusScale(elem.critics) * 1.4) + const rectGroup = svg.append('g') + .attr('class', 'rects') - svg.append('rect') - .attr('id', `rect${elem.id}-${elem.platform}`) - .attr('class', 'videogame_rect') - .attr('rx', 4) - .attr('ry', 4) - .attr('x', () => xScale(elem["user score"]) + 30) - .attr('y', () => yScale(elem.score) - 20) - .attr('width', elem.name.length*11) - .attr('height', 100) - .attr('fill', () => colores[selection][elem[selection]]) - .attr('stroke', 'black') - .attr('stroke-width', 2) - .style('opacity', 0) - .transition() - .duration(rectAparitionTime) - .ease(d3.easeQuadInOut) - .style('opacity', 1) + const textGroup = svg.append('g') + .attr('class', 'texts') - svg.append('text') + const text = textGroup.append('text') .attr('id', `text${elem.id}-${elem.platform}`) .attr('class', 'videogame_title') .attr('x', () => xScale(elem["user score"]) + 35) .attr('y', () => yScale(elem["score"]) - 5) - .text(elem.name) - .style('opacity', 0) + .attr('font-family', 'Georgia, serif') + .attr('font-weight', 'bold') + .attr('font-size', '15px') + .attr('fill', 'black') + .attr('opacity', 0) .transition() .duration(rectAparitionTime) .ease(d3.easeQuadInOut) - .style('opacity', 1) + .attr('opacity', 1) + + const lines = [ + elem.name, + `Generos: ${elem.genre}`, + `Fecha de lanzamiento: ${elem["r-date"]}` + ]; + svg.select(`#text${elem.id}-${elem.platform}`).selectAll('tspan') + .data(lines) + .enter() + .append('tspan') + .attr('x', () => xScale(elem["user score"]) + 35) + .attr('dy', (d, i) => (i === 0 ? 0 : 20)) + .text(d => d); + + + const bbox = text.node().getBBox(); + + rectGroup.append("rect") + .attr('id', `rect${elem.id}-${elem.platform}`) + .attr("x", bbox.x - 5) + .attr("y", bbox.y - 5) + .attr("width", bbox.width + 10) + .attr("height", bbox.height + 10) + .attr('stroke', 'black') + .attr('stroke-width', 1) + .attr('rx', 4) + .attr('ry', 4) + .attr('opacity', 0) + .attr("fill", () => colores[selection][elem[selection]]) + .transition() + .duration(rectAparitionTime) + .ease(d3.easeQuadInOut) + .attr('opacity', 0.85); + + + svg.select(`#rect${elem.id}-${elem.platform}`).lower(); + + + + } function handleMouseOut(event, elem) { d3.select(this) + .transition() + .duration(radiusTransition) + .ease(d3.easeQuadInOut) .attr('r', d => radiusScale(d.critics)); - d3.selectAll('.videogame_title').remove(); - d3.select(`#rect${elem.id}-${elem.platform}`).remove(); + d3.select(`#text${elem.id}-${elem.platform}`) + .transition() + .duration(rectAparitionTime/2) + .ease(d3.easeQuadInOut) + .style('opacity', 0) + .remove(); + + d3.select(`#rect${elem.id}-${elem.platform}`) + .transition() + .duration(rectAparitionTime/2) + .ease(d3.easeQuadInOut) + .style('opacity', 0) + .remove(); + + } -function appendBubbles(elegibleData) { - svg.selectAll("circle") - .data(elegibleData) +function createBubbles(data) { + const bubbleGroup = svg.append('g') + .attr('class', 'bubbles'); + + + + bubbleGroup.selectAll("circle") + .data(data) .enter() .append("circle") .attr("cx", d => xScale(d["user score"])) .attr("cy", d => yScale(d["score"])) .attr("r", d => radiusScale(d["critics"])) - .attr("fill", d => colores["platform"][d["platform"]]) + .attr("fill", d => { + if (colores[selection][d[selection]]){ + return colores[selection][d[selection]]; + } else return "#aaaaaa"; + }) .attr("stroke", "#000000") .attr("stroke-width", 1) + .lower() .on("mouseover", handleMouseOver) .on("mouseout", handleMouseOut) + + } function removeBubbles() { @@ -192,6 +263,7 @@ function removeBubbles() { } function changeSelection (event) { - + removeBubbles(); + selection = event.target.value; + createBubbles(elegibleData); } - -- GitLab