Public
Edited
Jul 3, 2024
Insert cell
Insert cell
Insert cell
{
// create array for the data
const data = {
Africa: 20.7,
Rest: 1479.3
};

//define square sizes, spacing and layout
const squareSize = 10;
const squaresPerRow = 50;
const gapSize = 2;
const totalSquares =
Math.floor(data["Africa"]) + Math.floor(data["Rest"]) + 1; // Adding 1 for the partial square

// Define the colors for each category
const colors = {
Africa: "#10827b",
Rest: "#dedede"
};

// Create a container for the text and SVG
const container = d3.create("div");

// Add the text and sample square using HTML
container.html(`
<div style="font-family: Arial, sans-serif; font-size: 12px; margin-bottom: 10px;">
If each
<span style="display: inline-block; width: ${squareSize}px; height: ${squareSize}px; background-color: ${colors.Rest}; margin-right: 5px;"></span>
represents 1 million doses, this is how far
<span style="background-color: ${colors.Africa}; color: #fff">Africa’s</span> current production is from its target.
</div>
`);

// Create an SVG container
const svg = container
.append("svg")
.attr("width", squaresPerRow * (squareSize + gapSize))
.attr(
"height",
Math.ceil(totalSquares / squaresPerRow) * (squareSize + gapSize)
);

// Create groups for Africa and Rest
const africaGroup = svg.append("g").attr("id", "africa");
const restGroup = svg.append("g").attr("id", "rest");

// Add full squares for Africa
africaGroup
.selectAll("rect.africa")
.data(d3.range(Math.floor(data["Africa"])))
.enter()
.append("rect")
.attr("class", "africa")
.attr("width", squareSize)
.attr("height", squareSize)
.attr("x", (d) => (d % squaresPerRow) * (squareSize + gapSize))
.attr("y", (d) => Math.floor(d / squaresPerRow) * (squareSize + gapSize))
.attr("fill", colors["Africa"]);

// Add the partial square
const africaCount = Math.floor(data["Africa"]);
const partialSquareX = (africaCount % squaresPerRow) * (squareSize + gapSize);
const partialSquareY =
Math.floor(africaCount / squaresPerRow) * (squareSize + gapSize);
const africaRatio = data["Africa"] - africaCount;
const restRatio = 1 - africaRatio;

africaGroup
.append("rect")
.attr("x", partialSquareX)
.attr("y", partialSquareY)
.attr("width", squareSize)
.attr("height", squareSize * africaRatio)
.attr("fill", colors["Africa"]);

restGroup
.append("rect")
.attr("x", partialSquareX)
.attr("y", partialSquareY + squareSize * africaRatio)
.attr("width", squareSize)
.attr("height", squareSize * restRatio)
.attr("fill", colors["Rest"]);

// Add full squares for Rest
restGroup
.selectAll("rect.rest")
.data(d3.range(Math.floor(data["Rest"])))
.enter()
.append("rect")
.attr("class", "rest")
.attr("width", squareSize)
.attr("height", squareSize)
.attr(
"x",
(d) => ((d + africaCount + 1) % squaresPerRow) * (squareSize + gapSize)
)
.attr(
"y",
(d) =>
Math.floor((d + africaCount + 1) / squaresPerRow) *
(squareSize + gapSize)
)
.attr("fill", colors["Rest"]);

return container.node();
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more