You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
treemap: bounds check throws on floating-point overshoot from d3 squarify (and on paddingInner collapse) #243
treemap() throws TypeError: treemap: layout produced out-of-bounds coordinates for node "…" for ordinary data at some chart sizes, so the whole chart fails to render.
assertLayoutCoordinates in packages/charts-core/src/hierarchy-treemap.ts compares each leaf's x1/y1 with the plot width and height exactly. d3's squarify adds tile sizes in floating point, so the last tile in a row can end about 1e-13 px past the edge. That trips the check.
Reproduction
The same layout that treemap() runs, with d3-hierarchy only:
import{hierarchy,treemap,treemapSquarify}from'd3-hierarchy';constwidth=361;constheight=300;constroot=hierarchy({children: [50,30,20,10,5,1].map((value)=>({ value })),}).sum((d)=>d.value??0);treemap().size([width,height]).tile(treemapSquarify)(root);constleaf=root.leaves().find((n)=>n.x1>width);console.log(leaf.x1-width);// 5.684341886080802e-14
A TanStack treemap with these values and a 361 × 300 plot area gets the same coordinates and throws. We hit it in a real app at normal container widths. A sweep over widths 300–900 px finds a failing width for each data set we tried, for example [7, 5, 3, 2, 1] at 593 × 300 and [90, 7, 5, 4, 2, 1] at 804 × 300.
A second case: paddingInner
With paddingInner, d3 collapses a tile that is thinner than the padding to its midpoint, and that point can be outside the plot area. For example, values [1000, 1], 600 × 300, paddingInner: 3: the small tile gets x0 = x1 = 601.2, so the check throws. Zero-area cells are already filtered out right after the check, so these tiles would otherwise be dropped harmlessly.
Expected behavior
A floating-point overshoot does not throw. For example, clamp each leaf to the plot area, or compare with a small tolerance. A tile that collapsed outside the plot area is dropped, not reported as an error.
Workaround
A custom method that runs squarify and then clamps each child to its parent's box:
Thanks @quinnj, the reproduction cases made both causes clear. The fix is merged in #244 and queued for release, but it is not on npm yet.
AI review notes:
Regression tests cover all four reported cases, including the padded tile collapse, and still reject non-finite or materially out-of-bounds custom layouts. All 15 focused tests, full local validation, and the applicable remote CI checks passed on the merged candidate.
The change tolerates machine-scale rounding, clamps those accepted bounds, and lets the existing filter omit empty cells. The Changeset will be included in the pending release.
Activity
tannerlinsley commentedon Oct 23, 2026
Thanks @quinnj, the reproduction cases made both causes clear. The fix is merged in #244 and queued for release, but it is not on npm yet.