FunnelChart 漏斗图
逐层收窄的转化漏斗,每层显示绝对值。
基础用法
数据通过 props 传入,纯 SVG 渲染,无第三方图表库依赖。
配色取自 --viz-1..8 token,色盲友好。
背景 视口
<script setup lang="ts">
import { CfFunnelChart } from '@chufix-design/vue';
const steps = [
{ label: '访问', value: 10000 },
{ label: '注册', value: 3200 },
{ label: '激活', value: 1800 },
{ label: '付费', value: 580 },
{ label: '续订', value: 410 },
];
</script>
<template>
<CfFunnelChart :steps="steps" />
</template> <script setup>
import { CfFunnelChart } from '@chufix-design/vue';
const steps = [
{ label: '访问', value: 10000 },
{ label: '注册', value: 3200 },
{ label: '激活', value: 1800 },
{ label: '付费', value: 580 },
{ label: '续订', value: 410 },
];
</script>
<template>
<CfFunnelChart :steps="steps" />
</template> import { CfFunnelChart } from '@chufix-design/react';
export default function Demo() {
const steps = [
{ label: '访问', value: 10000 },
{ label: '注册', value: 3200 },
{ label: '激活', value: 1800 },
{ label: '付费', value: 580 },
{ label: '续订', value: 410 },
];
return (
<>
<CfFunnelChart steps={steps} />
</>
);
} import { CfFunnelChart } from '@chufix-design/react';
export default function Demo() {
const steps = [
{ label: '访问', value: 10000 },
{ label: '注册', value: 3200 },
{ label: '激活', value: 1800 },
{ label: '付费', value: 580 },
{ label: '续订', value: 410 },
];
return (
<>
<CfFunnelChart steps={steps} />
</>
);
} 好坏漏斗对比
健康漏斗(每段流失 30-50%)vs 流失严重漏斗(92% 直接流失)。
背景 视口
健康漏斗(12% 付费)
流失严重(0.4% 付费)
<script setup lang="ts">
import { CfFunnelChart } from '@chufix-design/vue';
const goodConversion = [
{ label: '访问 100k', value: 100000 },
{ label: '注册 50k', value: 50000 },
{ label: '激活 35k', value: 35000 },
{ label: '付费 12k', value: 12000 },
];
const badConversion = [
{ label: '访问 100k', value: 100000 },
{ label: '注册 8k', value: 8000 },
{ label: '激活 3k', value: 3000 },
{ label: '付费 400', value: 400 },
];
</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;">健康漏斗(12% 付费)</div>
<CfFunnelChart :steps="goodConversion" :height="200" />
</div>
<div>
<div style="font-size: 11px; color: var(--fg-3); margin-bottom: 4px;">流失严重(0.4% 付费)</div>
<CfFunnelChart :steps="badConversion" :height="200" />
</div>
</div>
</template> <script setup>
import { CfFunnelChart } from '@chufix-design/vue';
const goodConversion = [
{ label: '访问 100k', value: 100000 },
{ label: '注册 50k', value: 50000 },
{ label: '激活 35k', value: 35000 },
{ label: '付费 12k', value: 12000 },
];
const badConversion = [
{ label: '访问 100k', value: 100000 },
{ label: '注册 8k', value: 8000 },
{ label: '激活 3k', value: 3000 },
{ label: '付费 400', value: 400 },
];
</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;">健康漏斗(12% 付费)</div>
<CfFunnelChart :steps="goodConversion" :height="200" />
</div>
<div>
<div style="font-size: 11px; color: var(--fg-3); margin-bottom: 4px;">流失严重(0.4% 付费)</div>
<CfFunnelChart :steps="badConversion" :height="200" />
</div>
</div>
</template> import { CfFunnelChart } from '@chufix-design/react';
export default function Demo() {
const goodConversion = [
{ label: '访问 100k', value: 100000 },
{ label: '注册 50k', value: 50000 },
{ label: '激活 35k', value: 35000 },
{ label: '付费 12k', value: 12000 },
];
const badConversion = [
{ label: '访问 100k', value: 100000 },
{ label: '注册 8k', value: 8000 },
{ label: '激活 3k', value: 3000 },
{ label: '付费 400', value: 400 },
];
return (
<>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
<div>
<div style={{ fontSize: 11, color: "var(--fg-3)", marginBottom: 4 }}>健康漏斗(12% 付费)</div>
<CfFunnelChart steps={goodConversion} height={200} />
</div>
<div>
<div style={{ fontSize: 11, color: "var(--fg-3)", marginBottom: 4 }}>流失严重(0.4% 付费)</div>
<CfFunnelChart steps={badConversion} height={200} />
</div>
</div>
</>
);
} import { CfFunnelChart } from '@chufix-design/react';
export default function Demo() {
const goodConversion = [
{ label: '访问 100k', value: 100000 },
{ label: '注册 50k', value: 50000 },
{ label: '激活 35k', value: 35000 },
{ label: '付费 12k', value: 12000 },
];
const badConversion = [
{ label: '访问 100k', value: 100000 },
{ label: '注册 8k', value: 8000 },
{ label: '激活 3k', value: 3000 },
{ label: '付费 400', value: 400 },
];
return (
<>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
<div>
<div style={{ fontSize: 11, color: "var(--fg-3)", marginBottom: 4 }}>健康漏斗(12% 付费)</div>
<CfFunnelChart steps={goodConversion} height={200} />
</div>
<div>
<div style={{ fontSize: 11, color: "var(--fg-3)", marginBottom: 4 }}>流失严重(0.4% 付费)</div>
<CfFunnelChart steps={badConversion} height={200} />
</div>
</div>
</>
);
} API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
steps | FunnelStep[] | — | { label, value }[],从上到下值递减 |
width | number | 360 | SVG 宽度 |
height | number | 240 | SVG 高度 |
showLabels | boolean | true | 显示每段的 label / value |
ariaLabel | string | — | 透传给根 <svg> 的 aria-label |
Events
| Vue 事件 | React 回调 | 载荷类型 | 说明 |
|---|---|---|---|
item-enter | onItemEnter | FunnelChartInteractionPayload | 鼠标进入某层时触发 |
item-leave | onItemLeave | FunnelChartInteractionPayload | 鼠标离开某层时触发 |
类型
interface FunnelChartInteractionPayload {
step: FunnelStep;
dataIndex: number;
nativeEvent?: PointerEvent;
}
反馈与讨论
FunnelChart 漏斗图 的讨论