{"spec_id":"treemap-basic","library":"d3","language":"javascript","code":"// anyplot.ai\n// treemap-basic: Basic Treemap\n// Library: d3 7.9.0 | JavaScript 22.23.1\n// Quality: 92/100 | Created: 2026-08-04\n\nconst t = window.ANYPLOT_TOKENS;\nconst { width, height } = window.ANYPLOT_SIZE;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// R&D budget allocation ($ thousands) by division and project\nconst data = {\n  name: \"root\",\n  children: [\n    {\n      name: \"Software Engineering\",\n      children: [\n        { name: \"Platform Core\", value: 420 },\n        { name: \"Mobile Apps\", value: 310 },\n        { name: \"DevOps Tooling\", value: 180 },\n        { name: \"API Gateway\", value: 140 },\n      ],\n    },\n    {\n      name: \"Hardware Engineering\",\n      children: [\n        { name: \"Sensor R&D\", value: 260 },\n        { name: \"PCB Design\", value: 190 },\n        { name: \"Prototyping Lab\", value: 150 },\n      ],\n    },\n    {\n      name: \"Data Science\",\n      children: [\n        { name: \"ML Platform\", value: 240 },\n        { name: \"Forecasting Models\", value: 170 },\n        { name: \"Data Pipeline\", value: 130 },\n      ],\n    },\n    {\n      name: \"Product Design\",\n      children: [\n        { name: \"UX Research\", value: 150 },\n        { name: \"Visual Design\", value: 110 },\n      ],\n    },\n    {\n      name: \"Quality Assurance\",\n      children: [\n        { name: \"Automated Testing\", value: 160 },\n        { name: \"Manual QA\", value: 90 },\n      ],\n    },\n  ],\n};\n\nconst divisions = data.children.map((d) => d.name);\nconst color = d3.scaleOrdinal().domain(divisions).range(t.palette);\n\n// --- Layout -------------------------------------------------------------------\nconst margin = { top: 130, right: 40, bottom: 40, left: 40 };\nconst iw = width - margin.left - margin.right;\nconst ih = height - margin.top - margin.bottom;\n\nconst root = d3\n  .hierarchy(data)\n  .sum((d) => d.value)\n  .sort((a, b) => b.value - a.value);\n\nd3\n  .treemap()\n  .tile(d3.treemapResquarify)\n  .size([iw, ih])\n  .paddingOuter(6)\n  .paddingTop((d) => (d.depth === 1 ? 30 : 0))\n  .paddingInner(3)\n  .round(true)(root);\n\nconst divisionNodes = root.children;\nconst projectNodes = root.leaves();\n\nfunction relativeLuminance(hex) {\n  const { r, g, b } = d3.rgb(hex);\n  const chan = (v) => {\n    const c = v / 255;\n    return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n  };\n  return 0.2126 * chan(r) + 0.7152 * chan(g) + 0.0722 * chan(b);\n}\nfunction labelColorFor(hex) {\n  return relativeLuminance(hex) > 0.45 ? \"#1A1A17\" : \"#FFFFFF\";\n}\n\n// --- SVG mount ------------------------------------------------------------\nconst svg = d3.select(\"#container\").append(\"svg\").attr(\"width\", width).attr(\"height\", height);\nconst g = svg.append(\"g\").attr(\"transform\", `translate(${margin.left},${margin.top})`);\n\n// --- Division panels (tinted background + header label) -----------------\nconst divisionGroup = g.selectAll(\"g.division\").data(divisionNodes).join(\"g\").attr(\"class\", \"division\");\n\ndivisionGroup\n  .append(\"rect\")\n  .attr(\"x\", (d) => d.x0)\n  .attr(\"y\", (d) => d.y0)\n  .attr(\"width\", (d) => d.x1 - d.x0)\n  .attr(\"height\", (d) => d.y1 - d.y0)\n  .attr(\"fill\", (d) => color(d.data.name))\n  .attr(\"fill-opacity\", 0.12)\n  .attr(\"stroke\", (d) => color(d.data.name))\n  .attr(\"stroke-width\", 1.5);\n\ndivisionGroup\n  .append(\"text\")\n  .attr(\"x\", (d) => d.x0 + 10)\n  .attr(\"y\", (d) => d.y0 + 20)\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"16px\")\n  .style(\"font-weight\", \"600\")\n  .style(\"font-family\", \"system-ui, sans-serif\")\n  .text((d) => d.data.name);\n\n// --- Project tiles (leaves), shaded by rank within their division -------\nconst projectGroup = g.selectAll(\"g.project\").data(projectNodes).join(\"g\").attr(\"class\", \"project\");\n\nprojectGroup.each(function (d) {\n  const siblings = d.parent.children;\n  const rank = siblings.indexOf(d);\n  const baseColor = color(d.parent.data.name);\n  const shaded = d3.color(baseColor).darker(rank * 0.32);\n  d.fill = shaded.formatHex();\n  d.label = labelColorFor(d.fill);\n});\n\nprojectGroup\n  .append(\"rect\")\n  .attr(\"x\", (d) => d.x0)\n  .attr(\"y\", (d) => d.y0)\n  .attr(\"width\", (d) => d.x1 - d.x0)\n  .attr(\"height\", (d) => d.y1 - d.y0)\n  .attr(\"fill\", (d) => d.fill)\n  .attr(\"stroke\", t.pageBg)\n  .attr(\"stroke-width\", 2);\n\nconst labelableProjects = projectGroup.filter((d) => d.x1 - d.x0 > 90 && d.y1 - d.y0 > 34);\n\nlabelableProjects\n  .append(\"text\")\n  .attr(\"x\", (d) => d.x0 + 8)\n  .attr(\"y\", (d) => d.y0 + 20)\n  .attr(\"fill\", (d) => d.label)\n  .style(\"font-size\", \"13px\")\n  .style(\"font-weight\", \"600\")\n  .style(\"font-family\", \"system-ui, sans-serif\")\n  .text((d) => d.data.name);\n\nlabelableProjects\n  .filter((d) => d.y1 - d.y0 > 52)\n  .append(\"text\")\n  .attr(\"x\", (d) => d.x0 + 8)\n  .attr(\"y\", (d) => d.y0 + 38)\n  .attr(\"fill\", (d) => d.label)\n  .attr(\"opacity\", 0.85)\n  .style(\"font-size\", \"12px\")\n  .style(\"font-family\", \"system-ui, sans-serif\")\n  .text((d) => `$${d.data.value}k`);\n\n// --- Title --------------------------------------------------------------\nsvg\n  .append(\"text\")\n  .attr(\"x\", width / 2)\n  .attr(\"y\", 50)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"22px\")\n  .style(\"font-weight\", \"600\")\n  .style(\"font-family\", \"system-ui, sans-serif\")\n  .text(\"treemap-basic · javascript · d3 · anyplot.ai\");\n\nsvg\n  .append(\"text\")\n  .attr(\"x\", width / 2)\n  .attr(\"y\", 82)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.inkSoft)\n  .style(\"font-size\", \"15px\")\n  .style(\"font-family\", \"system-ui, sans-serif\")\n  .text(\"R&D Budget Allocation by Division and Project ($ thousands)\");\n"}