Files
louiscklaw 9035c1312b update,
2025-02-01 02:09:32 +08:00

483 lines
17 KiB
HTML

<!DOCTYPE html>
<head>
<title>Games Rating: 2015 - 2019</title>
<meta charset="utf-8">
<script type="text/javascript" src="../lib/d3.v5.min.js"></script>
<script type="text/javascript" src="../lib/d3-dsv.min.js"></script>
<style>
/* CSS Styling */
.data-circle {
fill: brown;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 30,
bottom: 30,
left: 60
},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom + 40;
// set the ranges
var xScale = d3.scaleLinear().range([0, width]);
//x.ticks(d3.utcMonth.every(5)).map(formatTime)
var yScale = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom()
.ticks(10)
.scale(xScale);
var yAxis = d3.axisLeft()
.ticks(10)
.scale(yScale);
// Create a line generator
var line = d3.line()
.x(function(d) {
return xScale(d.date);
})
.y(function(d) {
return yScale(d.running_total);
})
var svgElement = d3.select("#container").append("svg")
.attr("width", width + margin.left + margin.right + 50)
.attr("height", height + margin.top + margin.bottom + 80)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + (margin.top + 20) + ")");
// Get the data
d3.csv("average-rating.csv").then(function(data) {
// format the data
var ratings_2015 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var ratings_2016 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var ratings_2017 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var ratings_2018 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var ratings_2019 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var max_rating = 0;
var counts = [0, 0, 0, 0, 0];
data.forEach(function(d) {
if (+d.year == 2015) {
if (ratings_2015[Math.floor(+d.average_rating)] !== undefined)
ratings_2015[Math.floor(+d.average_rating)] += 1;
else
ratings_2015[Math.floor(+d.average_rating)] = 1;
counts[0] = d3.max(ratings_2015);
} else if (+d.year == 2016) {
if (ratings_2016[Math.floor(+d.average_rating)] !== undefined)
ratings_2016[Math.floor(+d.average_rating)] += 1;
else
ratings_2016[Math.floor(+d.average_rating)] = 1;
counts[1] = d3.max(ratings_2016);
} else if (+d.year == 2017) {
if (ratings_2017[Math.floor(+d.average_rating)] !== undefined)
ratings_2017[Math.floor(+d.average_rating)] += 1;
else
ratings_2017[Math.floor(+d.average_rating)] = 1;
counts[2] = d3.max(ratings_2017);
} else if (+d.year == 2018) {
if (ratings_2018[Math.floor(+d.average_rating)] !== undefined)
ratings_2018[Math.floor(+d.average_rating)] += 1;
else
ratings_2018[Math.floor(+d.average_rating)] = 1;
counts[3] = d3.max(ratings_2018);
} else if (+d.year == 2019) {
if (ratings_2019[Math.floor(+d.average_rating)] !== undefined)
ratings_2019[Math.floor(+d.average_rating)] += 1;
else
ratings_2019[Math.floor(+d.average_rating)] = 1;
counts[4] = d3.max(ratings_2019);
}
if (max_rating < Math.floor(+d.average_rating)) {
max_rating = Math.floor(+d.average_rating);
}
});
// Scale the range of the data
xScale.domain([0, max_rating]);
yScale.domain([0, d3.max(counts)]);
//var path = svgElement.append("path")
// .attr("d", line(data));
var circle_ratings = [ratings_2015, ratings_2016, ratings_2017, ratings_2018, ratings_2019];
// Add the x Axis
var xAxis = svgElement.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
// Add the y Axis
var yAxis = svgElement.append("g")
.call(d3.axisLeft(yScale));
// Add the lines
svgElement.append("path")
.datum(ratings_2015)
.attr("fill", "none")
.attr("stroke", "brown")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d, i) {
return xScale(i)
})
.y(function(d) {
return yScale(d)
})
)
svgElement.append("path")
.datum(ratings_2016)
.attr("fill", "none")
.attr("stroke", "pink")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d, i) {
return xScale(i);
})
.y(function(d) {
return yScale(d)
})
)
svgElement.append("path")
.datum(ratings_2017)
.attr("fill", "none")
.attr("stroke", "gray")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d, i) {
return xScale(i);
})
.y(function(d) {
return yScale(d)
})
)
svgElement.append("path")
.datum(ratings_2018)
.attr("fill", "none")
.attr("stroke", "#d0ff2f")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d, i) {
return xScale(i);
})
.y(function(d) {
return yScale(d)
})
)
svgElement.append("path")
.datum(ratings_2019)
.attr("fill", "none")
.attr("stroke", "cyan")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d, i) {
return xScale(i);
})
.y(function(d) {
return yScale(d)
})
)
var lineAndDots = svgElement.append("g")
.attr("class", "line-and-dots")
.attr("transform", "translate(0," + 0 + ")")
lineAndDots.selectAll("line-circle")
.data(ratings_2015)
.enter().append("circle")
.attr("class", "data-circle")
.attr("r", 3)
.attr("cx", function(d, i) {
return xScale(i);
})
.attr("cy", function(d) {
return yScale(d);
})
.on("mouseover", function(d, i) {
d3.select(this).attr("r", 10);
drawBarChart(i, 2015, data);
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 3);
d3.select("#bar").remove();
});
lineAndDots.selectAll("line-circle")
.data(ratings_2016)
.enter().append("circle")
.attr("class", "data-circle")
.attr("r", 3)
.style('fill', 'pink')
.attr("cx", function(d, i) {
return xScale(i);
})
.attr("cy", function(d) {
return yScale(d);
})
.on("mouseover", function(d, i) {
d3.select(this).attr("r", 10);
drawBarChart(i, 2016, data);
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 3);
d3.select("#bar").remove();
});
lineAndDots.selectAll("line-circle")
.data(ratings_2017)
.enter().append("circle")
.attr("class", "data-circle")
.attr("r", 3)
.style('fill', 'gray')
.attr("cx", function(d, i) {
return xScale(i);
})
.attr("cy", function(d) {
return yScale(d);
})
.on("mouseover", function(d, i) {
d3.select(this).attr("r", 10);
drawBarChart(i, 2017, data);
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 3);
d3.select("#bar").remove();
});
lineAndDots.selectAll("line-circle")
.data(ratings_2018)
.enter().append("circle")
.attr("class", "data-circle")
.attr("r", 3)
.style('fill', '#d0ff2f')
.attr("cx", function(d, i) {
return xScale(i);
})
.attr("cy", function(d) {
return yScale(d);
})
.on("mouseover", function(d, i) {
d3.select(this).attr("r", 10);
drawBarChart(i, 2018, data);
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 3);
d3.select("#bar").remove();
});
lineAndDots.selectAll("line-circle")
.data(ratings_2019)
.enter().append("circle")
.attr("class", "data-circle")
.attr("r", 3)
.style('fill', 'cyan')
.attr("cx", function(d, i) {
return xScale(i);
})
.attr("cy", function(d) {
return yScale(d);
})
.on("mouseover", function(d, i) {
d3.select(this).attr("r", 10);
drawBarChart(i, 2019, data);
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 3);
d3.select("#bar").remove();
});
//xAxis Label
svgElement.append("text")
.attr("transform", "translate(" + (width / 2) +
" ," + (height - margin.bottom + margin.top + 50) + ")")
.text("Rating");
//yAxis Label
svgElement.append("text")
.attr("transform", "rotate(-90)")
.attr("x", (0 - (height / 2)))
.attr("y", (0 - margin.left + 15))
.text("Count");
svgElement.append("text")
.attr("x", (width / 2))
.attr("y", -20)
.attr("text-anchor", "middle")
.attr("font-weight", 700)
.text("Board Games by Rating 2015-2019");
svgElement.append("text")
.attr("x", (width / 2))
.attr("y", -5)
.attr("text-anchor", "middle")
.attr("font-weight", 700)
.text("helfayoumy3");
svgElement.append("text")
.attr("x", (width + 10))
.attr("y", 40)
.text("2015");
svgElement.append("circle")
.attr("cx", (width + 2))
.attr("cy", 35)
.attr("r", 5)
.style("fill", "brown");
svgElement.append("text")
.attr("x", (width + 10))
.attr("y", 60)
.text("2016");
svgElement.append("circle")
.attr("cx", (width + 2))
.attr("cy", 55)
.attr("r", 5)
.style("fill", "pink");
svgElement.append("text")
.attr("x", (width + 10))
.attr("y", 80)
.text("2017");
svgElement.append("circle")
.attr("cx", (width + 2))
.attr("cy", 75)
.attr("r", 5)
.style("fill", "gray");
svgElement.append("text")
.attr("x", (width + 10))
.attr("y", 100)
.text("2018");
svgElement.append("circle")
.attr("cx", (width + 2))
.attr("cy", 95)
.attr("r", 5)
.style("fill", "#d0ff2f");
svgElement.append("text")
.attr("x", (width + 10))
.attr("y", 120)
.text("2019");
svgElement.append("circle")
.attr("cx", (width + 2))
.attr("cy", 115)
.attr("r", 5)
.style("fill", "cyan");
});
function drawBarChart(rating, year, data) {
var margin = {
top: 20,
right: 30,
bottom: 30,
left: 60
},
width = 560 - margin.left - margin.right - 80,
height = 400 - margin.top - margin.bottom - 200;
var xScale = d3.scaleLinear().range([0, width]),
yScale = d3.scaleBand().range([height, 0]).padding([0.8]);
var svgElement = d3.select("#container").append("svg")
.attr("width", width + margin.left + margin.right + 50)
.attr("height", height + margin.top + margin.bottom + 80)
.attr("id", "bar")
.append("g")
.attr("transform",
"translate(" + (margin.left + 100) + "," + (margin.top + 20) + ")");
var top5 = {};
data.forEach(function(d) {
if (+d.year == year && Math.floor(+d.average_rating) == rating) {
top5[d.name] = +d.users_rated;
}
});
var items = Object.keys(top5).map(function(key) {
return [key, top5[key]];
});
items.sort(function(first, second) {
return second[1] - first[1];
});
top5 = items.slice(0, 5);
top5 = top5.reverse()
var count = [];
for (var i in top5) {
count.push(top5[i][1]);
}
xScale.domain([0, d3.max(count)]);
yScale.domain(top5.map(function(d) {
return d[0];
}));
// Add the x Axis
var xAxis = svgElement.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
// Add the y Axis
var yAxis = svgElement.append("g")
.call(d3.axisLeft(yScale));
svgElement.selectAll(".bar")
.data(top5)
.enter().append("rect")
.attr("class", "bar")
.attr("fill", "deeppink")
.attr("y", function(d) {
return yScale(d[0]);
})
.attr("height", (4 * yScale.bandwidth()))
.attr("width", function(d) {
return xScale(d[1]);
});
//xAxis Label
svgElement.append("text")
.attr("transform", "translate(" + (width / 2) +
" ," + (height - margin.bottom + margin.top + 50) + ")")
.attr("text-anchor", "middle")
.text("Number of users");
//yAxis Label
svgElement.append("text")
.attr("transform", "rotate(-90)")
.attr("text-anchor", "middle")
.attr("x", (0 - (height / 2)))
.attr("y", (0 - margin.left - 70))
.text("Games");
svgElement.append("text")
.attr("x", (width / 2))
.attr("y", -10)
.attr("text-anchor", "middle")
.text("Top 5 most rated games for year " + year + " with rating " + rating);
}
</script>
</body>