You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3.js可缩放树形图(Treemap)内部矩形尺寸异常问题求助

Looks like I found the issue with your treemap's sizing problem—the culprit is how your position function handles scale calculations, especially when navigating into child levels like "Maxillopoda". Let's break this down and fix it:

The Root Cause

Your x and y scales aren’t being updated to match the current root node’s coordinate bounds when you zoom into a subgroup. Right now, you’re likely using a global scale (mapped to the full treemap’s 0-1 domain) to calculate child node sizes. This skews proportions once you’re in a sub-level: even though "Halopitilus" has a value of 1, its relative width within its parent’s local bounds gets inflated when using the global scale, leading to the oversized rectangle.

Fix Steps & Revised Code

Here’s how to adjust your code to align visual sizes with node values:

  1. Update scales dynamically when zooming
    Every time you switch to a new root (e.g., clicking into "Maxillopoda"), redefine your x and y scales to use the current root’s x0/x1 and y0/y1 as their domain. This ensures all child node calculations are relative to their parent’s bounds, not the entire treemap.

  2. Fix header and child node positioning
    Your original translate(0,-30) pushed the root header off the canvas, and child nodes didn’t account for the header’s height offset.

Revised Zoom/Update Function

function zoomTo(root) {
  // Calculate available space for treemap content (excluding the 30px header)
  const contentWidth = width;
  const contentHeight = height - 30;

  // Create scales tied to the current root's coordinate range
  const x = d3.scaleLinear()
    .domain([root.x0, root.x1])
    .range([0, contentWidth]);

  const y = d3.scaleLinear()
    .domain([root.y0, root.y1])
    .range([0, contentHeight]);

  // Pass updated scales to the position function
  position(group, root, x, y);
}

Updated Position Function

function position(group, root, x, y) {
  group.selectAll("g")
    .attr("transform", d => {
      if (d === root) {
        // Position root header at the top of the canvas
        return `translate(0, 0)`;
      } else {
        // Position child nodes below the header using dynamic scales
        return `translate(${x(d.x0)}, ${y(d.y0) + 30})`;
      }
    })
    .select("rect")
    .attr("width", d => d === root ? width : x(d.x1) - x(d.x0))
    .attr("height", d => d === root ? 30 : y(d.y1) - y(d.y0));
}

Quick Additional Check

Ensure your treemap layout uses d3.treemap().sum(d => d.value)—this guarantees the sizing logic is correctly tied to your nodes’ numerical values from the start.

By tying scales to the current root’s bounds, each child node’s width/height is calculated as a proportion of its parent’s available space, which aligns visual size with actual value. The header positioning fixes the offset so all elements stay within the canvas, and the content area scales correctly.

内容的提问来源于stack exchange,提问作者Herlock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 23:42:50