@beppla/tapas-ui 1.4.30 → 1.4.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/commonjs/PieChart/BACKWARD_COMPATIBILITY.md +157 -0
  2. package/commonjs/PieChart/BUGFIX_EMPTY_DATA.md +86 -0
  3. package/commonjs/PieChart/GroupedLegend.js +240 -0
  4. package/commonjs/PieChart/GroupedLegend.js.map +1 -0
  5. package/commonjs/PieChart/IMPLEMENTATION_SUMMARY.md +306 -0
  6. package/commonjs/PieChart/NestedPieChart.README.md +421 -0
  7. package/commonjs/PieChart/NestedPieChart.js +567 -0
  8. package/commonjs/PieChart/NestedPieChart.js.map +1 -0
  9. package/commonjs/PieChart/NestedPieChart.types.js +2 -0
  10. package/commonjs/PieChart/NestedPieChart.types.js.map +1 -0
  11. package/commonjs/PieChart/NestedPieChart.utils.js +360 -0
  12. package/commonjs/PieChart/NestedPieChart.utils.js.map +1 -0
  13. package/commonjs/PieChart/index.js +8 -0
  14. package/commonjs/PieChart/index.js.map +1 -1
  15. package/module/PieChart/BACKWARD_COMPATIBILITY.md +157 -0
  16. package/module/PieChart/BUGFIX_EMPTY_DATA.md +86 -0
  17. package/module/PieChart/GroupedLegend.js +234 -0
  18. package/module/PieChart/GroupedLegend.js.map +1 -0
  19. package/module/PieChart/IMPLEMENTATION_SUMMARY.md +306 -0
  20. package/module/PieChart/NestedPieChart.README.md +421 -0
  21. package/module/PieChart/NestedPieChart.js +563 -0
  22. package/module/PieChart/NestedPieChart.js.map +1 -0
  23. package/module/PieChart/NestedPieChart.types.js +2 -0
  24. package/module/PieChart/NestedPieChart.types.js.map +1 -0
  25. package/module/PieChart/NestedPieChart.utils.js +343 -0
  26. package/module/PieChart/NestedPieChart.utils.js.map +1 -0
  27. package/module/PieChart/index.js +1 -0
  28. package/module/PieChart/index.js.map +1 -1
  29. package/package.json +1 -1
  30. package/typescript/PieChart/GroupedLegend.d.ts +26 -0
  31. package/typescript/PieChart/GroupedLegend.d.ts.map +1 -0
  32. package/typescript/PieChart/NestedPieChart.d.ts +12 -0
  33. package/typescript/PieChart/NestedPieChart.d.ts.map +1 -0
  34. package/typescript/PieChart/NestedPieChart.types.d.ts +117 -0
  35. package/typescript/PieChart/NestedPieChart.types.d.ts.map +1 -0
  36. package/typescript/PieChart/NestedPieChart.utils.d.ts +57 -0
  37. package/typescript/PieChart/NestedPieChart.utils.d.ts.map +1 -0
  38. package/typescript/PieChart/index.d.ts +2 -0
  39. package/typescript/PieChart/index.d.ts.map +1 -1
@@ -0,0 +1,421 @@
1
+ # NestedPieChart (多层级饼图)
2
+
3
+ 多层级饼图组件,支持双层嵌套、分组图例、交互高亮等功能。专为 Store insights / Summary 等场景设计。
4
+
5
+ ## 特性
6
+
7
+ ### 核心功能
8
+
9
+ - ✅ **多层级支持**:支持 2 层嵌套(外层大类 + 内层子类),可扩展到 N 层
10
+ - ✅ **树形数据结构**:支持 `tree` 和 `flat` 两种数据输入格式
11
+ - ✅ **智能配色**:
12
+ - 大类固定基色(可自定义 mapping)
13
+ - 子类自动生成同色系渐变色
14
+ - 保证相邻颜色可辨识(可配置最小色差)
15
+ - ✅ **分组图例**:
16
+ - 按大类分组显示
17
+ - 支持折叠/展开(可配置默认状态)
18
+ - 显示分组小计和子项明细
19
+ - 可配置排序策略(按值、按标签、保持原序)
20
+ - ✅ **交互高亮**:
21
+ - Hover 扇区高亮对应图例项
22
+ - Hover 图例项高亮对应扇区
23
+ - 点击事件支持(扇区和图例)
24
+ - ✅ **数据筛选**:点击图例可隐藏/显示对应扇区(可选)
25
+ - ✅ **自定义 Tooltip**:支持自定义渲染和格式化
26
+ - ✅ **数据处理**:自动去重、合并、过滤 0 值
27
+ - ✅ **响应式布局**:自适应容器尺寸
28
+ - ✅ **跨端支持**:Web 端完整功能,RN 端提供降级方案
29
+
30
+ ## 基础用法
31
+
32
+ ### 树形数据(推荐)
33
+
34
+ ```tsx
35
+ import { NestedPieChart } from '@beppla/tapas-ui';
36
+
37
+ const data = [
38
+ {
39
+ key: 'cash',
40
+ label: 'Cash',
41
+ children: [
42
+ { key: 'cash-19', label: '19% VAT', value: 1250.50 },
43
+ { key: 'cash-7', label: '7% VAT', value: 680.30 },
44
+ ],
45
+ },
46
+ {
47
+ key: 'credit-card',
48
+ label: 'Credit Card',
49
+ children: [
50
+ { key: 'cc-19', label: '19% VAT', value: 3420.80 },
51
+ { key: 'cc-7', label: '7% VAT', value: 1560.40 },
52
+ ],
53
+ },
54
+ ];
55
+
56
+ const paymentMethodColors = {
57
+ 'cash': '#00B894',
58
+ 'credit-card': '#FF6B00',
59
+ };
60
+
61
+ <NestedPieChart
62
+ data={data}
63
+ height={450}
64
+ colorStrategy={{
65
+ baseColors: paymentMethodColors,
66
+ autoGenerate: true,
67
+ }}
68
+ formatValue={(value) => `€${value.toFixed(2)}`}
69
+ />
70
+ ```
71
+
72
+ ### 扁平数据
73
+
74
+ ```tsx
75
+ const flatData = [
76
+ { key: 'cash-19', label: '19% VAT', value: 1250.50, groupKey: 'cash', groupLabel: 'Cash' },
77
+ { key: 'cash-7', label: '7% VAT', value: 680.30, groupKey: 'cash', groupLabel: 'Cash' },
78
+ { key: 'cc-19', label: '19% VAT', value: 3420.80, groupKey: 'credit-card', groupLabel: 'Credit Card' },
79
+ ];
80
+
81
+ <NestedPieChart
82
+ data={flatData}
83
+ dataType="flat"
84
+ height={450}
85
+ />
86
+ ```
87
+
88
+ ## Props
89
+
90
+ ### 数据相关
91
+
92
+ | Prop | Type | Default | Description |
93
+ |------|------|---------|-------------|
94
+ | `data` | `NestedPieChartNode[]` \| `NestedPieChartFlatData[]` | **required** | 图表数据 |
95
+ | `dataType` | `'tree'` \| `'flat'` | auto | 数据类型,默认自动推断 |
96
+ | `levels` | `number` | auto | 显示层数,默认自动计算 |
97
+
98
+ ### 尺寸相关
99
+
100
+ | Prop | Type | Default | Description |
101
+ |------|------|---------|-------------|
102
+ | `width` | `number` | auto | 容器宽度 |
103
+ | `height` | `number` | `400` | 容器高度 |
104
+ | `outerRadius` | `number` \| `string` | auto | 外圆半径(可以是数字或百分比) |
105
+ | `innerRadius` | `number` \| `string` | `60` | 内圆半径(形成 donut 图) |
106
+ | `radiusGap` | `number` | `15` | 层与层之间的间隔 |
107
+
108
+ ### 配色相关
109
+
110
+ | Prop | Type | Default | Description |
111
+ |------|------|---------|-------------|
112
+ | `colorStrategy` | `ColorStrategy` | `{ autoGenerate: true }` | 配色策略 |
113
+ | `colors` | `string[]` | `DEFAULT_COLORS` | 默认配色数组 |
114
+
115
+ #### ColorStrategy
116
+
117
+ ```tsx
118
+ interface ColorStrategy {
119
+ baseColors?: Record<string, string>; // 大类基色 mapping
120
+ autoGenerate?: boolean; // 是否自动生成子类渐变色
121
+ colorSteps?: number; // 渐变色阶数
122
+ minColorDiff?: number; // 相邻颜色最小色差 (0-1)
123
+ }
124
+ ```
125
+
126
+ ### 图例相关
127
+
128
+ | Prop | Type | Default | Description |
129
+ |------|------|---------|-------------|
130
+ | `showLegend` | `boolean` | `true` | 是否显示图例 |
131
+ | `legendMode` | `'flat'` \| `'grouped'` | `'grouped'` | 图例模式 |
132
+ | `legendPosition` | `'top'` \| `'bottom'` \| `'left'` \| `'right'` | `'right'` | 图例位置 |
133
+ | `legendContent` | `'all'` \| `'parent-only'` \| `'children-only'` | `'all'` | 图例显示内容 |
134
+ | `legendCollapsible` | `boolean` | `true` | 是否可折叠 |
135
+ | `legendDefaultExpanded` | `boolean` | `true` | 默认展开状态 |
136
+ | `legendSortStrategy` | `LegendSortStrategy` | `'none'` | 子项排序策略 |
137
+ | `legendGroupSortStrategy` | `LegendSortStrategy` | `'none'` | 分组排序策略 |
138
+ | `legendShowValues` | `boolean` | `true` | 是否显示数值 |
139
+ | `legendShowPercent` | `boolean` | `true` | 是否显示百分比 |
140
+ | `legendItemGap` | `number` | `6` | 图例项间距 |
141
+ | `legendGroupGap` | `number` | `16` | 分组间距 |
142
+ | `legendLabelMinWidth` | `number` | auto | 标签最小宽度 |
143
+ | `legendChartGap` | `number` | `30` | 图例与图表间距 |
144
+
145
+ #### LegendSortStrategy
146
+
147
+ - `'none'`: 保持原始顺序
148
+ - `'value-desc'`: 按值降序
149
+ - `'value-asc'`: 按值升序
150
+ - `'label-asc'`: 按标签升序
151
+ - `'label-desc'`: 按标签降序
152
+
153
+ ### 格式化相关
154
+
155
+ | Prop | Type | Default | Description |
156
+ |------|------|---------|-------------|
157
+ | `formatValue` | `(value: number) => string` | Euro format | 数值格式化函数 |
158
+ | `formatPercent` | `(percent: number) => string` | `${percent.toFixed(1)}%` | 百分比格式化函数 |
159
+
160
+ ### 交互相关
161
+
162
+ | Prop | Type | Default | Description |
163
+ |------|------|---------|-------------|
164
+ | `onSliceClick` | `(event: SliceClickEvent) => void` | - | 扇区点击事件 |
165
+ | `onSliceHover` | `(event: SliceClickEvent \| null) => void` | - | 扇区 hover 事件 |
166
+ | `onLegendClick` | `(event: LegendClickEvent) => void` | - | 图例点击事件 |
167
+ | `enableLegendFilter` | `boolean` | `false` | 是否启用图例筛选功能 |
168
+
169
+ ### Tooltip 相关
170
+
171
+ | Prop | Type | Default | Description |
172
+ |------|------|---------|-------------|
173
+ | `showTooltip` | `boolean` | `true` | 是否显示 Tooltip |
174
+ | `customTooltip` | `(event: SliceClickEvent) => ReactNode` | - | 自定义 Tooltip 渲染 |
175
+
176
+ ### 其他
177
+
178
+ | Prop | Type | Default | Description |
179
+ |------|------|---------|-------------|
180
+ | `padAngle` | `number` | `0.01` | 扇区间隔角度 |
181
+ | `centerText` | `string` | - | 中心文本 |
182
+ | `centerTextStyle` | `CSSProperties` | - | 中心文本样式 |
183
+ | `emptyText` | `string` | `'No data available'` | 空数据提示文本 |
184
+ | `style` | `any` | - | 容器样式 |
185
+ | `testID` | `string` | - | 测试 ID |
186
+
187
+ ## 数据结构
188
+
189
+ ### NestedPieChartNode (树形)
190
+
191
+ ```tsx
192
+ interface NestedPieChartNode {
193
+ key: string | number; // 唯一标识
194
+ label: string; // 显示文本
195
+ value?: number; // 叶子节点必须有值
196
+ color?: string; // 自定义颜色(可选)
197
+ children?: NestedPieChartNode[]; // 子节点
198
+ metadata?: Record<string, any>; // 额外元数据
199
+ }
200
+ ```
201
+
202
+ ### NestedPieChartFlatData (扁平)
203
+
204
+ ```tsx
205
+ interface NestedPieChartFlatData {
206
+ key: string | number;
207
+ label: string;
208
+ value: number;
209
+ groupKey: string | number; // 所属分组
210
+ groupLabel: string; // 分组名称
211
+ color?: string;
212
+ metadata?: Record<string, any>;
213
+ }
214
+ ```
215
+
216
+ ## 事件对象
217
+
218
+ ### SliceClickEvent
219
+
220
+ ```tsx
221
+ interface SliceClickEvent {
222
+ key: string | number;
223
+ label: string;
224
+ value: number;
225
+ level: number; // 0=根,1=第一层子节点
226
+ path: Array<string | number>; // 从根到当前节点的路径
227
+ parentKey?: string | number;
228
+ metadata?: Record<string, any>;
229
+ }
230
+ ```
231
+
232
+ ### LegendClickEvent
233
+
234
+ ```tsx
235
+ interface LegendClickEvent extends SliceClickEvent {
236
+ groupKey?: string | number;
237
+ isGroupHeader?: boolean; // 是否点击的是分组标题
238
+ }
239
+ ```
240
+
241
+ ## 高级用法
242
+
243
+ ### 自定义配色策略
244
+
245
+ ```tsx
246
+ <NestedPieChart
247
+ data={data}
248
+ colorStrategy={{
249
+ baseColors: {
250
+ 'cash': '#00B894',
251
+ 'credit-card': '#FF6B00',
252
+ 'apple-pay': '#0066CC',
253
+ },
254
+ autoGenerate: true,
255
+ colorSteps: 5,
256
+ minColorDiff: 0.12,
257
+ }}
258
+ />
259
+ ```
260
+
261
+ ### 交互和筛选
262
+
263
+ ```tsx
264
+ function InteractiveChart() {
265
+ const [selectedItem, setSelectedItem] = useState<string>('');
266
+
267
+ return (
268
+ <>
269
+ <NestedPieChart
270
+ data={data}
271
+ enableLegendFilter={true}
272
+ onSliceClick={(event) => {
273
+ setSelectedItem(event.label);
274
+ }}
275
+ onLegendClick={(event) => {
276
+ console.log('Legend clicked:', event);
277
+ }}
278
+ />
279
+ {selectedItem && <Text>Selected: {selectedItem}</Text>}
280
+ </>
281
+ );
282
+ }
283
+ ```
284
+
285
+ ### 自定义 Tooltip
286
+
287
+ ```tsx
288
+ <NestedPieChart
289
+ data={data}
290
+ customTooltip={(event) => (
291
+ <div style={{
292
+ backgroundColor: '#2C3E50',
293
+ color: 'white',
294
+ padding: '12px',
295
+ borderRadius: '8px',
296
+ }}>
297
+ <div style={{ fontWeight: 600 }}>{event.label}</div>
298
+ <div>Amount: €{event.value.toFixed(2)}</div>
299
+ <div>Level: {event.level === 0 ? 'Payment Method' : 'Tax Rate'}</div>
300
+ </div>
301
+ )}
302
+ />
303
+ ```
304
+
305
+ ### 排序策略
306
+
307
+ ```tsx
308
+ <NestedPieChart
309
+ data={data}
310
+ legendGroupSortStrategy="value-desc" // 分组按值降序
311
+ legendSortStrategy="value-desc" // 子项按值降序
312
+ />
313
+ ```
314
+
315
+ ### 中心文本和样式
316
+
317
+ ```tsx
318
+ <NestedPieChart
319
+ data={data}
320
+ centerText="€14,768"
321
+ centerTextStyle={{
322
+ fontSize: '28px',
323
+ fontWeight: 700,
324
+ color: '#2C3E50',
325
+ }}
326
+ />
327
+ ```
328
+
329
+ ## 使用场景
330
+
331
+ ### Store Insights / Summary
332
+
333
+ ```tsx
334
+ // 支付方式 -> 税率分析
335
+ const salesData = [
336
+ {
337
+ key: 'cash',
338
+ label: 'Cash',
339
+ children: [
340
+ { key: 'cash-19', label: '19% VAT', value: 1250.50 },
341
+ { key: 'cash-7', label: '7% VAT', value: 680.30 },
342
+ ],
343
+ },
344
+ // ...
345
+ ];
346
+
347
+ <NestedPieChart
348
+ data={salesData}
349
+ height={450}
350
+ formatValue={(value) => new Intl.NumberFormat('de-DE', {
351
+ style: 'currency',
352
+ currency: 'EUR',
353
+ }).format(value)}
354
+ />
355
+ ```
356
+
357
+ ### 分类销售分析
358
+
359
+ ```tsx
360
+ // 产品类别 -> 子类别销售
361
+ const productData = [
362
+ {
363
+ key: 'food',
364
+ label: 'Food & Beverage',
365
+ children: [
366
+ { key: 'food-hot', label: 'Hot Meals', value: 5200 },
367
+ { key: 'food-cold', label: 'Cold Drinks', value: 3100 },
368
+ { key: 'food-dessert', label: 'Desserts', value: 1800 },
369
+ ],
370
+ },
371
+ // ...
372
+ ];
373
+ ```
374
+
375
+ ## 注意事项
376
+
377
+ 1. **数据要求**:
378
+ - 每个节点必须有唯一的 `key`
379
+ - 叶子节点必须有 `value`
380
+ - 0 值会被自动过滤
381
+
382
+ 2. **性能优化**:
383
+ - 自动去重和合并相同 key 的数据
384
+ - 建议数据量不超过 100 个节点(包括所有层级)
385
+
386
+ 3. **跨端支持**:
387
+ - Web 端:完整功能
388
+ - React Native:目前提供降级提示,后续版本支持
389
+
390
+ 4. **颜色生成**:
391
+ - 建议为主要分类提供 `baseColors` mapping
392
+ - 子类渐变色会自动生成,保证同色系且可辨识
393
+
394
+ ## 类型定义
395
+
396
+ 完整的 TypeScript 类型定义请参考:
397
+ - `NestedPieChart.types.ts`
398
+
399
+ ## 工具函数
400
+
401
+ 组件提供了一系列工具函数,可单独导入使用:
402
+
403
+ ```tsx
404
+ import {
405
+ isTreeData,
406
+ flatToTree,
407
+ cleanData,
408
+ generateColorShades,
409
+ generateColorMap,
410
+ processData,
411
+ buildLegendGroupData,
412
+ formatEuro,
413
+ } from '@beppla/tapas-ui';
414
+ ```
415
+
416
+ ## 相关组件
417
+
418
+ - `PieChart` - 基础饼图组件
419
+ - `BarChart` - 柱状图组件
420
+ - `LineChart` - 折线图组件
421
+ - `ComboChart` - 组合图组件