|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<html> |
|
<head> |
|
<title>D3.js Marimekko Chart</title> |
|
<script src="https://d3js.org/d3.v7.min.js"></script> |
|
<style> |
|
body { |
|
font-family: sans-serif; |
|
} |
|
.tile { |
|
stroke: #fff; |
|
stroke-width: 1px; |
|
} |
|
.label { |
|
font-size: 12px; |
|
fill: #333; |
|
pointer-events: none; |
|
} |
|
svg { |
|
width: 100%; |
|
height: auto; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<svg id="marimekko"></svg> |
|
|
|
<script> |
|
// Replace this with your uploaded JSON data |
|
const data = [ |
|
{ category: "A", subcategory: "X", value: 30 }, |
|
{ category: "A", subcategory: "Y", value: 20 }, |
|
{ category: "B", subcategory: "X", value: 25 }, |
|
{ category: "B", subcategory: "Y", value: 25 } |
|
]; |
|
|
|
const width = 800; |
|
const height = 400; |
|
|
|
const svg = d3.select("#marimekko") |
|
.attr("viewBox", `0 0 ${width} ${height}`) |
|
.attr("preserveAspectRatio", "xMidYMid meet"); |
|
|
|
// Aggregate totals by category |
|
const categories = d3.rollups(data, v => d3.sum(v, d => d.value), d => d.category); |
|
const total = d3.sum(categories, d => d[1]); |
|
|
|
let x = 0; |
|
categories.forEach(([cat, catTotal]) => { |
|
const catWidth = (catTotal / total) * width; |
|
let y = 0; |
|
|
|
const subcats = data.filter(d => d.category === cat); |
|
const subTotal = d3.sum(subcats, d => d.value); |
|
|
|
subcats.forEach(d => { |
|
const rectHeight = (d.value / subTotal) * height; |
|
|
|
svg.append("rect") |
|
.attr("class", "tile") |
|
.attr("x", x) |
|
.attr("y", y) |
|
.attr("width", catWidth) |
|
.attr("height", rectHeight) |
|
.attr("fill", d3.schemeCategory10[subcats.indexOf(d)]); |
|
|
|
svg.append("text") |
|
.attr("class", "label") |
|
.attr("x", x + catWidth / 2) |
|
.attr("y", y + rectHeight / 2) |
|
.attr("text-anchor", "middle") |
|
.attr("dy", ".35em") |
|
.text(`${cat}-${d.subcategory}`); |
|
|
|
y += rectHeight; |
|
}); |
|
|
|
x += catWidth; |
|
}); |
|
</script> |
|
</body> |
|
</html> |