diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000000000000000000000000000000000000..c95cb21d83fc7c66cd0cbce811aef946054376de --- /dev/null +++ b/src/style.css @@ -0,0 +1,9 @@ +.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 ca75922469138af4248f71b86a1b254a4919342f..40a3b5cdf081f074f88e81b71dbdaa36d317c054 100644 --- a/src/visualizacion.html +++ b/src/visualizacion.html @@ -2,15 +2,24 @@ <html lang="es"> <head> <title>Visualización DESI</title> - </head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v7.min.js"></script> - + <link href="style.css" rel="stylesheet"> + </head> <body> - <script src="visualizacion.js"></script> + <div> + <label for="color_scheme"> + Filtrado por: + </label> + <select id="color_scheme" oninput=""> + <option value="platform">Plataforma</option> + <option value="developer">Desarrollador</option> + </select> + </div> <div class="container" id="div-leyenda"> <!-- En esta seccion la leyenda --> <!-- Interaccion con D3 para modificar HTML aqui --> </div> + <script src="visualizacion.js"></script> </body> </html> \ No newline at end of file diff --git a/src/visualizacion.js b/src/visualizacion.js index 1984bc8c65f1b895f0e095c3dcdfde12634611b7..30e8513838160da9dff604566224a56760b221fd 100644 --- a/src/visualizacion.js +++ b/src/visualizacion.js @@ -1,97 +1,178 @@ /** - * Diccionario de correspondencia de una consola / plataforma con su color representativo + * Diccionario de correspondencia de colores */ -const consolaColores = { - Nintendo64: "#E1A84E", - PlayStation: "#4A7DCE", - PlayStation3: "#666666", - Dreamcast: "#D47A45", - Xbox360: "#8BBF61", - Wii: "#5EB8EC", - XboxOne: "#629A62", - Switch: "#C84D4D", - PlayStation2: "#3A66A1", - PlayStation4: "#3D76C9", - GameCube: "#8B5DB7", - Xbox: "#619A61", - PC: "#9A9A9A", - WiiU: "#63B6D5", - GameBoyAdvance: "#8574B5", - "3DS": "#C1536E", - DS: "#BBBBBB", - PlayStationVita: "#5A7EB0", - PSP: "#545454", - XboxSeriesX: "#4F5B4A", - PlayStation5: "#C5D1E3", - Stadia: "#D45A3B" -}; +const colores = { + "platform" : { + Nintendo64: "#E1A84E", + PlayStation: "#4A7DCE", + PlayStation3: "#6666e0", + Dreamcast: "#D47A45", + Xbox360: "#8BBF61", + Wii: "#5EB8EC", + XboxOne: "#629A62", + Switch: "#C84D4D", + PlayStation2: "#3A66A1", + PlayStation4: "#3D76C9", + GameCube: "#8B5DB7", + Xbox: "#619A61", + PC: "#9A9A9A", + WiiU: "#63B6D5", + GameBoyAdvance: "#8574B5", + "3DS": "#C1536E", + DS: "#BBBBBB", + PlayStationVita: "#5A7EB0", + PSP: "#5454f0", + XboxSeriesX: "#4F5B4A", + PlayStation5: "#C5D1E3", + Stadia: "#D45A3B" + }, + "developer" : { + Capcom: "#C75450", + TelltaleGames: "#6A9CCB", + EASports: "#65A879", + Nintendo: "#D84840", + Konami: "#C25C74", + EACanada: "#518E85", + UbisoftMontreal: "#5A78B8", + Ubisoft: "#4C96C9", + SquareEnix: "#D48E47", + OmegaForce: "#A17367", + ElectronicArts: "#7A9098", + EATiburon: "#68A8B9", + Codemasters: "#84A85B", + Sega: "#5272A5", + BandaiNamcoGames: "#D69444", + VisualConcepts: "#6488C0", + "Traveller'sTales": "#9569A1", + VicariousVisions: "#A3A658", + Namco: "#C87478" + } +} -/** - * Diccionario de correspondencia de una desarrolladora con su color correspondiente. - * Si una desarrolladora no está dentro del diccionario tomará un color gris claro #BBBBBB - * En este diccionario solo aparecen los 20 desarrolladores que más aparecen - */ -const developerColores = { - Capcom: "#C75450", - TelltaleGames: "#6A9CCB", - EASports: "#65A879", - Nintendo: "#D84840", - Konami: "#C25C74", - EACanada: "#518E85", - UbisoftMontreal: "#5A78B8", - Ubisoft: "#4C96C9", - SquareEnix: "#D48E47", - OmegaForce: "#A17367", - ElectronicArts: "#7A9098", - EATiburon: "#68A8B9", - Codemasters: "#84A85B", - Sega: "#5272A5", - BandaiNamcoGames: "#D69444", - VisualConcepts: "#6488C0", - "Traveller'sTales": "#9569A1", - VicariousVisions: "#A3A658", - Namco: "#C87478" -}; +const width = 1000; +const height = 500; +const margin_x = 62; +const margin_y = 60; +const right_margin = 300; -const width = 1000; -const height = 600; -const margin_x = 32; -const margin_y = 20; +let selection = "platform" + 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})`); -/** - * data {@type List} - */ + +let xScale; +let yScale; +let radiusScale; + + +function createAxis() { + const xAxis = d3.axisBottom(xScale).ticks(10); + const yAxis = d3.axisLeft(yScale).ticks(10); + + svg.append("g") + .attr("class", "xAxis") + .attr("transform", `translate(0,${height})`) + .call(xAxis); + svg.append('text') + .attr('class', 'xAxisLabel') + .attr('x', width / 5) + .attr('y', height + 40) + .style('font-weight', 'bold') + .style('font-size', '20px') + .style('font-family', 'Georgia, serif') + .text("Calificacion 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('transform', 'rotate(-90)') + .text("Calificacion dada por expertos") +} + d3.csv('files/games-data.csv').then((data) => { - - data.forEach(d => { - d["user score"] = +d["user score"]; - if(!d["user score"]) d["critics"] = -14; - d["score"] = +d["score"] / 10; + + data.forEach(elem => { + elem["user score"] = +elem["user score"]; + if(!elem["user score"]) elem["critics"] = -14; + elem["score"] = +elem["score"] / 10; // Los datos estan entre 0 y 100, asi que normalizo a entre 0 y 10 - d["critics"] = +d["critics"]; - d["users"] = +d["users"]; + elem["critics"] = +elem["critics"]; + elem["users"] = +elem["users"]; + elem.id = elem.name.replaceAll(/[ :'"()\[\]]*/g, ''); }); - const xScale = d3.scaleLinear().domain( - [0, d3.max(data, d => d["user-score"]) || 10] - ).range([0, width]); - const yScale = d3.scaleLinear().domain([0, 10]).range([height, 0]); - const xAxis = d3.axisBottom(xScale).ticks(10); - const yAxis = d3.axisLeft(yScale).ticks(10); + 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]); + - const radiusScale = d3.scaleSqrt().range([5, 20]) - .domain([0, d3.max(data, d => d["critics"]) || 1]); - svg.append("g").attr("class", "xAxis").attr("transform", `translate(0,${height})`).call(xAxis); - svg.append("g").attr("class", "yAxis").call(yAxis); let elegibleData = data.sort((a, b) => { return (b["critics"] + b["users"]) - (a["critics"] + a["users"]) }).slice(0, 50); - + + createAxis(); + appendBubbles(elegibleData); + +}); + +function handleMouseOver(event, elem) { + + const rectAparitionTime = 300; + + d3.select(this) + .transition() + .duration(300) + .ease(d3.easeQuadInOut) + .attr("r", radiusScale(elem.critics) * 1.4) + + 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) + + svg.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) + .transition() + .duration(rectAparitionTime) + .ease(d3.easeQuadInOut) + .style('opacity', 1) +} + +function handleMouseOut(event, elem) { + d3.select(this) + .attr('r', d => radiusScale(d.critics)); + d3.selectAll('.videogame_title').remove(); + d3.select(`#rect${elem.id}-${elem.platform}`).remove(); +} + +function appendBubbles(elegibleData) { svg.selectAll("circle") .data(elegibleData) .enter() @@ -99,22 +180,18 @@ d3.csv('files/games-data.csv').then((data) => { .attr("cx", d => xScale(d["user score"])) .attr("cy", d => yScale(d["score"])) .attr("r", d => radiusScale(d["critics"])) - .attr("fill", d => consolaColores[d["platform"]]) + .attr("fill", d => colores["platform"][d["platform"]]) .attr("stroke", "#000000") .attr("stroke-width", 1) - .append("title") - .text(d => `${d.name}\nPlataforma: ${d.platform}\n` + - `Desarrollador: ${d.developer}\nJugadores: ${d.players}`) - - - - - -}); - - - + .on("mouseover", handleMouseOver) + .on("mouseout", handleMouseOut) +} +function removeBubbles() { + svg.selectAll('circle').remove() +} +function changeSelection (event) { +}