{"id":"5831f55fccfa1c41","slug":"zoomable-circle-packing","first_public_version":185,"paused_version":null,"likes":350,"publish_level":"live","forks":657,"fork_of":{"id":"0edfeb766ced5a8c","slug":"pack-component","title":"Circle packing component","owner":{"id":"863951e3ebe4c0ae","avatar_url":"https://avatars.observableusercontent.com/avatar/5af16e327a90b2873351dda8a596c0d2d3bf954f64523deefe80177c9764d0f7","login":"d3","name":"D3","bio":"Bring your data to life.","home_url":"https://d3js.org","type":"team","tier":"pro_2024"},"version":98},"has_importers":true,"thumbnail":"b7cc8cf4a59de5ccd08c47284bd20de50d3cc20fe29d9f76caaef1a2b661abae","default_thumbnail":"b7cc8cf4a59de5ccd08c47284bd20de50d3cc20fe29d9f76caaef1a2b661abae","update_time":"2020-07-15T21:59:28.355Z","publish_time":"2023-07-18T13:30:14.830Z","publish_version":187,"latest_version":187,"roles":[],"sharing":null,"owner":{"id":"863951e3ebe4c0ae","avatar_url":"https://avatars.observableusercontent.com/avatar/5af16e327a90b2873351dda8a596c0d2d3bf954f64523deefe80177c9764d0f7","login":"d3","name":"D3","bio":"Bring your data to life.","home_url":"https://d3js.org","type":"team","tier":"pro_2024"},"creator":{"id":"074c414ad1d825f5","avatar_url":"https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519","login":"mbostock","name":"Mike Bostock","bio":"Visualization toolmaker. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.","home_url":"https://bost.ocks.org/mike/","tier":"pro"},"authors":[{"id":"074c414ad1d825f5","avatar_url":"https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519","name":"Mike Bostock","login":"mbostock","bio":"Visualization toolmaker. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.","home_url":"https://bost.ocks.org/mike/","tier":"pro","approved":true,"description":""}],"files":[{"id":"e65374209781891f37dea1e7a6e1c5e020a3009b8aedf113b4c80942018887a1176ad4945cf14444603ff91d3da371b3b0d72419fa8d2ee0f6e815732475d5de","url":"https://static.observableusercontent.com/files/e65374209781891f37dea1e7a6e1c5e020a3009b8aedf113b4c80942018887a1176ad4945cf14444603ff91d3da371b3b0d72419fa8d2ee0f6e815732475d5de","download_url":"https://static.observableusercontent.com/files/e65374209781891f37dea1e7a6e1c5e020a3009b8aedf113b4c80942018887a1176ad4945cf14444603ff91d3da371b3b0d72419fa8d2ee0f6e815732475d5de?response-content-disposition=attachment%3Bfilename*%3DUTF-8%27%27flare-2.json","name":"flare-2.json","create_time":"2019-10-29T23:58:41.592Z","mime_type":"application/json","status":"public","size":11634,"content_encoding":"gzip","private_bucket_id":null}],"comments":[],"commenting_lock":null,"suggestions_to":[],"suggestion_from":null,"collections":[{"id":"d9df4fb5263ace62","type":"public","slug":"visualization","title":"Visualization","description":"Explore and explain patterns in quantitative data using D3, Vega, and Observable Plot","update_time":"2023-07-19T17:50:40.230Z","pinned":true,"ordered":true,"custom_thumbnail":"09e385d95ce7df7d392b0133d68e97dd5675378190775d038d21516ea62178ba","default_thumbnail":"32ad600cf556f7b9991b2a11f7b6b8e55abe7ada6062ef88a5a7de422bb261ab","thumbnail":"09e385d95ce7df7d392b0133d68e97dd5675378190775d038d21516ea62178ba","listing_count":84,"parent_collection_count":1,"owner":{"id":"f35c755083683fe5","avatar_url":"https://avatars.observableusercontent.com/avatar/424c6c1f7794371c9915a160519bdfb34cf34e50069fcd6def38a1a04d4e9702","login":"observablehq","name":"Observable","bio":"The end-to-end solution for building and hosting better data apps, dashboards, and reports.","home_url":"https://observablehq.com","type":"team","tier":"enterprise_2024"}},{"id":"1b0fbc3b1939d7fa","type":"public","slug":"gallery","title":"Gallery","description":"Examples featured in the D3 gallery","update_time":"2023-04-10T02:28:10.124Z","pinned":false,"ordered":false,"custom_thumbnail":null,"default_thumbnail":"6953adf7aec9d29339751fa68d9c9dc67169a0ffd7469f9a4055eda920bdd2a4","thumbnail":"6953adf7aec9d29339751fa68d9c9dc67169a0ffd7469f9a4055eda920bdd2a4","listing_count":147,"parent_collection_count":0,"owner":{"id":"863951e3ebe4c0ae","avatar_url":"https://avatars.observableusercontent.com/avatar/5af16e327a90b2873351dda8a596c0d2d3bf954f64523deefe80177c9764d0f7","login":"d3","name":"D3","bio":"Bring your data to life.","home_url":"https://d3js.org","type":"team","tier":"pro_2024"}},{"id":"aa8e262f42c95c83","type":"public","slug":"product-page","title":"Product page","description":"Notebooks to display on the product page","update_time":"2021-10-15T15:03:26.270Z","pinned":false,"ordered":false,"custom_thumbnail":null,"default_thumbnail":"2000d58a53de52a26198face6a9361b9304027249ee374d6e0275cf57c412b06","thumbnail":"2000d58a53de52a26198face6a9361b9304027249ee374d6e0275cf57c412b06","listing_count":15,"parent_collection_count":0,"owner":{"id":"f35c755083683fe5","avatar_url":"https://avatars.observableusercontent.com/avatar/424c6c1f7794371c9915a160519bdfb34cf34e50069fcd6def38a1a04d4e9702","login":"observablehq","name":"Observable","bio":"The end-to-end solution for building and hosting better data apps, dashboards, and reports.","home_url":"https://observablehq.com","type":"team","tier":"enterprise_2024"}},{"id":"ac3c6ed33ef3345f","type":"public","slug":"d3-hierarchy","title":"d3-hierarchy","description":"2D layout algorithms for visualizing hierarchical data.","update_time":"2019-03-07T07:26:12.604Z","pinned":true,"ordered":false,"custom_thumbnail":null,"default_thumbnail":"d1bb6653143239319cfee07a6f362c108ad0ddc9e7c064ebf185364992c2426c","thumbnail":"d1bb6653143239319cfee07a6f362c108ad0ddc9e7c064ebf185364992c2426c","listing_count":35,"parent_collection_count":1,"owner":{"id":"863951e3ebe4c0ae","avatar_url":"https://avatars.observableusercontent.com/avatar/5af16e327a90b2873351dda8a596c0d2d3bf954f64523deefe80177c9764d0f7","login":"d3","name":"D3","bio":"Bring your data to life.","home_url":"https://d3js.org","type":"team","tier":"pro_2024"}}],"version":161,"title":"Zoomable Circle Packing","license":"isc","copyright":"Copyright 2018–2020 Observable, Inc.","nodes":[{"id":0,"value":"md`# Zoomable Circle Packing\n\nClick to zoom in or out.`","pinned":false,"mode":"js","data":null,"name":null},{"id":9,"value":"chart = {\n  const root = pack(data);\n  let focus = root;\n  let view;\n\n  const svg = d3.create(\"svg\")\n      .attr(\"viewBox\", `-${width / 2} -${height / 2} ${width} ${height}`)\n      .style(\"display\", \"block\")\n      .style(\"margin\", \"0 -14px\")\n      .style(\"background\", color(0))\n      .style(\"cursor\", \"pointer\")\n      .on(\"click\", () => zoom(root));\n\n  const node = svg.append(\"g\")\n    .selectAll(\"circle\")\n    .data(root.descendants().slice(1))\n    .join(\"circle\")\n      .attr(\"fill\", d => d.children ? color(d.depth) : \"white\")\n      .attr(\"pointer-events\", d => !d.children ? \"none\" : null)\n      .on(\"mouseover\", function() { d3.select(this).attr(\"stroke\", \"#000\"); })\n      .on(\"mouseout\", function() { d3.select(this).attr(\"stroke\", null); })\n      .on(\"click\", d => focus !== d && (zoom(d), d3.event.stopPropagation()));\n\n  const label = svg.append(\"g\")\n      .style(\"font\", \"10px sans-serif\")\n      .attr(\"pointer-events\", \"none\")\n      .attr(\"text-anchor\", \"middle\")\n    .selectAll(\"text\")\n    .data(root.descendants())\n    .join(\"text\")\n      .style(\"fill-opacity\", d => d.parent === root ? 1 : 0)\n      .style(\"display\", d => d.parent === root ? \"inline\" : \"none\")\n      .text(d => d.data.name);\n\n  zoomTo([root.x, root.y, root.r * 2]);\n\n  function zoomTo(v) {\n    const k = width / v[2];\n\n    view = v;\n\n    label.attr(\"transform\", d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`);\n    node.attr(\"transform\", d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`);\n    node.attr(\"r\", d => d.r * k);\n  }\n\n  function zoom(d) {\n    const focus0 = focus;\n\n    focus = d;\n\n    const transition = svg.transition()\n        .duration(d3.event.altKey ? 7500 : 750)\n        .tween(\"zoom\", d => {\n          const i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2]);\n          return t => zoomTo(i(t));\n        });\n\n    label\n      .filter(function(d) { return d.parent === focus || this.style.display === \"inline\"; })\n      .transition(transition)\n        .style(\"fill-opacity\", d => d.parent === focus ? 1 : 0)\n        .on(\"start\", function(d) { if (d.parent === focus) this.style.display = \"inline\"; })\n        .on(\"end\", function(d) { if (d.parent !== focus) this.style.display = \"none\"; });\n  }\n\n  return svg.node();\n}","pinned":true,"mode":"js","data":null,"name":null},{"id":3,"value":"data = FileAttachment(\"flare-2.json\").json()","pinned":true,"mode":"js","data":null,"name":null},{"id":84,"value":"pack = data => d3.pack()\n    .size([width, height])\n    .padding(3)\n  (d3.hierarchy(data)\n    .sum(d => d.value)\n    .sort((a, b) => b.value - a.value))","pinned":true,"mode":"js","data":null,"name":null},{"id":80,"value":"width = 932","pinned":true,"mode":"js","data":null,"name":null},{"id":82,"value":"height = width","pinned":true,"mode":"js","data":null,"name":null},{"id":41,"value":"format = d3.format(\",d\")","pinned":true,"mode":"js","data":null,"name":null},{"id":45,"value":"color = d3.scaleLinear()\n    .domain([0, 5])\n    .range([\"hsl(152,80%,80%)\", \"hsl(228,30%,40%)\"])\n    .interpolate(d3.interpolateHcl)","pinned":true,"mode":"js","data":null,"name":null},{"id":6,"value":"d3 = require(\"d3@5\")","pinned":true,"mode":"js","data":null,"name":null}],"resolutions":[],"schedule":null,"last_view_time":null}