Skip to content

Commit ae64619

Browse files
authored
Fix Treemap reactivity regression (#516)
* fix(Treemap): Fix reactivity of props (tile, padding, etc) and remove `selected` prop * fix(Treemap): Add `maintainAspectRatio` (default: false) to opt into tiling function adjustment (primarily for zoom) * Fix headings * Fix CI * fix(Treemap): Fix `padding*` prop types to support function or number constant * docs(Treemap): Fix display of nodes on treemap example (referential equality) * docs(Treemap): Fix zoomable examples
1 parent f8b8287 commit ae64619

9 files changed

Lines changed: 342 additions & 48 deletions

File tree

.changeset/cruel-cameras-begin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'layerchart': patch
3+
---
4+
5+
breaking(Treemap): Remove `selected` prop

.changeset/early-peaches-accept.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'layerchart': patch
3+
---
4+
5+
fix(Treemap): Add `maintainAspectRatio` (default: false) to opt into tiling function adjustment (primarily for zoom)

.changeset/modern-nails-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'layerchart': patch
3+
---
4+
5+
fix(Treemap): Fix reactivity of props (tile, padding, etc)

.changeset/spotty-rules-taste.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'layerchart': patch
3+
---
4+
5+
fix(Treemap): Fix `padding*` prop types to support function or number constant

packages/layerchart/src/lib/components/Treemap.svelte

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,53 +18,53 @@
1818
*
1919
* @default 0
2020
*/
21-
padding?: number;
21+
padding?: number | ((node: HierarchyRectangularNode<T>) => number);
2222
2323
/**
2424
* The inner padding between nodes.
2525
*
2626
* @default 0
2727
*/
28-
paddingInner?: number;
28+
paddingInner?: number | ((node: HierarchyRectangularNode<T>) => number);
2929
3030
/**
3131
* The outer padding between nodes.
3232
*
3333
* @default 0
3434
*/
35-
paddingOuter?: number;
35+
paddingOuter?: number | ((node: HierarchyRectangularNode<T>) => number);
3636
3737
/**
3838
* The top padding between nodes.
3939
*
4040
* @default 0
4141
*/
42-
paddingTop?: number;
42+
paddingTop?: number | ((node: HierarchyRectangularNode<T>) => number);
4343
4444
/**
4545
* The bottom padding between nodes.
4646
*
4747
* @default 0
4848
*/
49-
paddingBottom?: number;
49+
paddingBottom?: number | ((node: HierarchyRectangularNode<T>) => number);
5050
/**
5151
* The left padding between nodes.
5252
*
5353
*/
54-
paddingLeft?: number;
54+
paddingLeft?: number | ((node: HierarchyRectangularNode<T>) => number);
5555
5656
/**
5757
* The right padding between nodes.
5858
*
5959
*/
60-
paddingRight?: number;
60+
paddingRight?: number | ((node: HierarchyRectangularNode<T>) => number);
6161
6262
/**
63-
* The selected node.
63+
* Modify tiling function for approapriate aspect ratio when treemap is zoomed in
6464
*
65-
* @default null
65+
* @default false
6666
*/
67-
selected?: HierarchyRectangularNode<T> | null;
67+
maintainAspectRatio?: boolean;
6868
6969
hierarchy?: HierarchyNode<T>;
7070
@@ -99,7 +99,7 @@
9999
paddingBottom = 0,
100100
paddingLeft,
101101
paddingRight,
102-
selected = $bindable(null),
102+
maintainAspectRatio = false,
103103
children,
104104
}: TreemapProps<T> = $props();
105105
@@ -121,45 +121,82 @@
121121
: tile
122122
);
123123
124-
const treemap = $derived.by(() => {
124+
const treemapData = $derived.by(() => {
125125
const _treemap = d3treemap<T>()
126126
.size([ctx.width, ctx.height])
127-
.tile(aspectTile(tileFunc, ctx.width, ctx.height));
127+
.tile(maintainAspectRatio ? aspectTile(tileFunc, ctx.width, ctx.height) : tileFunc);
128128
129129
if (padding) {
130-
_treemap.padding(padding);
130+
// Make Typescript happy to pick the correct overload
131+
// TODO: Better way to do this?
132+
if (typeof padding === 'number') {
133+
_treemap.padding(padding);
134+
} else {
135+
_treemap.padding(padding);
136+
}
131137
}
132138
133139
if (paddingInner) {
134-
_treemap.paddingInner(paddingInner);
140+
if (typeof paddingInner === 'number') {
141+
_treemap.paddingInner(typeof paddingInner === 'number' ? paddingInner : paddingInner);
142+
} else {
143+
_treemap.paddingInner(paddingInner);
144+
}
135145
}
136146
137147
if (paddingOuter) {
138-
_treemap.paddingOuter(paddingOuter);
148+
if (typeof paddingOuter === 'number') {
149+
_treemap.paddingOuter(paddingOuter);
150+
} else {
151+
_treemap.paddingOuter(paddingOuter);
152+
}
139153
}
140154
141155
if (paddingTop) {
142-
_treemap.paddingTop(paddingTop);
156+
if (typeof paddingTop === 'number') {
157+
_treemap.paddingTop(paddingTop);
158+
} else {
159+
_treemap.paddingTop(paddingTop);
160+
}
143161
}
144162
145163
if (paddingBottom) {
146-
_treemap.paddingBottom(paddingBottom);
164+
if (typeof paddingBottom === 'number') {
165+
_treemap.paddingBottom(paddingBottom);
166+
} else {
167+
_treemap.paddingBottom(paddingBottom);
168+
}
147169
}
148170
149171
if (paddingLeft) {
150-
_treemap.paddingLeft(paddingLeft);
172+
if (typeof paddingLeft === 'number') {
173+
_treemap.paddingLeft(paddingLeft);
174+
} else {
175+
_treemap.paddingLeft(paddingLeft);
176+
}
151177
}
152178
if (paddingRight) {
153-
_treemap.paddingRight(paddingRight);
179+
if (typeof paddingRight === 'number') {
180+
_treemap.paddingRight(paddingRight);
181+
} else {
182+
_treemap.paddingRight(paddingRight);
183+
}
154184
}
155-
return _treemap;
156-
});
157185
158-
const treemapData = $derived(hierarchy ? treemap(hierarchy) : null);
186+
if (hierarchy) {
187+
const h = hierarchy.copy();
188+
const treemapData = _treemap(h);
189+
return {
190+
links: treemapData.links(),
191+
nodes: treemapData.descendants(),
192+
};
193+
}
159194
160-
$effect.pre(() => {
161-
selected = treemapData;
195+
return {
196+
links: [],
197+
nodes: [],
198+
};
162199
});
163200
</script>
164201

165-
{@render children?.({ nodes: treemapData ? treemapData.descendants() : [] })}
202+
{@render children?.({ nodes: treemapData.nodes })}

packages/layerchart/src/lib/utils/treemap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function aspectTile(tile: TileFunc, width: number, height: number): TileF
2828
/**
2929
* Show if the node (a) is a child of the selected (b), or any parent above selected
3030
*/
31-
export function isNodeVisible(a: HierarchyNode<any>, b: HierarchyNode<any> | null) {
31+
export function isNodeVisible(a: HierarchyNode<any>, b: HierarchyNode<any> | null | undefined) {
3232
while (b) {
3333
if (a.parent === b) return true;
3434
b = b.parent;

0 commit comments

Comments
 (0)