Treemap
Hierarchical rectangle area chart, single-level slice-and-dice layout.
Basic usage
Data comes in via props; rendered as pure SVG with no third-party charting dependency.
Colors come from the --viz-1..8 tokens, colorblind-friendly.
<script setup lang="ts">
import { CfTreemap } from '@chufix-design/vue';
const nodes = [
{ name: 'react-dom', value: 1200 },
{ name: 'react', value: 720 },
{ name: 'lodash', value: 540 },
{ name: 'moment', value: 480 },
{ name: 'rxjs', value: 380 },
{ name: 'd3', value: 320 },
{ name: 'three', value: 280 },
{ name: 'others', value: 200 },
];
</script>
<template>
<CfTreemap :nodes="nodes" />
</template> <script setup>
import { CfTreemap } from '@chufix-design/vue';
const nodes = [
{ name: 'react-dom', value: 1200 },
{ name: 'react', value: 720 },
{ name: 'lodash', value: 540 },
{ name: 'moment', value: 480 },
{ name: 'rxjs', value: 380 },
{ name: 'd3', value: 320 },
{ name: 'three', value: 280 },
{ name: 'others', value: 200 },
];
</script>
<template>
<CfTreemap :nodes="nodes" />
</template> import { CfTreemap } from '@chufix-design/react';
export default function Demo() {
const nodes = [
{ name: 'react-dom', value: 1200 },
{ name: 'react', value: 720 },
{ name: 'lodash', value: 540 },
{ name: 'moment', value: 480 },
{ name: 'rxjs', value: 380 },
{ name: 'd3', value: 320 },
{ name: 'three', value: 280 },
{ name: 'others', value: 200 },
];
return (
<>
<CfTreemap nodes={nodes} />
</>
);
} import { CfTreemap } from '@chufix-design/react';
export default function Demo() {
const nodes = [
{ name: 'react-dom', value: 1200 },
{ name: 'react', value: 720 },
{ name: 'lodash', value: 540 },
{ name: 'moment', value: 480 },
{ name: 'rxjs', value: 380 },
{ name: 'd3', value: 320 },
{ name: 'three', value: 280 },
{ name: 'others', value: 200 },
];
return (
<>
<CfTreemap nodes={nodes} />
</>
);
} Label visibility
showLabels=false shows only color blocks — useful for thumbnail layouts. Text only appears when a rectangle is large enough (w>50, h>20).
<script setup lang="ts">
import { CfTreemap } from '@chufix-design/vue';
const small = [
{ name: '依赖 A', value: 280 },
{ name: '依赖 B', value: 220 },
{ name: '依赖 C', value: 180 },
{ name: '依赖 D', value: 120 },
{ name: '其他', value: 80 },
];
</script>
<template>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
<div>
<div style="font-size: 11px; color: var(--fg-3); margin-bottom: 4px;">5 个节点(label 显示)</div>
<CfTreemap :nodes="small" :height="180" />
</div>
<div>
<div style="font-size: 11px; color: var(--fg-3); margin-bottom: 4px;">label 隐藏</div>
<CfTreemap :nodes="small" :height="180" :show-labels="false" />
</div>
</div>
</template> <script setup>
import { CfTreemap } from '@chufix-design/vue';
const small = [
{ name: '依赖 A', value: 280 },
{ name: '依赖 B', value: 220 },
{ name: '依赖 C', value: 180 },
{ name: '依赖 D', value: 120 },
{ name: '其他', value: 80 },
];
</script>
<template>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
<div>
<div style="font-size: 11px; color: var(--fg-3); margin-bottom: 4px;">5 个节点(label 显示)</div>
<CfTreemap :nodes="small" :height="180" />
</div>
<div>
<div style="font-size: 11px; color: var(--fg-3); margin-bottom: 4px;">label 隐藏</div>
<CfTreemap :nodes="small" :height="180" :show-labels="false" />
</div>
</div>
</template> import { CfTreemap } from '@chufix-design/react';
export default function Demo() {
const small = [
{ name: '依赖 A', value: 280 },
{ name: '依赖 B', value: 220 },
{ name: '依赖 C', value: 180 },
{ name: '依赖 D', value: 120 },
{ name: '其他', value: 80 },
];
return (
<>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
<div>
<div style={{ fontSize: 11, color: "var(--fg-3)", marginBottom: 4 }}>5 个节点(label 显示)</div>
<CfTreemap nodes={small} height={180} />
</div>
<div>
<div style={{ fontSize: 11, color: "var(--fg-3)", marginBottom: 4 }}>label 隐藏</div>
<CfTreemap nodes={small} height={180} showLabels={false} />
</div>
</div>
</>
);
} import { CfTreemap } from '@chufix-design/react';
export default function Demo() {
const small = [
{ name: '依赖 A', value: 280 },
{ name: '依赖 B', value: 220 },
{ name: '依赖 C', value: 180 },
{ name: '依赖 D', value: 120 },
{ name: '其他', value: 80 },
];
return (
<>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
<div>
<div style={{ fontSize: 11, color: "var(--fg-3)", marginBottom: 4 }}>5 个节点(label 显示)</div>
<CfTreemap nodes={small} height={180} />
</div>
<div>
<div style={{ fontSize: 11, color: "var(--fg-3)", marginBottom: 4 }}>label 隐藏</div>
<CfTreemap nodes={small} height={180} showLabels={false} />
</div>
</div>
</>
);
} Nested hierarchy + drill-down
Attach children to any node and the layout recurses with slice-and-dice; parent rectangles reserve headerHeight pixels at the top for their label. Click a top-level rectangle with children to drill in: the subtree becomes the new focus, with a breadcrumb, an ↑ Up button, and a footer tracking the current focus. Pass drillable={false} for a static nested view.
顶层方块直接展示子分类的嵌套排版;单击有子项的方块即可下钻聚焦到该子树。
焦点 全部
<script setup lang="ts">
import { ref } from 'vue';
import { CfTag, CfTreemap } from '@chufix-design/vue';
const nodes = [
{
name: '亚太',
children: [
{ name: '中国', value: 4280 },
{ name: '日本', value: 1820 },
{ name: '东南亚', value: 1240 },
{ name: '澳洲', value: 760 },
],
},
{
name: '欧洲',
children: [
{ name: '英国', value: 1420 },
{ name: '德国', value: 1380 },
{ name: '法国', value: 980 },
{ name: '北欧', value: 820 },
],
},
{
name: '北美',
children: [
{ name: '美国', value: 3920 },
{ name: '加拿大', value: 1080 },
],
},
{
name: '其他',
children: [
{ name: '南美', value: 620 },
{ name: '中东', value: 540 },
{ name: '非洲', value: 380 },
],
},
];
const focus = ref<string[]>([]);
</script>
<template>
<p style="margin: 0 0 8px; color: var(--fg-3); font-size: 12px;">
顶层方块直接展示子分类的嵌套排版;单击有子项的方块即可下钻聚焦到该子树。
</p>
<CfTreemap
:nodes="nodes"
:width="640"
:height="320"
@drill="(p: { pathNames: string[] }) => focus = p.pathNames"
/>
<p style="margin-top: 8px; font-size: 12px;">
<CfTag tone="info" size="sm">焦点</CfTag>
{{ focus.length ? focus.join(' / ') : '全部' }}
</p>
</template> <script setup>
import { ref } from 'vue';
import { CfTag, CfTreemap } from '@chufix-design/vue';
const nodes = [
{
name: '亚太',
children: [
{ name: '中国', value: 4280 },
{ name: '日本', value: 1820 },
{ name: '东南亚', value: 1240 },
{ name: '澳洲', value: 760 },
],
},
{
name: '欧洲',
children: [
{ name: '英国', value: 1420 },
{ name: '德国', value: 1380 },
{ name: '法国', value: 980 },
{ name: '北欧', value: 820 },
],
},
{
name: '北美',
children: [
{ name: '美国', value: 3920 },
{ name: '加拿大', value: 1080 },
],
},
{
name: '其他',
children: [
{ name: '南美', value: 620 },
{ name: '中东', value: 540 },
{ name: '非洲', value: 380 },
],
},
];
const focus = ref<string[]>([]);
</script>
<template>
<p style="margin: 0 0 8px; color: var(--fg-3); font-size: 12px;">
顶层方块直接展示子分类的嵌套排版;单击有子项的方块即可下钻聚焦到该子树。
</p>
<CfTreemap
:nodes="nodes"
:width="640"
:height="320"
@drill="(p: { pathNames: string[] }) => focus = p.pathNames"
/>
<p style="margin-top: 8px; font-size: 12px;">
<CfTag tone="info" size="sm">焦点</CfTag>
{{ focus.length ? focus.join(' / ') : '全部' }}
</p>
</template> import { useState } from 'react';
import { CfTag, CfTreemap } from '@chufix-design/react';
export default function Demo() {
const nodes = [
{
name: '亚太',
children: [
{ name: '中国', value: 4280 },
{ name: '日本', value: 1820 },
{ name: '东南亚', value: 1240 },
{ name: '澳洲', value: 760 },
],
},
{
name: '欧洲',
children: [
{ name: '英国', value: 1420 },
{ name: '德国', value: 1380 },
{ name: '法国', value: 980 },
{ name: '北欧', value: 820 },
],
},
{
name: '北美',
children: [
{ name: '美国', value: 3920 },
{ name: '加拿大', value: 1080 },
],
},
{
name: '其他',
children: [
{ name: '南美', value: 620 },
{ name: '中东', value: 540 },
{ name: '非洲', value: 380 },
],
},
];
const [focus, setFocus] = useState<string[]>([]);
return (
<>
<p style={{ margin: "0 0 8px", color: "var(--fg-3)", fontSize: 12 }}>
顶层方块直接展示子分类的嵌套排版;单击有子项的方块即可下钻聚焦到该子树。
</p>
<CfTreemap nodes={nodes} width={640} height={320} onDrill={(p: { pathNames: string[] }) => setFocus(p.pathNames)}
/>
<p style={{ marginTop: 8, fontSize: 12 }}>
<CfTag tone="info" size="sm">焦点</CfTag>
{focus.length ? focus.join(' / ') : '全部'}
</p>
</>
);
} import { useState } from 'react';
import { CfTag, CfTreemap } from '@chufix-design/react';
export default function Demo() {
const nodes = [
{
name: '亚太',
children: [
{ name: '中国', value: 4280 },
{ name: '日本', value: 1820 },
{ name: '东南亚', value: 1240 },
{ name: '澳洲', value: 760 },
],
},
{
name: '欧洲',
children: [
{ name: '英国', value: 1420 },
{ name: '德国', value: 1380 },
{ name: '法国', value: 980 },
{ name: '北欧', value: 820 },
],
},
{
name: '北美',
children: [
{ name: '美国', value: 3920 },
{ name: '加拿大', value: 1080 },
],
},
{
name: '其他',
children: [
{ name: '南美', value: 620 },
{ name: '中东', value: 540 },
{ name: '非洲', value: 380 },
],
},
];
const [focus, setFocus] = useState<string[]>([]);
return (
<>
<p style={{ margin: "0 0 8px", color: "var(--fg-3)", fontSize: 12 }}>
顶层方块直接展示子分类的嵌套排版;单击有子项的方块即可下钻聚焦到该子树。
</p>
<CfTreemap nodes={nodes} width={640} height={320} onDrill={(p: { pathNames: string[] }) => setFocus(p.pathNames)}
/>
<p style={{ marginTop: 8, fontSize: 12 }}>
<CfTag tone="info" size="sm">焦点</CfTag>
{focus.length ? focus.join(' / ') : '全部'}
</p>
</>
);
} API
| Prop | Type | Default | Description |
|---|---|---|---|
nodes | TreemapNode[] | — | { name, value?, colorIndex?, children? }[] |
width / height | number | 480 / 240 | |
childPadding | number | 4 | Inner padding around children inside a parent |
headerHeight | number | 16 | Space reserved at the top of a parent for its label |
drillable | boolean | true | Click a top-level rect with children to drill in |
showBreadcrumb | boolean | true | Render breadcrumb + ↑ Up control when drilled |
反馈与讨论
Treemap · Discussion