diff --git a/4-data-visualization/5-treemap/index.css b/4-data-visualization/5-treemap/index.css new file mode 100644 index 0000000..4984151 --- /dev/null +++ b/4-data-visualization/5-treemap/index.css @@ -0,0 +1,28 @@ +html { + text-align: center; + margin: 0; + height: 100vh; + width: 100vw; + background-color: navajowhite; +} + +#tooltip { + opacity: 0; + height: 50px; + width: 250px; + border-radius: 5px; + padding: 10px; + z-index: 10; + position: absolute; + background-color: greenyellow; +} + +#chart { + text-align: center; +} + +#legend svg { + border-radius: 5px; +} + +/*# sourceMappingURL=index.css.map */ diff --git a/4-data-visualization/5-treemap/index.css.map b/4-data-visualization/5-treemap/index.css.map new file mode 100644 index 0000000..d817e19 --- /dev/null +++ b/4-data-visualization/5-treemap/index.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["index.scss"],"names":[],"mappings":"AAAA;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE","file":"index.css"} \ No newline at end of file diff --git a/4-data-visualization/5-treemap/index.html b/4-data-visualization/5-treemap/index.html new file mode 100644 index 0000000..65c52f3 --- /dev/null +++ b/4-data-visualization/5-treemap/index.html @@ -0,0 +1,19 @@ + + + + + Freecodecamp Treemap diagram + + + + + +

Video Game Sales

+

Top 100 Most Sold Video Games Grouped by Platform

+
+
+
+
+ + + \ No newline at end of file diff --git a/4-data-visualization/5-treemap/index.js b/4-data-visualization/5-treemap/index.js new file mode 100644 index 0000000..35c2bfa --- /dev/null +++ b/4-data-visualization/5-treemap/index.js @@ -0,0 +1,162 @@ +const tooltip = d3.select("#tooltip"); + +const w = 1295; +const h = 1300; + +const colorScale = d3.scaleOrdinal().range(d3.schemePastel2); + +const svg = d3 + .select("#chart") + .append("svg") + .attr("width", w + 20) + .attr("height", h + 20) + .append("g") + .attr("transform", `translate(10, 10)`); + +d3.json( + "https://cdn.freecodecamp.org/testable-projects-fcc/data/tree_map/video-game-sales-data.json" +).then((data) => { + const root = d3 + .hierarchy(data) + .sum((d) => { + return d.value; + }) + .sort((a, b) => { + return b.height - a.height || b.value - a.value; + }); + d3.treemap().size([w, h])(root); + svg + .selectAll("rect") + .data(root.leaves()) + .join("rect") + .attr("class", "tile") + .attr("x", function (d) { + return d.y0; + }) + .attr("y", function (d) { + return d.x0; + }) + .attr("width", function (d) { + return d.y1 - d.y0; + }) + .attr("height", function (d) { + return d.x1 - d.x0; + }) + .attr("data-name", (d) => { + return d.data.name; + }) + .attr("data-category", (d) => { + return d.data.category; + }) + .attr("data-value", (d) => { + return d.data.value; + }) + .attr("fill", (d) => { + return colorScale(d.data.category); + }) + .style("stroke", "black") + .on("mouseover", (e) => { + tooltip + .style("opacity", 0.8) + .style("left", e.pageX + "px") + .style("top", e.pageY + "px") + .attr("data-value", e.target.attributes["data-value"].nodeValue) + .html(`Name: ${e.target.attributes["data-name"].nodeValue} +
Category: ${e.target.attributes["data-category"].nodeValue} +
Value: ${e.target.attributes["data-value"].nodeValue}`); + }) + .on("mouseout", () => { + d3.select("#tooltip").style("opacity", 0); + }); + + svg + .selectAll("text") + .data(root.leaves()) + .join("text") + .attr("x", function (d) { + return d.y0 + 5; + }) + .attr("y", function (d) { + return d.x0 + 10; + }) + .selectAll("tspan") + .data((d) => { + return d.data.name.split(/[\/\s]/g); + }) + .enter() + .append("tspan") + .text((d) => { + return d; + }) + .attr("y", function (d, i) { + const parent = this.parentElement; + const y = parseFloat(parent.getAttribute("y")); + if (i === 0) { + return y; + } else { + return y + i * 10; + } + }) + .attr("x", function (d, i) { + const parent = this.parentElement; + return parent.getAttribute("x"); + }) + .attr("font-size", "12px") + .attr("fill", "black"); + + let categories = root.leaves().map((item) => { + return item.data.category; + }); + categories = categories.filter((category, index, self) => { + return self.indexOf(category) === index; + }); + const legend = d3 + .select("#legend") + .append("svg") + .attr("height", 200) + .attr("width", 500) + .style("background", "grey"); + + legend + .selectAll("rect") + .data(categories) + .join("rect") + .attr("class", "legend-item") + .attr("data-category", (d) => d) + .attr("fill", (d) => { + return colorScale(d); + }) + .attr("x", 10) + .attr("y", 10) + .attr("transform", function (d, i) { + return ( + "translate(" + + (i % 5) * 100 + + "," + + (Math.floor(i / 5) * 10 + 40 * Math.floor(i / 5)) + + ")" + ); + }) + .attr("height", 10) + .attr("width", 10); + + legend + .selectAll("text") + .data(categories) + .join("text") + .attr("fill", "black") + .attr("x", 30) + .attr("y", 20) + .attr("transform", function (d, i) { + return ( + "translate(" + + (i % 5) * 100 + + "," + + (Math.floor(i / 5) * 10 + 40 * Math.floor(i / 5)) + + ")" + ); + }) + .text((d) => { + return d; + }); +}); diff --git a/4-data-visualization/5-treemap/index.scss b/4-data-visualization/5-treemap/index.scss new file mode 100644 index 0000000..cf963e4 --- /dev/null +++ b/4-data-visualization/5-treemap/index.scss @@ -0,0 +1,26 @@ +html { + text-align: center; + margin: 0; + height: 100vh; + width: 100vw; + background-color: navajowhite; +} + +#tooltip{ + opacity: 0; + height: 50px; + width: 250px; + border-radius: 5px; + padding: 10px; + z-index: 10; + position: absolute; + background-color: greenyellow; +} + +#chart { + text-align: center; +} + +#legend svg{ + border-radius: 5px; +} \ No newline at end of file