diff --git a/Asia.json b/Asia.json
new file mode 100644
index 00000000..c52196d6
--- /dev/null
+++ b/Asia.json
@@ -0,0 +1,27 @@
+{
+ "name": "world",
+ "children": [
+ {
+ "name": "Asia",
+ "color": "#f58321",
+ "children": [
+ {"name": "China", "weight": 14.84, "code": "CN"},
+ {"name": "Japan", "weight": 5.91, "code": "JP"},
+ {"name": "India", "weight": 2.83, "code": "IN"},
+ {"name": "South Korea", "weight": 1.86, "code": "KR"},
+ {"name": "Russia", "weight": 1.8, "code": "RU"},
+ {"name": "Indonesia", "weight": 1.16, "code": "ID"},
+ {"name": "Turkey", "weight": 0.97, "code": "TR"},
+ {"name": "Saudi Arabia", "weight": 0.87, "code": "SA"},
+ {"name": "Iran", "weight": 0.57, "code": "IR"},
+ {"name": "Thaïland", "weight": 0.53, "code": "TH"},
+ {"name": "United Arab Emirates", "weight": 0.5, "code": "AE"},
+ {"name": "Hong Kong", "weight": 0.42, "code": "HK"},
+ {"name": "Israel", "weight": 0.4, "code": "IL"},
+ {"name": "Malasya", "weight": 0.4, "code": "MY"},
+ {"name": "Singapore", "weight": 0.39, "code": "SG"},
+ {"name": "Philippines", "weight": 0.39, "code": "PH"}
+ ]
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/AsiaGDP.json b/AsiaGDP.json
new file mode 100644
index 00000000..294724f0
--- /dev/null
+++ b/AsiaGDP.json
@@ -0,0 +1,18 @@
+[
+{"name": "China", "weight": 14.84},
+{"name": "Japan", "weight": 5.91},
+{"name": "India", "weight": 2.83},
+{"name": "South Korea", "weight": 1.86},
+{"name": "Russia", "weight": 1.8},
+{"name": "Indonesia", "weight": 1.16},
+{"name": "Turkey", "weight": 0.97},
+{"name": "Saudi Arabia", "weight": 0.87},
+{"name": "Iran", "weight": 0.57},
+{"name": "Thaïland", "weight": 0.53},
+{"name": "United Arab Emirates", "weight": 0.5},
+{"name": "Hong Kong", "weight": 0.42},
+{"name": "Israel", "weight": 0.4},
+{"name": "Malasya", "weight": 0.4},
+{"name": "Singapore", "weight": 0.39},
+{"name": "Philippines", "weight": 0.39}
+]
\ No newline at end of file
diff --git a/codeBlock.html b/codeBlock.html
new file mode 100644
index 00000000..aa81c2c0
--- /dev/null
+++ b/codeBlock.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+ Code Example
+
+
+
+
+
+
+
+
All About Treemaps
+
+
+
+
Inline Code Example
+
+ This is an example of <code> element for showing
+ inline code.
+
+
+
Code Block Example
+
+
+ // This is a sample code snippet in JavaScript
+ function greet(name) {
+ console.log("Hello, " + name + "!");
+ }
+
+ greet("World");
+
+
+
+
+
+
diff --git a/codeTutorial.html b/codeTutorial.html
new file mode 100644
index 00000000..6e681a11
--- /dev/null
+++ b/codeTutorial.html
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+ Creating a Simple Voronoi Treemap
+
+
+
+
+
+
+
Creating a Simple Voronoi Treemap with D3.js
+
+
+
+
+
+ In order to create a simple Voronoi treemap using D3.js, follow these
+ steps:
+
+
+
+
+
+
+ Initialize the HTML Structure:
+
+ Set up the HTML structure with an SVG container where the treemap will
+ be rendered.
+
+ <svg id="simpleVoronoi"></svg>
+
+ The <svg> element with the ID "simpleVoronoi"
+ serves as the container for the Voronoi treemap.
+
+
+
+
+
+ Import D3.js Library:
+
+ Import the D3.js library by adding the following script tag just
+ before your custom script:
+
+ <script
+ src="https://d3js.org/d3.v7.min.js"></script>
+
+ This script tag imports the D3.js library from the official CDN,
+ making D3.js functionalities available in your project.
+
+
+
+
+
+ Initialize the Voronoi Treemap:
+
+ Define constants for SVG dimensions, data, and necessary variables.
+ Initialize the Voronoi treemap by calling functions to set up data,
+ layout, and drawing.
+
+
+const HEIGHT = 500;
+const WIDTH = 960;
+const HALF_WIDTH = WIDTH / 2;
+const HALF_HEIGHT = HEIGHT / 2;
+
+// Define your data array here
+const data = [/* Your data array */];
+
+// Initialize SVG container
+const svg = d3.select("#simpleVoronoi")
+ .attr("width", WIDTH)
+ .attr("height", HEIGHT);
+
+const TREEMAP_RADIUS = Math.min(HALF_WIDTH, HALF_HEIGHT);
+
+const _voronoiTreemap = d3.voronoiTreemap();
+let hierarchy, circlingPolygon;
+
+const fontScale = d3.scaleLinear();
+
+function init(rootData) {
+ initData();
+ initLayout();
+ hierarchy = d3.hierarchy({ children: rootData }).sum((d) => d.weight);
+ _voronoiTreemap.clip(circlingPolygon)(hierarchy);
+
+ drawTreemap(hierarchy);
+}
+
+init(data);
+
+
+ This block of code initializes constants, sets up the SVG container,
+ and prepares data and layout for the Voronoi treemap.
+
+
+ Constants like HEIGHT and WIDTH define the
+ dimensions of the SVG container. Data, such as country names, weights,
+ and colors, are stored in the data array. The
+ init function initializes the treemap by calling other
+ functions to set up data, layout, and drawing.
+
+
+
+
+
+ Initialize Data and Layout:
+
+ Define functions to initialize data and layout settings for the
+ treemap.
+
+
+function initData() {
+ circlingPolygon = computeCirclingPolygon();
+ fontScale.domain([3, 20]).range([8, 20]).clamp(true);
+}
+
+function computeCirclingPolygon() {
+ return [
+ [0, 0],
+ [WIDTH, 0],
+ [WIDTH, HEIGHT],
+ [0, HEIGHT],
+ ];
+}
+
+function initLayout() {
+ const drawingArea = svg.append("g").classed("drawingArea", true);
+ const treemapContainer = drawingArea.append("g").classed("treemap-container", true);
+
+ treemapContainer
+ .append("path")
+ .classed("world", true)
+ .attr("transform", `translate(${-TREEMAP_RADIUS}, ${-TREEMAP_RADIUS})`)
+ .attr("d", `M${circlingPolygon.join(",")}Z`);
+}
+
+
+ These functions initialize data and layout settings for the treemap,
+ including the circling polygon and font scale.
+
+
+ The initData function calculates the circling polygon and
+ sets the font scale based on the provided data. The
+ computeCirclingPolygon function calculates the vertices
+ of the circling polygon, while the initLayout function
+ sets up the SVG container and draws the circling polygon.
+
+
+
+
+
+ Draw the Treemap:
+
+ Create a function to draw the Voronoi treemap based on the provided
+ data and layout.
+
+
+function drawTreemap(hierarchy) {
+ const leaves = hierarchy.leaves();
+
+ const cells = svg.select(".treemap-container")
+ .append("g")
+ .classed("cells", true)
+ .selectAll(".cell")
+ .data(leaves)
+ .enter()
+ .append("path")
+ .classed("cell", true)
+ .attr("d", (d) => `M${d.polygon.join(",")}z`)
+ .style("stroke", "black")
+ .style("stroke-width", "10px")
+ .style("fill", (d) => d.data.color);
+
+ const labels = svg.select(".treemap-container")
+ .append("g")
+ .classed("labels", true)
+ .selectAll(".label")
+ .data(leaves)
+ .enter()
+ .append("g")
+ .classed("label", true)
+ .attr("transform", (d) => `translate(${d.polygon.site.x}, ${d.polygon.site.y})`)
+ .style("font-size", (d) => fontScale(d.data.weight));
+
+ labels
+ .append("text")
+ .classed("name", true)
+ .html((d) => d.data.name);
+
+ labels
+ .append("text")
+ .classed("value", true)
+ .text((d) => `${d.data.weight}%`);
+}
+
+
+ This function draws the Voronoi treemap based on the provided data and
+ layout settings, including cells and labels.
+
+
+ The drawTreemap function creates cells and labels for
+ each data point in the treemap. It appends SVG elements for cells and
+ labels, styles them accordingly, and positions them based on the
+ calculated data. The cells represent the Voronoi regions, while the
+ labels display country names and weights.
+
+
+
+
+
+ © 2024 Voronoi Treemaps
+
+
+
diff --git a/globalEconomyByGDP.json b/globalEconomyByGDP.json
new file mode 100644
index 00000000..72d0e59b
--- /dev/null
+++ b/globalEconomyByGDP.json
@@ -0,0 +1,89 @@
+{
+ "name": "world",
+ "children": [
+ {
+ "name": "Asia",
+ "color": "#ffffcc",
+ "children": [
+ {"name": "China", "weight": 14.84, "code": "CN"},
+ {"name": "Japan", "weight": 5.91, "code": "JP"},
+ {"name": "India", "weight": 2.83, "code": "IN"},
+ {"name": "South Korea", "weight": 1.86, "code": "KR"},
+ {"name": "Russia", "weight": 1.8, "code": "RU"},
+ {"name": "Indonesia", "weight": 1.16, "code": "ID"},
+ {"name": "Turkey", "weight": 0.97, "code": "TR"},
+ {"name": "Saudi Arabia", "weight": 0.87, "code": "SA"},
+ {"name": "Iran", "weight": 0.57, "code": "IR"},
+ {"name": "Thaïland", "weight": 0.53, "code": "TH"},
+ {"name": "United Arab Emirates", "weight": 0.5, "code": "AE"},
+ {"name": "Hong Kong", "weight": 0.42, "code": "HK"},
+ {"name": "Israel", "weight": 0.4, "code": "IL"},
+ {"name": "Malasya", "weight": 0.4, "code": "MY"},
+ {"name": "Singapore", "weight": 0.39, "code": "SG"},
+ {"name": "Philippines", "weight": 0.39, "code": "PH"}
+ ]
+ },
+ {
+ "name": "North America",
+ "color": "#ffcc99",
+ "children": [
+ {"name": "United States", "weight": 24.32, "code": "US"},
+ {"name": "Canada", "weight": 2.09, "code": "CA"},
+ {"name": "Mexico", "weight": 1.54, "code": "MX"}
+ ]
+ },
+ {
+ "name": "Europe",
+ "color": "#ffcccc",
+ "children": [
+ {"name": "Germany", "weight": 4.54, "code": "DE"},
+ {"name": "United Kingdom", "weight": 3.85, "code": "UK"},
+ {"name": "France", "weight": 3.26, "code": "FR"},
+ {"name": "Italy", "weight": 2.46, "code": "IT"},
+ {"name": "Spain", "weight": 1.62, "code": "ES"},
+ {"name": "Netherlands", "weight": 1.01, "code": "NL"},
+ {"name": "Switzerland", "weight": 0.9, "code": "CH"},
+ {"name": "Sweden", "weight": 0.67, "code": "SE"},
+ {"name": "Poland", "weight": 0.64, "code": "PL"},
+ {"name": "Belgium", "weight": 0.61, "code": "BE"},
+ {"name": "Norway", "weight": 0.52, "code": "NO"},
+ {"name": "Austria", "weight": 0.51, "code": "AT"},
+ {"name": "Denmark", "weight": 0.4, "code": "DK"},
+ {"name": "Ireland", "weight": 0.38, "code": "IE"}
+ ]
+ },
+ {
+ "name": "South America",
+ "color": "#ff99cc",
+ "children": [
+ {"name": "Brazil", "weight": 2.39, "code": "BR"},
+ {"name": "Argentina", "weight": 0.79, "code": "AR"},
+ {"name": "Venezuela", "weight": 0.5, "code": "VE"},
+ {"name": "Colombia", "weight": 0.39, "code": "CO"}
+ ]
+ },
+ {
+ "name": "Australia",
+ "color": "#ffccff",
+ "children": [
+ {"name": "Australia", "weight": 1.81, "code": "AU"}
+ ]
+ },
+ {
+ "name": "Africa",
+ "color": "#cc99ff",
+ "children": [
+ {"name": "Nigeria", "weight": 0.65, "code": "NG"},
+ {"name": "Egypt", "weight": 0.45, "code": "EG"},
+ {"name": "South Africa", "weight": 0.42, "code": "ZA"}
+ ]
+ },
+ {
+ "name": "Rest of the World",
+ "color": "#ccccff",
+ "children": [
+ {"name": "Rest of the World", "weight": 9.41, "code": "RotW"}
+ ]
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..1db88d40
--- /dev/null
+++ b/index.html
@@ -0,0 +1,292 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Home page
+
+
+
+
+
+
+
+
+
+
Voronoi Treemap
+
+
+
+
+
What are Voronoi Treemaps?
+
+ Voronoi Treemaps are methods of visualizing hierarchical data, where
+ each cell represents a portion of the data and the hierarchy is encoded
+ by the nesting of cells within each other. Unlike traditional Treemaps,
+ Voronoi Tree Maps do not use rectangles to represent the data, but
+ rather use arbitrary polygons to represent the data. This allows for a
+ more organic and natural representation of the data.
+
+
+
+
+
Traditional Treemap
+
+
+ This is a Traditional Treemap. Notice how the rectangles are used to
+ represent the data. This can lead to a more rigid and less organic
+ representation of the data.
+
+
+
+
+
+
+
+
Voronoi Treemap
+
+ This is a Voronoi Treemap. Notice how the polygons are used to represent
+ the data. As you can see the data seems to have a more organic and
+ natural representation.
+
+
+
+
+
+
+
+
+
+
+
+
Creating a Simple Voronoi Treemap with D3.js
+
+
+
+
+
+ In order to create a simple Voronoi treemap using D3.js, follow these
+ steps:
+
+
+
+
+
+
+ Initialize the HTML Structure:
+
+ Set up the HTML structure with an SVG container where the treemap will
+ be rendered.
+
+ <svg id="simpleVoronoi"></svg>
+
+ The <svg> element with the ID "simpleVoronoi"
+ serves as the container for the Voronoi treemap.
+
+
+
+
+
+ Import D3.js Library:
+
+ Import the D3.js library by adding the following script tag just
+ before your custom script:
+
+ <script
+ src="https://d3js.org/d3.v7.min.js"></script>
+
+ This script tag imports the D3.js library from the official CDN,
+ making D3.js functionalities available in your project.
+
+
+
+
+
+ Initialize the Voronoi Treemap:
+
+ Define constants for SVG dimensions, data, and necessary variables.
+ Initialize the Voronoi treemap by calling functions to set up data,
+ layout, and drawing.
+
+
+const HEIGHT = 500;
+const WIDTH = 960;
+const HALF_WIDTH = WIDTH / 2;
+const HALF_HEIGHT = HEIGHT / 2;
+
+// Define your data array here
+const data = [/* Your data array */];
+
+// Initialize SVG container
+const svg = d3.select("#simpleVoronoi")
+ .attr("width", WIDTH)
+ .attr("height", HEIGHT);
+
+const TREEMAP_RADIUS = Math.min(HALF_WIDTH, HALF_HEIGHT);
+
+const _voronoiTreemap = d3.voronoiTreemap();
+let hierarchy, circlingPolygon;
+
+const fontScale = d3.scaleLinear();
+
+function init(rootData) {
+ initData();
+ initLayout();
+ hierarchy = d3.hierarchy({ children: rootData }).sum((d) => d.weight);
+ _voronoiTreemap.clip(circlingPolygon)(hierarchy);
+
+ drawTreemap(hierarchy);
+}
+
+init(data);
+
+
+ This block of code initializes constants, sets up the SVG container,
+ and prepares data and layout for the Voronoi treemap.
+
+
+ Constants like HEIGHT and WIDTH define the
+ dimensions of the SVG container. Data, such as country names, weights,
+ and colors, are stored in the data array. The
+ init function initializes the treemap by calling other
+ functions to set up data, layout, and drawing.
+
+
+
+
+
+ Initialize Data and Layout:
+
+ Define functions to initialize data and layout settings for the
+ treemap.
+
+
+function initData() {
+ circlingPolygon = computeCirclingPolygon();
+ fontScale.domain([3, 20]).range([8, 20]).clamp(true);
+}
+
+function computeCirclingPolygon() {
+ return [
+ [0, 0],
+ [WIDTH, 0],
+ [WIDTH, HEIGHT],
+ [0, HEIGHT],
+ ];
+}
+
+function initLayout() {
+ const drawingArea = svg.append("g").classed("drawingArea", true);
+ const treemapContainer = drawingArea.append("g").classed("treemap-container", true);
+
+ treemapContainer
+ .append("path")
+ .classed("world", true)
+ .attr("transform", `translate(${-TREEMAP_RADIUS}, ${-TREEMAP_RADIUS})`)
+ .attr("d", `M${circlingPolygon.join(",")}Z`);
+}
+
+
+ These functions initialize data and layout settings for the treemap,
+ including the circling polygon and font scale.
+
+
+ The initData function calculates the circling polygon and
+ sets the font scale based on the provided data. The
+ computeCirclingPolygon function calculates the vertices
+ of the circling polygon, while the initLayout function
+ sets up the SVG container and draws the circling polygon.
+
+
+
+
+
+ Draw the Treemap:
+
+ Create a function to draw the Voronoi treemap based on the provided
+ data and layout.
+
+
+function drawTreemap(hierarchy) {
+ const leaves = hierarchy.leaves();
+
+ const cells = svg.select(".treemap-container")
+ .append("g")
+ .classed("cells", true)
+ .selectAll(".cell")
+ .data(leaves)
+ .enter()
+ .append("path")
+ .classed("cell", true)
+ .attr("d", (d) => `M${d.polygon.join(",")}z`)
+ .style("stroke", "black")
+ .style("stroke-width", "10px")
+ .style("fill", (d) => d.data.color);
+
+ const labels = svg.select(".treemap-container")
+ .append("g")
+ .classed("labels", true)
+ .selectAll(".label")
+ .data(leaves)
+ .enter()
+ .append("g")
+ .classed("label", true)
+ .attr("transform", (d) => `translate(${d.polygon.site.x}, ${d.polygon.site.y})`)
+ .style("font-size", (d) => fontScale(d.data.weight));
+
+ labels
+ .append("text")
+ .classed("name", true)
+ .html((d) => d.data.name);
+
+ labels
+ .append("text")
+ .classed("value", true)
+ .text((d) => `${d.data.weight}%`);
+}
+
+
+ This function draws the Voronoi treemap based on the provided data and
+ layout settings, including cells and labels.
+
+
+ The drawTreemap function creates cells and labels for
+ each data point in the treemap. It appends SVG elements for cells and
+ labels, styles them accordingly, and positions them based on the
+ calculated data. The cells represent the Voronoi regions, while the
+ labels display country names and weights.
+
+
+
+
+
+
+
+ © 2024 Voronoi Treemaps
+
+
diff --git a/index.js b/index.js
new file mode 100644
index 00000000..c5e36119
--- /dev/null
+++ b/index.js
@@ -0,0 +1,111 @@
+const HEIGHT = 500;
+const WIDTH = 960;
+const HALF_WIDTH = WIDTH / 2;
+const HALF_HEIGHT = HEIGHT / 2;
+
+const data = [
+ { name: "China", weight: 14.84, color: "#ffffcc" },
+ { name: "Japan", weight: 5.91, color: "#ffcc99" },
+ { name: "India", weight: 2.83, color: "#ffcccc" },
+ { name: "South Korea", weight: 1.86, color: "#ff99cc" },
+ { name: "Russia", weight: 1.8, color: "#ffccff" },
+ { name: "Indonesia", weight: 1.16, color: "#cc99ff" },
+ { name: "Turkey", weight: 0.97, color: "#ccccff" },
+ { name: "Saudi Arabia", weight: 0.87, color: "#99ccff" },
+ { name: "Iran", weight: 0.57, color: "#ccffff" },
+ { name: "Thaïland", weight: 0.53, color: "#99ffcc" },
+ { name: "UAE", weight: 0.5, color: "#ccffcc" },
+ { name: "Hong Kong", weight: 0.42, color: "#ccff99" },
+];
+
+var svg = d3;
+
+const TREEMAP_RADIUS = Math.min(HALF_WIDTH, HALF_HEIGHT);
+
+const _voronoiTreemap = d3.voronoiTreemap();
+let hierarchy, circlingPolygon;
+
+const fontScale = d3.scaleLinear();
+
+let drawingArea, treemapContainer;
+
+function init(rootData) {
+ initData();
+ initLayout();
+ hierarchy = d3.hierarchy({ children: rootData }).sum((d) => d.weight);
+ _voronoiTreemap.clip(circlingPolygon)(hierarchy);
+
+ drawTreemap(hierarchy);
+}
+
+init(data);
+
+function initData() {
+ circlingPolygon = computeCirclingPolygon();
+ fontScale.domain([3, 20]).range([8, 20]).clamp(true);
+}
+
+function computeCirclingPolygon() {
+ return [
+ [0, 0],
+ [WIDTH, 0],
+ [WIDTH, HEIGHT],
+ [0, HEIGHT],
+ ];
+}
+
+function initLayout() {
+ svg = d3
+ .select("#simpleVoronoi")
+ .attr("width", WIDTH)
+ .attr("height", HEIGHT)
+ .attr("transform", "translate(0, 30)");
+ drawingArea = svg.append("g").classed("drawingArea", true);
+ treemapContainer = drawingArea.append("g").classed("treemap-container", true);
+
+ treemapContainer
+ .append("path")
+ .classed("world", true)
+ .attr("transform", `translate(${-TREEMAP_RADIUS}, ${-TREEMAP_RADIUS})`)
+ .attr("d", `M${circlingPolygon.join(",")}Z`);
+}
+
+function drawTreemap(hierarchy) {
+ const leaves = hierarchy.leaves();
+
+ treemapContainer
+ .append("g")
+ .classed("cells", true)
+ .selectAll(".cell")
+ .data(leaves)
+ .enter()
+ .append("path")
+ .classed("cell", true)
+ .attr("d", (d) => `M${d.polygon.join(",")}z`)
+ .style("stroke", "black")
+ .style("stroke-width", "10px")
+ .style("fill", (d) => d.data.color);
+
+ const labels = treemapContainer
+ .append("g")
+ .classed("labels", true)
+ .selectAll(".label")
+ .data(leaves)
+ .enter()
+ .append("g")
+ .classed("label", true)
+ .attr(
+ "transform",
+ (d) => `translate(${d.polygon.site.x}, ${d.polygon.site.y})`
+ )
+ .style("font-size", (d) => fontScale(d.data.weight));
+
+ labels
+ .append("text")
+ .classed("name", true)
+ .html((d) => d.data.name);
+ labels
+ .append("text")
+ .classed("value", true)
+ .text((d) => `${d.data.weight}%`);
+}
diff --git a/navbar.html b/navbar.html
new file mode 100644
index 00000000..26ea8c0a
--- /dev/null
+++ b/navbar.html
@@ -0,0 +1,5 @@
+
+ Home
+ Code
+ Examples
+
diff --git a/style.css b/style.css
new file mode 100644
index 00000000..596f2b17
--- /dev/null
+++ b/style.css
@@ -0,0 +1,150 @@
+/* Basic styling for the navigation bar */
+
+body {
+ font-family: Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+}
+
+div {
+}
+
+h1 {
+ margin: 0px 0 0 0;
+}
+
+nav {
+ background-color: #333;
+ color: #fff;
+ text-align: center;
+ padding: 10px 0;
+ position: fixed; /* Make the navigation bar fixed */
+ width: 100%; /* Make it full width */
+ top: 0; /* Stick it to the top of the screen */
+ z-index: 999;
+}
+nav a {
+ color: #fff;
+ text-decoration: none;
+ padding: 0 15px;
+}
+nav a:hover {
+ /* background-color: #555; */
+ color: #a52020;
+ transition: color 0.1s ease-in-out;
+}
+.container {
+ max-width: 800px;
+ margin: 20px auto;
+ padding: 20px;
+ background-color: #fff;
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+pre {
+ background-color: #f4f4f4;
+ padding: 10px;
+ border: 1px solid #ddd;
+ border-radius: 5px;
+ overflow-x: auto; /* Enable horizontal scrollbar if needed */
+}
+code {
+ font-family: Consolas, monospace;
+ font-size: 14px;
+ color: #333;
+}
+
+.title {
+ padding: auto;
+ padding-top: 30px;
+ display: grid;
+ place-items: center;
+ font-size: 2rem;
+}
+
+svg {
+ background-color: white;
+}
+
+.cell {
+ stroke: white;
+ stroke-width: 1px;
+}
+.label {
+ text-anchor: middle;
+ fill: black;
+}
+
+.label > .name {
+ dominant-baseline: text-after-edge;
+}
+
+.label > .value {
+ dominant-baseline: text-before-edge;
+}
+
+/* BEGIN INDEX HTML */
+.homeTitleText {
+ padding: auto;
+ padding-top: 50px;
+ padding-bottom: 20px;
+ font-size: 1.2rem;
+ padding-left: 20px;
+}
+
+.simpleVoronoi {
+ display: flex;
+ padding-left: 20px;
+}
+
+.centerText {
+ display: grid;
+ padding-top: 0px;
+ padding-left: 20px;
+ font-size: 1.5rem;
+}
+
+.centerText h2 {
+ font-size: 1.3rem;
+ display: grid;
+}
+
+.centerText p {
+ font-size: 1rem;
+ max-width: 900px;
+}
+
+/* Footer */
+footer {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 50px 0 10px 0;
+}
+
+/* END INDEX HTML */
+
+/* BEGIN CODETUTORIAL HTML*/
+.codeTitle {
+ padding: auto;
+ padding-top: 120px;
+ font-size: 1.2rem;
+ padding-left: 20px;
+}
+
+.codeIntro {
+ padding: auto;
+ padding-top: 5px;
+ font-size: 1rem;
+ max-width: 900px;
+ padding-left: 20px;
+}
+
+/* END CODETUTORIAL HTML*/
+
+/* BEGIN VORONOITREEMAPS HTML */
+.complexVoronoi {
+ display: grid;
+ place-content: center;
+ padding-top: 50px;
+}
diff --git a/treemap.csv b/treemap.csv
new file mode 100644
index 00000000..c3d1fbb6
--- /dev/null
+++ b/treemap.csv
@@ -0,0 +1,18 @@
+name,parent,value
+Origin,,
+CN,Origin,14.84
+JP,Origin,5.91
+IN,Origin,2.83
+KR,Origin,1.86
+RU,Origin,1.8
+ID,Origin,1.16
+TR,Origin,0.97
+SA,Origin,0.87
+IR,Origin,0.57
+TH,Origin,0.53
+AE,Origin,0.5
+HK,Origin,0.42
+IL,Origin,0.4
+MY,Origin,0.4
+SG,Origin,0.39
+PH,Origin,0.39
diff --git a/treemap.js b/treemap.js
new file mode 100644
index 00000000..1cc799e4
--- /dev/null
+++ b/treemap.js
@@ -0,0 +1,76 @@
+// set the dimensions and margins of the graph
+var margin = { top: 0, right: 10, bottom: 0, left: 0 },
+ width = 980 - margin.left - margin.right,
+ height = 520 - margin.top - margin.bottom;
+
+// append the svg object to the body of the page
+var svg = d3
+ .select("#my_dataviz")
+ .append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+// Read data
+d3.csv("./treemap.csv", function (data) {
+ // stratify the data: reformatting for d3.js
+ var root = d3
+ .stratify()
+ .id(function (d) {
+ return d.name;
+ }) // Name of the entity (column name is name in csv)
+ .parentId(function (d) {
+ return d.parent;
+ })(
+ // Name of the parent (column name is parent in csv)
+ data
+ );
+ root.sum(function (d) {
+ return +d.value;
+ }); // Compute the numeric value for each entity
+
+ // Then d3.treemap computes the position of each element of the hierarchy
+ // The coordinates are added to the root object above
+ d3.treemap().size([width, height]).padding(10)(root);
+
+ console.log(root.leaves());
+ // use this information to add rectangles:
+ svg
+ .selectAll("rect")
+ .data(root.leaves())
+ .enter()
+ .append("rect")
+ .attr("x", function (d) {
+ return d.x0;
+ })
+ .attr("y", function (d) {
+ return d.y0;
+ })
+ .attr("width", function (d) {
+ return d.x1 - d.x0;
+ })
+ .attr("height", function (d) {
+ return d.y1 - d.y0;
+ })
+ .style("stroke", "black")
+ .style("fill", "#ffcc99");
+
+ // and to add the text labels
+ svg
+ .selectAll("text")
+ .data(root.leaves())
+ .enter()
+ .append("text")
+ .attr("x", function (d) {
+ return d.x0 + 10;
+ }) // +10 to adjust position (more right)
+ .attr("y", function (d) {
+ return d.y0 + 20;
+ }) // +20 to adjust position (lower)
+ .text(function (d) {
+ return d.data.name;
+ })
+ .attr("font-size", "10px")
+ .attr("fill", "black");
+});
diff --git a/voronoiTreemaps.html b/voronoiTreemaps.html
new file mode 100644
index 00000000..bd4c77b9
--- /dev/null
+++ b/voronoiTreemaps.html
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+ d3-voronoi-treemap usage
+
+
+
+
+
+
+
+
diff --git a/voronoiTreemaps.js b/voronoiTreemaps.js
new file mode 100644
index 00000000..6bfef9c5
--- /dev/null
+++ b/voronoiTreemaps.js
@@ -0,0 +1,228 @@
+//begin: constants
+var _2PI = 2 * Math.PI;
+//end: constants
+
+//begin: layout conf.
+var svgWidth = 960,
+ svgHeight = 500,
+ margin = { top: 10, right: 10, bottom: 10, left: 10 },
+ height = svgHeight - margin.top - margin.bottom,
+ width = svgWidth - margin.left - margin.right,
+ halfWidth = width / 2,
+ halfHeight = height / 2,
+ quarterWidth = width / 4,
+ quarterHeight = height / 4,
+ titleY = 20,
+ legendsMinY = height - 20,
+ treemapRadius = 205,
+ treemapCenter = [halfWidth, halfHeight + 5];
+//end: layout conf.
+
+//begin: treemap conf.
+var _voronoiTreemap = d3.voronoiTreemap();
+var hierarchy, circlingPolygon;
+//end: treemap conf.
+
+//begin: drawing conf.
+var fontScale = d3.scaleLinear();
+//end: drawing conf.
+
+//begin: reusable d3Selection
+var svg, drawingArea, treemapContainer;
+//end: reusable d3Selection
+
+d3.json("globalEconomyByGDP.json").then(function (rootData) {
+ initData();
+ initLayout(rootData);
+ hierarchy = d3.hierarchy(rootData).sum(function (d) {
+ return d.weight;
+ });
+ _voronoiTreemap.clip(circlingPolygon)(hierarchy);
+
+ drawTreemap(hierarchy);
+});
+
+function initData(rootData) {
+ circlingPolygon = computeCirclingPolygon(treemapRadius);
+ fontScale.domain([3, 20]).range([8, 20]).clamp(true);
+}
+
+function computeCirclingPolygon(radius) {
+ var points = 60,
+ increment = _2PI / points,
+ circlingPolygon = [];
+
+ for (var a = 0, i = 0; i < points; i++, a += increment) {
+ circlingPolygon.push([
+ radius + radius * Math.cos(a),
+ radius + radius * Math.sin(a),
+ ]);
+ }
+
+ return circlingPolygon;
+}
+
+function initLayout(rootData) {
+ svg = d3.select("svg").attr("width", svgWidth).attr("height", svgHeight);
+
+ drawingArea = svg
+ .append("g")
+ .classed("drawingArea", true)
+ .attr("transform", "translate(" + [margin.left, margin.top] + ")");
+
+ treemapContainer = drawingArea
+ .append("g")
+ .classed("treemap-container", true)
+ .attr("transform", "translate(" + treemapCenter + ")");
+
+ treemapContainer
+ .append("path")
+ .classed("world", true)
+ .attr("transform", "translate(" + [-treemapRadius, -treemapRadius] + ")")
+ .attr("d", "M" + circlingPolygon.join(",") + "Z");
+
+ drawTitle();
+ drawFooter();
+ drawLegends(rootData);
+}
+
+function drawTitle() {
+ drawingArea
+ .append("text")
+ .attr("id", "title")
+ .attr("transform", "translate(" + [halfWidth, titleY] + ")")
+ .attr("text-anchor", "middle");
+ // .text("The Global Economy by GDP (as of 01/2017)");
+}
+
+function drawFooter() {
+ drawingArea
+ .append("text")
+ .classed("tiny light", true)
+ .attr("transform", "translate(" + [0, height] + ")")
+ .attr("text-anchor", "start");
+ drawingArea
+ .append("text")
+ .classed("tiny light", true)
+ .attr("transform", "translate(" + [halfWidth, height] + ")")
+ .attr("text-anchor", "middle");
+ drawingArea
+ .append("text")
+ .classed("tiny light", true)
+ .attr("transform", "translate(" + [width, height] + ")")
+ .attr("text-anchor", "end");
+}
+
+function drawLegends(rootData) {
+ var legendHeight = 13,
+ interLegend = 4,
+ colorWidth = legendHeight * 6,
+ continents = rootData.children.reverse();
+
+ var legendContainer = drawingArea
+ .append("g")
+ .classed("legend", true)
+ .attr("transform", "translate(" + [0, legendsMinY] + ")");
+
+ var legends = legendContainer.selectAll(".legend").data(continents).enter();
+
+ var legend = legends
+ .append("g")
+ .classed("legend", true)
+ .attr("transform", function (d, i) {
+ return "translate(" + [0, -i * (legendHeight + interLegend)] + ")";
+ });
+
+ legend
+ .append("rect")
+ .classed("legend-color", true)
+ .attr("y", -legendHeight)
+ .attr("width", colorWidth)
+ .attr("height", legendHeight)
+ .style("fill", function (d) {
+ return d.color;
+ });
+ legend
+ .append("text")
+ .classed("tiny", true)
+ .attr("transform", "translate(" + [colorWidth + 5, -2] + ")")
+ .text(function (d) {
+ return d.name;
+ });
+
+ legendContainer
+ .append("text")
+ .attr(
+ "transform",
+ "translate(" +
+ [0, -continents.length * (legendHeight + interLegend) - 5] +
+ ")"
+ )
+ .text("Continents");
+}
+
+function drawTreemap(hierarchy) {
+ var leaves = hierarchy.leaves();
+
+ var cells = treemapContainer
+ .append("g")
+ .classed("cells", true)
+ .attr("transform", "translate(" + [-treemapRadius, -treemapRadius] + ")")
+ .selectAll(".cell")
+ .data(leaves)
+ .enter()
+ .append("path")
+ .classed("cell", true)
+ .attr("d", function (d) {
+ return "M" + d.polygon.join(",") + "z";
+ })
+ .style("fill", function (d) {
+ return d.parent.data.color;
+ });
+
+ var labels = treemapContainer
+ .append("g")
+ .classed("labels", true)
+ .attr("transform", "translate(" + [-treemapRadius, -treemapRadius] + ")")
+ .selectAll(".label")
+ .data(leaves)
+ .enter()
+ .append("g")
+ .classed("label", true)
+ .attr("transform", function (d) {
+ return "translate(" + [d.polygon.site.x, d.polygon.site.y] + ")";
+ })
+ .style("font-size", function (d) {
+ return fontScale(d.data.weight);
+ });
+
+ labels
+ .append("text")
+ .classed("name", true)
+ .html(function (d) {
+ return d.data.weight < 1 ? d.data.code : d.data.name;
+ });
+ labels
+ .append("text")
+ .classed("value", true)
+ .text(function (d) {
+ return d.data.weight + "%";
+ });
+
+ var hoverers = treemapContainer
+ .append("g")
+ .classed("hoverers", true)
+ .attr("transform", "translate(" + [-treemapRadius, -treemapRadius] + ")")
+ .selectAll(".hoverer")
+ .data(leaves)
+ .enter()
+ .append("path")
+ .classed("hoverer", true)
+ .attr("d", function (d) {
+ return "M" + d.polygon.join(",") + "z";
+ });
+
+ hoverers.append("title").text(function (d) {
+ return d.data.name + "\n" + d.value + "%";
+ });
+}