@zerodep-dev/vue-tsx-pro-ui 0.3.2 → 0.4.0
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.
- package/dist/charts/AreaChart.d.ts +1 -1
- package/dist/charts/AreaChart.js +6 -48
- package/dist/charts/AreaChart.js.map +1 -1
- package/dist/charts/BarChart.js +6 -49
- package/dist/charts/BarChart.js.map +1 -1
- package/dist/charts/ChordChart.d.ts +7 -2
- package/dist/charts/ChordChart.js +151 -60
- package/dist/charts/ChordChart.js.map +1 -1
- package/dist/charts/ComboChart.d.ts +2 -1
- package/dist/charts/ComboChart.js +17 -93
- package/dist/charts/ComboChart.js.map +1 -1
- package/dist/charts/DonutChart.d.ts +6 -1
- package/dist/charts/DonutChart.js +134 -51
- package/dist/charts/DonutChart.js.map +1 -1
- package/dist/charts/FunnelChart.js.map +1 -1
- package/dist/charts/GraphChart.d.ts +22 -10
- package/dist/charts/GraphChart.js +415 -175
- package/dist/charts/GraphChart.js.map +1 -1
- package/dist/charts/LineChart.d.ts +1 -29
- package/dist/charts/LineChart.js +6 -54
- package/dist/charts/LineChart.js.map +1 -1
- package/dist/charts/MapChart.d.ts +21 -48
- package/dist/charts/MapChart.js +426 -353
- package/dist/charts/MapChart.js.map +1 -1
- package/dist/charts/RadarChart.js.map +1 -1
- package/dist/charts/SankeyChart.d.ts +7 -2
- package/dist/charts/SankeyChart.js +164 -76
- package/dist/charts/SankeyChart.js.map +1 -1
- package/dist/charts/ScatterChart.d.ts +7 -1
- package/dist/charts/ScatterChart.js +45 -30
- package/dist/charts/ScatterChart.js.map +1 -1
- package/dist/charts/TimelineChart.d.ts +8 -1
- package/dist/charts/TimelineChart.js +141 -89
- package/dist/charts/TimelineChart.js.map +1 -1
- package/dist/charts/TreemapChart.d.ts +6 -0
- package/dist/charts/TreemapChart.js +174 -58
- package/dist/charts/TreemapChart.js.map +1 -1
- package/dist/charts/WaterfallChart.d.ts +6 -7
- package/dist/charts/WaterfallChart.js +46 -51
- package/dist/charts/WaterfallChart.js.map +1 -1
- package/dist/charts/XYChart.d.ts +44 -35
- package/dist/charts/XYChart.js +493 -281
- package/dist/charts/XYChart.js.map +1 -1
- package/dist/charts/axis-ticks.d.ts +1 -1
- package/dist/charts/axis-ticks.js +4 -5
- package/dist/charts/axis-ticks.js.map +1 -1
- package/dist/charts/flow.d.ts +4 -11
- package/dist/charts/flow.js +4 -4
- package/dist/charts/flow.js.map +1 -1
- package/dist/charts/frame.d.ts +6 -30
- package/dist/charts/frame.js +6 -99
- package/dist/charts/frame.js.map +1 -1
- package/dist/charts/geo/projection.d.ts +45 -0
- package/dist/charts/geo/projection.js +201 -0
- package/dist/charts/geo/projection.js.map +1 -0
- package/dist/charts/geo/topojson.d.ts +50 -0
- package/dist/charts/geo/topojson.js +119 -0
- package/dist/charts/geo/topojson.js.map +1 -0
- package/dist/charts/index.d.ts +21 -9
- package/dist/charts/index.js +19 -8
- package/dist/charts/label-layout.js.map +1 -1
- package/dist/charts/layout/chord.d.ts +44 -0
- package/dist/charts/layout/chord.js +45 -0
- package/dist/charts/layout/chord.js.map +1 -0
- package/dist/charts/layout/graph.d.ts +49 -0
- package/dist/charts/layout/graph.js +268 -0
- package/dist/charts/layout/graph.js.map +1 -0
- package/dist/charts/layout/sankey.d.ts +79 -0
- package/dist/charts/layout/sankey.js +200 -0
- package/dist/charts/layout/sankey.js.map +1 -0
- package/dist/charts/layout/treemap.d.ts +46 -0
- package/dist/charts/layout/treemap.js +152 -0
- package/dist/charts/layout/treemap.js.map +1 -0
- package/dist/charts/marks.d.ts +79 -0
- package/dist/charts/marks.js +231 -0
- package/dist/charts/marks.js.map +1 -0
- package/dist/charts/plot.d.ts +107 -0
- package/dist/charts/plot.js +231 -0
- package/dist/charts/plot.js.map +1 -0
- package/dist/charts/scale.d.ts +29 -0
- package/dist/charts/scale.js +244 -0
- package/dist/charts/scale.js.map +1 -0
- package/dist/charts/shape.d.ts +46 -0
- package/dist/charts/shape.js +131 -0
- package/dist/charts/shape.js.map +1 -0
- package/dist/charts/stack.d.ts +17 -0
- package/dist/charts/stack.js +35 -0
- package/dist/charts/stack.js.map +1 -0
- package/dist/charts/text-size.d.ts +12 -0
- package/dist/charts/text-size.js +32 -0
- package/dist/charts/text-size.js.map +1 -0
- package/dist/display/VirtualList.d.ts +1 -2
- package/dist/display/VirtualList.js +11 -21
- package/dist/display/VirtualList.js.map +1 -1
- package/dist/input/Combobox.d.ts +1 -1
- package/dist/input/Combobox.js.map +1 -1
- package/dist/input/ListPopover.d.ts +1 -1
- package/dist/input/ListPopover.js.map +1 -1
- package/dist/input/Listbox.d.ts +1 -2
- package/dist/input/Listbox.js +7 -19
- package/dist/input/Listbox.js.map +1 -1
- package/dist/input/Select.d.ts +1 -1
- package/dist/input/Select.js.map +1 -1
- package/dist/maps/china-provinces.js +35680 -0
- package/dist/maps/china-provinces.js.map +1 -0
- package/dist/maps/china.d.ts +13 -0
- package/dist/maps/china.js +8 -0
- package/dist/maps/china.js.map +1 -0
- package/dist/maps/index.d.ts +9 -0
- package/dist/maps/index.js +3 -0
- package/dist/maps/world-countries.js +22273 -0
- package/dist/maps/world-countries.js.map +1 -0
- package/dist/maps/world.d.ts +13 -0
- package/dist/maps/world.js +8 -0
- package/dist/maps/world.js.map +1 -0
- package/dist/overlay/CommandPalette.d.ts +1 -1
- package/dist/overlay/CommandPalette.js.map +1 -1
- package/dist/overlay/detached.js +14 -1
- package/dist/overlay/detached.js.map +1 -1
- package/dist/patterns/QueryTable.js +0 -2
- package/dist/patterns/QueryTable.js.map +1 -1
- package/dist/table/DataTable.js +1 -1
- package/dist/table/DataTable.js.map +1 -1
- package/dist/table/DataTableView.d.ts +0 -3
- package/dist/table/DataTableView.js +32 -26
- package/dist/table/DataTableView.js.map +1 -1
- package/dist/table/table-styles.d.ts +1 -1
- package/dist/table/table-styles.js +0 -13
- package/dist/table/table-styles.js.map +1 -1
- package/package.json +7 -8
- package/dist/charts/single.d.ts +0 -41
- package/dist/charts/single.js +0 -66
- package/dist/charts/single.js.map +0 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 矩形树图的布局:扁平的明细按几个字段逐级分组成树,再按“squarified”算法切块,块的面积与数值成比例、尽量接近正方形
|
|
3
|
+
* (Bruls、Huizing、van Wijk 的 squarify,写法同 d3-hierarchy 的 treemapSquarify,ISC)。
|
|
4
|
+
*
|
|
5
|
+
* const root = groupTree(rows, [(row) => row.region, (row) => row.supplier], (row) => row.amount);
|
|
6
|
+
* treemapLayout(root, { width: 600, height: 300, padding: 3 });
|
|
7
|
+
* root.children[0].x0、y0、x1、y1;叶子的 data 是那一行明细
|
|
8
|
+
*/
|
|
9
|
+
/** 树上的一个节点:分组或一条明细(叶子);布局后带上矩形 */
|
|
10
|
+
export interface TreemapNode<D> {
|
|
11
|
+
/** 分组的值(区域名),叶子是最内层分组的值 */
|
|
12
|
+
key: string;
|
|
13
|
+
/** 数值:叶子是明细的值,分组是子节点之和 */
|
|
14
|
+
value: number;
|
|
15
|
+
/** 层级:根是 0 */
|
|
16
|
+
depth: number;
|
|
17
|
+
/** 叶子对应的明细 */
|
|
18
|
+
data?: D;
|
|
19
|
+
/** 父节点(根没有) */
|
|
20
|
+
parent?: TreemapNode<D>;
|
|
21
|
+
/** 子节点,按数值从大到小(叶子没有) */
|
|
22
|
+
children?: TreemapNode<D>[];
|
|
23
|
+
/** 左 */
|
|
24
|
+
x0: number;
|
|
25
|
+
/** 上 */
|
|
26
|
+
y0: number;
|
|
27
|
+
/** 右 */
|
|
28
|
+
x1: number;
|
|
29
|
+
/** 下 */
|
|
30
|
+
y1: number;
|
|
31
|
+
}
|
|
32
|
+
/** treemapLayout 的选项 */
|
|
33
|
+
export interface TreemapLayoutOptions {
|
|
34
|
+
/** 宽 */
|
|
35
|
+
width: number;
|
|
36
|
+
/** 高 */
|
|
37
|
+
height: number;
|
|
38
|
+
/** 块与块之间、分组四周留的空,默认 0 */
|
|
39
|
+
padding?: number;
|
|
40
|
+
/** 分组顶边多留的空(写分组名),默认同 padding */
|
|
41
|
+
paddingTop?: number;
|
|
42
|
+
}
|
|
43
|
+
/** 明细按 keys 逐级分组成树:同一组的明细挂在同一个分组下,数值不是正数的明细不要 */
|
|
44
|
+
export declare function groupTree<D>(rows: readonly D[], keys: readonly ((row: D) => string)[], value: (row: D) => number): TreemapNode<D>;
|
|
45
|
+
/** 给树上每个节点算出矩形(就地写入):分组四周与块之间留 padding,分组顶边留 paddingTop */
|
|
46
|
+
export declare function treemapLayout<D>(root: TreemapNode<D>, { width, height, padding, paddingTop }: TreemapLayoutOptions): void;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
//#region src/charts/layout/treemap.ts
|
|
2
|
+
var blank = {
|
|
3
|
+
x0: 0,
|
|
4
|
+
y0: 0,
|
|
5
|
+
x1: 0,
|
|
6
|
+
y1: 0
|
|
7
|
+
};
|
|
8
|
+
/** 明细按 keys 逐级分组成树:同一组的明细挂在同一个分组下,数值不是正数的明细不要 */
|
|
9
|
+
function groupTree(rows, keys, value) {
|
|
10
|
+
const root = {
|
|
11
|
+
key: "",
|
|
12
|
+
value: 0,
|
|
13
|
+
depth: 0,
|
|
14
|
+
children: [],
|
|
15
|
+
...blank
|
|
16
|
+
};
|
|
17
|
+
for (const row of rows) {
|
|
18
|
+
const amount = value(row);
|
|
19
|
+
if (!(amount > 0)) continue;
|
|
20
|
+
let node = root;
|
|
21
|
+
keys.forEach((key, level) => {
|
|
22
|
+
const name = key(row);
|
|
23
|
+
const leaf = level === keys.length - 1;
|
|
24
|
+
let child = leaf ? void 0 : node.children.find((item) => item.key === name);
|
|
25
|
+
if (!child) {
|
|
26
|
+
child = {
|
|
27
|
+
key: name,
|
|
28
|
+
value: 0,
|
|
29
|
+
depth: level + 1,
|
|
30
|
+
parent: node,
|
|
31
|
+
...blank
|
|
32
|
+
};
|
|
33
|
+
if (leaf) child.data = row;
|
|
34
|
+
else child.children = [];
|
|
35
|
+
node.children.push(child);
|
|
36
|
+
}
|
|
37
|
+
child.value += leaf ? amount : 0;
|
|
38
|
+
node = child;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const sum = (node) => {
|
|
42
|
+
if (!node.children) return node.value;
|
|
43
|
+
node.value = node.children.reduce((total, child) => total + sum(child), 0);
|
|
44
|
+
node.children.sort((a, b) => b.value - a.value);
|
|
45
|
+
return node.value;
|
|
46
|
+
};
|
|
47
|
+
sum(root);
|
|
48
|
+
return root;
|
|
49
|
+
}
|
|
50
|
+
/** 黄金比:squarify 追求的长宽比 */
|
|
51
|
+
var PHI = (1 + Math.sqrt(5)) / 2;
|
|
52
|
+
/** 一行(或一列)子节点沿横向依次排开 */
|
|
53
|
+
function dice(nodes, total, x0, y0, x1, y1) {
|
|
54
|
+
const k = total ? (x1 - x0) / total : 0;
|
|
55
|
+
let x = x0;
|
|
56
|
+
for (const node of nodes) Object.assign(node, {
|
|
57
|
+
x0: x,
|
|
58
|
+
y0,
|
|
59
|
+
x1: x += node.value * k,
|
|
60
|
+
y1
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** 沿纵向依次排开 */
|
|
64
|
+
function slice(nodes, total, x0, y0, x1, y1) {
|
|
65
|
+
const k = total ? (y1 - y0) / total : 0;
|
|
66
|
+
let y = y0;
|
|
67
|
+
for (const node of nodes) Object.assign(node, {
|
|
68
|
+
x0,
|
|
69
|
+
y0: y,
|
|
70
|
+
x1,
|
|
71
|
+
y1: y += node.value * k
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** squarify:一行行地放,一行里不断加节点,直到再加会让最长的长宽比变差 */
|
|
75
|
+
function squarify(parent, x0, y0, x1, y1) {
|
|
76
|
+
const nodes = parent.children ?? [];
|
|
77
|
+
let value = parent.value;
|
|
78
|
+
let i0 = 0;
|
|
79
|
+
while (i0 < nodes.length) {
|
|
80
|
+
const dx = x1 - x0;
|
|
81
|
+
const dy = y1 - y0;
|
|
82
|
+
let i1 = i0;
|
|
83
|
+
let sumValue = 0;
|
|
84
|
+
do
|
|
85
|
+
sumValue = nodes[i1++].value;
|
|
86
|
+
while (!sumValue && i1 < nodes.length);
|
|
87
|
+
let minValue = sumValue;
|
|
88
|
+
let maxValue = sumValue;
|
|
89
|
+
const alpha = Math.max(dy / dx, dx / dy) / (value * PHI);
|
|
90
|
+
let beta = sumValue * sumValue * alpha;
|
|
91
|
+
let minRatio = Math.max(maxValue / beta, beta / minValue);
|
|
92
|
+
for (; i1 < nodes.length; i1 += 1) {
|
|
93
|
+
const nodeValue = nodes[i1].value;
|
|
94
|
+
sumValue += nodeValue;
|
|
95
|
+
minValue = Math.min(minValue, nodeValue);
|
|
96
|
+
maxValue = Math.max(maxValue, nodeValue);
|
|
97
|
+
beta = sumValue * sumValue * alpha;
|
|
98
|
+
const ratio = Math.max(maxValue / beta, beta / minValue);
|
|
99
|
+
if (ratio > minRatio) {
|
|
100
|
+
sumValue -= nodeValue;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
minRatio = ratio;
|
|
104
|
+
}
|
|
105
|
+
const row = nodes.slice(i0, i1);
|
|
106
|
+
if (dx < dy) {
|
|
107
|
+
const y = dy && value ? y0 + dy * sumValue / value : y1;
|
|
108
|
+
dice(row, sumValue, x0, y0, x1, y);
|
|
109
|
+
y0 = y;
|
|
110
|
+
} else {
|
|
111
|
+
const x = dx && value ? x0 + dx * sumValue / value : x1;
|
|
112
|
+
slice(row, sumValue, x0, y0, x, y1);
|
|
113
|
+
x0 = x;
|
|
114
|
+
}
|
|
115
|
+
value -= sumValue;
|
|
116
|
+
i0 = i1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** 给树上每个节点算出矩形(就地写入):分组四周与块之间留 padding,分组顶边留 paddingTop */
|
|
120
|
+
function treemapLayout(root, { width, height, padding = 0, paddingTop = padding }) {
|
|
121
|
+
Object.assign(root, {
|
|
122
|
+
x0: 0,
|
|
123
|
+
y0: 0,
|
|
124
|
+
x1: width,
|
|
125
|
+
y1: height
|
|
126
|
+
});
|
|
127
|
+
const half = padding / 2;
|
|
128
|
+
const position = (node) => {
|
|
129
|
+
if (!node.children?.length) return;
|
|
130
|
+
const top = node === root ? 0 : paddingTop;
|
|
131
|
+
const inset = node === root ? 0 : padding;
|
|
132
|
+
let x0 = node.x0 + inset - half;
|
|
133
|
+
let y0 = node.y0 + top - half;
|
|
134
|
+
let x1 = node.x1 - inset + half;
|
|
135
|
+
let y1 = node.y1 - inset + half;
|
|
136
|
+
if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
|
|
137
|
+
if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
|
|
138
|
+
squarify(node, x0, y0, x1, y1);
|
|
139
|
+
for (const child of node.children) {
|
|
140
|
+
child.x0 += half;
|
|
141
|
+
child.y0 += half;
|
|
142
|
+
child.x1 = Math.max(child.x0, child.x1 - half);
|
|
143
|
+
child.y1 = Math.max(child.y0, child.y1 - half);
|
|
144
|
+
position(child);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
position(root);
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
export { groupTree, treemapLayout };
|
|
151
|
+
|
|
152
|
+
//# sourceMappingURL=treemap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"treemap.js","names":[],"sources":["../../../src/charts/layout/treemap.ts"],"sourcesContent":["/**\n * 矩形树图的布局:扁平的明细按几个字段逐级分组成树,再按“squarified”算法切块,块的面积与数值成比例、尽量接近正方形\n * (Bruls、Huizing、van Wijk 的 squarify,写法同 d3-hierarchy 的 treemapSquarify,ISC)。\n *\n * const root = groupTree(rows, [(row) => row.region, (row) => row.supplier], (row) => row.amount);\n * treemapLayout(root, { width: 600, height: 300, padding: 3 });\n * root.children[0].x0、y0、x1、y1;叶子的 data 是那一行明细\n */\n\n/** 树上的一个节点:分组或一条明细(叶子);布局后带上矩形 */\nexport interface TreemapNode<D> {\n /** 分组的值(区域名),叶子是最内层分组的值 */\n key: string;\n /** 数值:叶子是明细的值,分组是子节点之和 */\n value: number;\n /** 层级:根是 0 */\n depth: number;\n /** 叶子对应的明细 */\n data?: D;\n /** 父节点(根没有) */\n parent?: TreemapNode<D>;\n /** 子节点,按数值从大到小(叶子没有) */\n children?: TreemapNode<D>[];\n /** 左 */\n x0: number;\n /** 上 */\n y0: number;\n /** 右 */\n x1: number;\n /** 下 */\n y1: number;\n}\n\n/** treemapLayout 的选项 */\nexport interface TreemapLayoutOptions {\n /** 宽 */\n width: number;\n /** 高 */\n height: number;\n /** 块与块之间、分组四周留的空,默认 0 */\n padding?: number;\n /** 分组顶边多留的空(写分组名),默认同 padding */\n paddingTop?: number;\n}\n\nconst blank = { x0: 0, y0: 0, x1: 0, y1: 0 };\n\n/** 明细按 keys 逐级分组成树:同一组的明细挂在同一个分组下,数值不是正数的明细不要 */\nexport function groupTree<D>(\n rows: readonly D[],\n keys: readonly ((row: D) => string)[],\n value: (row: D) => number,\n): TreemapNode<D> {\n const root: TreemapNode<D> = { key: '', value: 0, depth: 0, children: [], ...blank };\n for (const row of rows) {\n const amount = value(row);\n if (!(amount > 0)) continue;\n let node = root;\n keys.forEach((key, level) => {\n const name = key(row);\n const leaf = level === keys.length - 1;\n let child = leaf ? undefined : node.children!.find((item) => item.key === name);\n if (!child) {\n child = { key: name, value: 0, depth: level + 1, parent: node, ...blank };\n if (leaf) child.data = row;\n else child.children = [];\n node.children!.push(child);\n }\n child.value += leaf ? amount : 0;\n node = child;\n });\n }\n const sum = (node: TreemapNode<D>): number => {\n if (!node.children) return node.value;\n node.value = node.children.reduce((total, child) => total + sum(child), 0);\n node.children.sort((a, b) => b.value - a.value);\n return node.value;\n };\n sum(root);\n return root;\n}\n\n/** 黄金比:squarify 追求的长宽比 */\nconst PHI = (1 + Math.sqrt(5)) / 2;\n\n/** 一行(或一列)子节点沿横向依次排开 */\nfunction dice<D>(\n nodes: readonly TreemapNode<D>[],\n total: number,\n x0: number,\n y0: number,\n x1: number,\n y1: number,\n) {\n const k = total ? (x1 - x0) / total : 0;\n let x = x0;\n for (const node of nodes) Object.assign(node, { x0: x, y0, x1: (x += node.value * k), y1 });\n}\n\n/** 沿纵向依次排开 */\nfunction slice<D>(\n nodes: readonly TreemapNode<D>[],\n total: number,\n x0: number,\n y0: number,\n x1: number,\n y1: number,\n) {\n const k = total ? (y1 - y0) / total : 0;\n let y = y0;\n for (const node of nodes) Object.assign(node, { x0, y0: y, x1, y1: (y += node.value * k) });\n}\n\n/** squarify:一行行地放,一行里不断加节点,直到再加会让最长的长宽比变差 */\nfunction squarify<D>(parent: TreemapNode<D>, x0: number, y0: number, x1: number, y1: number) {\n const nodes = parent.children ?? [];\n let value = parent.value;\n let i0 = 0;\n while (i0 < nodes.length) {\n const dx = x1 - x0;\n const dy = y1 - y0;\n let i1 = i0;\n let sumValue = 0;\n // 跳过数值为 0 的节点\n do sumValue = nodes[i1++]!.value;\n while (!sumValue && i1 < nodes.length);\n let minValue = sumValue;\n let maxValue = sumValue;\n const alpha = Math.max(dy / dx, dx / dy) / (value * PHI);\n let beta = sumValue * sumValue * alpha;\n let minRatio = Math.max(maxValue / beta, beta / minValue);\n for (; i1 < nodes.length; i1 += 1) {\n const nodeValue = nodes[i1]!.value;\n sumValue += nodeValue;\n minValue = Math.min(minValue, nodeValue);\n maxValue = Math.max(maxValue, nodeValue);\n beta = sumValue * sumValue * alpha;\n const ratio = Math.max(maxValue / beta, beta / minValue);\n if (ratio > minRatio) {\n sumValue -= nodeValue;\n break;\n }\n minRatio = ratio;\n }\n const row = nodes.slice(i0, i1);\n // 宽比高小:这一行横着排在顶上;否则竖着排在左边\n if (dx < dy) {\n const y = dy && value ? y0 + (dy * sumValue) / value : y1;\n dice(row, sumValue, x0, y0, x1, y);\n y0 = y;\n } else {\n const x = dx && value ? x0 + (dx * sumValue) / value : x1;\n slice(row, sumValue, x0, y0, x, y1);\n x0 = x;\n }\n value -= sumValue;\n i0 = i1;\n }\n}\n\n/** 给树上每个节点算出矩形(就地写入):分组四周与块之间留 padding,分组顶边留 paddingTop */\nexport function treemapLayout<D>(\n root: TreemapNode<D>,\n { width, height, padding = 0, paddingTop = padding }: TreemapLayoutOptions,\n): void {\n Object.assign(root, { x0: 0, y0: 0, x1: width, y1: height });\n const half = padding / 2;\n const position = (node: TreemapNode<D>) => {\n if (!node.children?.length) return;\n // 子节点先在外扩半个间距的区域里切块,各自再缩回半个间距:相邻两块之间正好一个 padding(同 d3 的 paddingInner)\n const top = node === root ? 0 : paddingTop;\n const inset = node === root ? 0 : padding;\n let x0 = node.x0 + inset - half;\n let y0 = node.y0 + top - half;\n let x1 = node.x1 - inset + half;\n let y1 = node.y1 - inset + half;\n if (x1 < x0) x0 = x1 = (x0 + x1) / 2;\n if (y1 < y0) y0 = y1 = (y0 + y1) / 2;\n squarify(node, x0, y0, x1, y1);\n for (const child of node.children) {\n child.x0 += half;\n child.y0 += half;\n child.x1 = Math.max(child.x0, child.x1 - half);\n child.y1 = Math.max(child.y0, child.y1 - half);\n position(child);\n }\n };\n position(root);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 直角坐标图表的图形:柱(分组、堆叠)、线、面积、数据点。柱状图、折线图、面积图、组合图、瀑布图按需组合,
|
|
3
|
+
* 坐标都从 XYChartContext 换算(横向时类目在纵轴)。
|
|
4
|
+
*
|
|
5
|
+
* render: (context) => [chartAreas(context, series, { curve: 'monotone' }), chartDots(context, series, 'hollow')]
|
|
6
|
+
*
|
|
7
|
+
* 进场:柱从基线长出来、线从左往右描出、面积与点淡入,时长取主题的 lg(“减少动态效果”时为 0);
|
|
8
|
+
* 用 @starting-style,只在图形第一次出现时播放,数据更新时原地变。
|
|
9
|
+
*/
|
|
10
|
+
import { css, type SxStyles } from '@zerodep-dev/vue-tsx-pro-tsx/styles';
|
|
11
|
+
import type { VNodeChild } from 'vue';
|
|
12
|
+
import type { ResolvedSeries } from './series';
|
|
13
|
+
import { type LineCurves } from './shape';
|
|
14
|
+
import type { XYChartContext } from './XYChart';
|
|
15
|
+
/** 图形的样式 */
|
|
16
|
+
export declare const chartMarkStyles: Readonly<{
|
|
17
|
+
readonly bar: css.CompiledStyles;
|
|
18
|
+
readonly growUp: css.CompiledStyles;
|
|
19
|
+
readonly growDown: css.CompiledStyles;
|
|
20
|
+
readonly growRight: css.CompiledStyles;
|
|
21
|
+
readonly growLeft: css.CompiledStyles;
|
|
22
|
+
readonly line: css.CompiledStyles;
|
|
23
|
+
readonly area: css.CompiledStyles;
|
|
24
|
+
readonly dot: css.CompiledStyles;
|
|
25
|
+
readonly hollowDot: css.CompiledStyles;
|
|
26
|
+
readonly filledDot: css.CompiledStyles;
|
|
27
|
+
readonly lineWidth: (width: number) => Readonly<[css.CompiledStyles, css.InlineStyles]>;
|
|
28
|
+
readonly fillOpacity: (opacity: number) => Readonly<[css.CompiledStyles, css.InlineStyles]>;
|
|
29
|
+
}>;
|
|
30
|
+
/** 柱的选项 */
|
|
31
|
+
export interface ChartBarOptions {
|
|
32
|
+
/** 堆叠 */
|
|
33
|
+
stacked?: boolean;
|
|
34
|
+
/** 柱末端的圆角(px) */
|
|
35
|
+
radius: number;
|
|
36
|
+
/** 一组柱占一格的比例,默认分组 0.7、堆叠 0.6 */
|
|
37
|
+
fill?: number;
|
|
38
|
+
/** 一组柱最宽多少(px),默认分组 96、堆叠 48 */
|
|
39
|
+
maxWidth?: number;
|
|
40
|
+
}
|
|
41
|
+
/** 一根柱:类目方向上从 start 起宽 width,数值方向上从 low 到 high */
|
|
42
|
+
export declare function chartBar<T extends object>(context: XYChartContext<T>, { start, width, low, high, radius, round, down, }: {
|
|
43
|
+
start: number;
|
|
44
|
+
width: number;
|
|
45
|
+
low: number;
|
|
46
|
+
high: number;
|
|
47
|
+
radius: number;
|
|
48
|
+
/** 末端是圆角 */
|
|
49
|
+
round: boolean;
|
|
50
|
+
/** 朝下(横向时朝左)长:末端在 low 那一头;不写时按正负(负值朝下) */
|
|
51
|
+
down?: boolean;
|
|
52
|
+
}): {
|
|
53
|
+
d: string;
|
|
54
|
+
grow: SxStyles;
|
|
55
|
+
};
|
|
56
|
+
/** 分组(并排)或堆叠的柱:每根柱带 data-index(第几行),点击下钻按它找行 */
|
|
57
|
+
export declare function chartBars<T extends object>(context: XYChartContext<T>, series: readonly ResolvedSeries<T>[], { stacked, radius, fill, maxWidth }: ChartBarOptions): VNodeChild;
|
|
58
|
+
/** 线的选项 */
|
|
59
|
+
export interface ChartLineOptions {
|
|
60
|
+
/** 曲线 */
|
|
61
|
+
curve: keyof LineCurves;
|
|
62
|
+
/** 线宽(px) */
|
|
63
|
+
width: number;
|
|
64
|
+
}
|
|
65
|
+
/** 每个系列一条线(空值处断开) */
|
|
66
|
+
export declare function chartLines<T extends object>(context: XYChartContext<T>, series: readonly ResolvedSeries<T>[], { curve, width }: ChartLineOptions): VNodeChild;
|
|
67
|
+
/** 面积的选项 */
|
|
68
|
+
export interface ChartAreaOptions {
|
|
69
|
+
/** 曲线 */
|
|
70
|
+
curve: keyof LineCurves;
|
|
71
|
+
/** 堆叠:用 context.stacks 里的上下沿 */
|
|
72
|
+
stacked: boolean;
|
|
73
|
+
/** 面积的不透明度 */
|
|
74
|
+
opacity: number;
|
|
75
|
+
}
|
|
76
|
+
/** 每个系列一片面积,上沿描一条线;重叠时下沿是 0(或数值轴的下端),堆叠时是下面那一层 */
|
|
77
|
+
export declare function chartAreas<T extends object>(context: XYChartContext<T>, series: readonly ResolvedSeries<T>[], { curve, stacked, opacity }: ChartAreaOptions): VNodeChild;
|
|
78
|
+
/** 数据点:filled 实心(描一圈表面色),hollow 空心(表面色填充、系列色描边);空值不画 */
|
|
79
|
+
export declare function chartDots<T extends object>(context: XYChartContext<T>, series: readonly ResolvedSeries<T>[], variant: 'filled' | 'hollow'): VNodeChild;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { t } from "../config/theme/tokens.js";
|
|
2
|
+
import { chartSvgStyles } from "./plot.js";
|
|
3
|
+
import { areaPath, barPath, linePath } from "./shape.js";
|
|
4
|
+
import { stackValues } from "./stack.js";
|
|
5
|
+
import { createVNode } from "vue";
|
|
6
|
+
import { mergeJsxProps } from "@zerodep-dev/vue-tsx-pro-tsx";
|
|
7
|
+
import { css } from "@zerodep-dev/vue-tsx-pro-tsx/styles";
|
|
8
|
+
//#region src/charts/marks.tsx
|
|
9
|
+
/**
|
|
10
|
+
* 直角坐标图表的图形:柱(分组、堆叠)、线、面积、数据点。柱状图、折线图、面积图、组合图、瀑布图按需组合,
|
|
11
|
+
* 坐标都从 XYChartContext 换算(横向时类目在纵轴)。
|
|
12
|
+
*
|
|
13
|
+
* render: (context) => [chartAreas(context, series, { curve: 'monotone' }), chartDots(context, series, 'hollow')]
|
|
14
|
+
*
|
|
15
|
+
* 进场:柱从基线长出来、线从左往右描出、面积与点淡入,时长取主题的 lg(“减少动态效果”时为 0);
|
|
16
|
+
* 用 @starting-style,只在图形第一次出现时播放,数据更新时原地变。
|
|
17
|
+
*/
|
|
18
|
+
var enter = `${t.durations.lg} ${t.easings.standard}`;
|
|
19
|
+
/** 图形的样式 */
|
|
20
|
+
var chartMarkStyles = css.create({
|
|
21
|
+
bar: {
|
|
22
|
+
transformBox: "fill-box",
|
|
23
|
+
transition: `scale ${enter}, opacity ${t.durations.sm} ${t.easings.standard}`
|
|
24
|
+
},
|
|
25
|
+
growUp: {
|
|
26
|
+
transformOrigin: "bottom",
|
|
27
|
+
scale: {
|
|
28
|
+
default: "1",
|
|
29
|
+
"@starting-style": "1 0"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
growDown: {
|
|
33
|
+
transformOrigin: "top",
|
|
34
|
+
scale: {
|
|
35
|
+
default: "1",
|
|
36
|
+
"@starting-style": "1 0"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
growRight: {
|
|
40
|
+
transformOrigin: "left",
|
|
41
|
+
scale: {
|
|
42
|
+
default: "1",
|
|
43
|
+
"@starting-style": "0 1"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
growLeft: {
|
|
47
|
+
transformOrigin: "right",
|
|
48
|
+
scale: {
|
|
49
|
+
default: "1",
|
|
50
|
+
"@starting-style": "0 1"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
line: {
|
|
54
|
+
fill: "none",
|
|
55
|
+
strokeLinejoin: "round",
|
|
56
|
+
strokeLinecap: "round",
|
|
57
|
+
strokeDasharray: "1",
|
|
58
|
+
strokeDashoffset: {
|
|
59
|
+
default: 0,
|
|
60
|
+
"@starting-style": 1
|
|
61
|
+
},
|
|
62
|
+
transition: `stroke-dashoffset ${t.durations.xl} ${t.easings.standard}`,
|
|
63
|
+
pointerEvents: "none"
|
|
64
|
+
},
|
|
65
|
+
area: {
|
|
66
|
+
stroke: "none",
|
|
67
|
+
pointerEvents: "none",
|
|
68
|
+
opacity: {
|
|
69
|
+
default: 1,
|
|
70
|
+
"@starting-style": 0
|
|
71
|
+
},
|
|
72
|
+
transition: `opacity ${enter}`
|
|
73
|
+
},
|
|
74
|
+
dot: {
|
|
75
|
+
transformBox: "fill-box",
|
|
76
|
+
transformOrigin: "center",
|
|
77
|
+
scale: {
|
|
78
|
+
default: "1",
|
|
79
|
+
"@starting-style": "0"
|
|
80
|
+
},
|
|
81
|
+
transition: `scale ${enter}`,
|
|
82
|
+
pointerEvents: "none"
|
|
83
|
+
},
|
|
84
|
+
hollowDot: {
|
|
85
|
+
fill: "_surface",
|
|
86
|
+
strokeWidth: 2
|
|
87
|
+
},
|
|
88
|
+
filledDot: {
|
|
89
|
+
stroke: "_surface",
|
|
90
|
+
strokeWidth: 1.5
|
|
91
|
+
},
|
|
92
|
+
lineWidth: (width) => ({ strokeWidth: width }),
|
|
93
|
+
fillOpacity: (opacity) => ({ fillOpacity: opacity })
|
|
94
|
+
});
|
|
95
|
+
/** 一行上一个系列的点:[类目坐标, 数值坐标];空值处断开成几段 */
|
|
96
|
+
function segments(context, value) {
|
|
97
|
+
const result = [];
|
|
98
|
+
let current = [];
|
|
99
|
+
context.rows.forEach((row, index) => {
|
|
100
|
+
const v = value(row, index);
|
|
101
|
+
if (v === void 0) {
|
|
102
|
+
if (current.length) result.push(current);
|
|
103
|
+
current = [];
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
current.push([
|
|
107
|
+
context.category(row, index),
|
|
108
|
+
context.value(v),
|
|
109
|
+
index
|
|
110
|
+
]);
|
|
111
|
+
});
|
|
112
|
+
if (current.length) result.push(current);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
/** 柱的选项 */
|
|
116
|
+
/** 柱末端朝哪边:正值朝上(横向朝右),负值反过来 */
|
|
117
|
+
function endOf(horizontal, negative) {
|
|
118
|
+
if (horizontal) return negative ? "left" : "right";
|
|
119
|
+
return negative ? "bottom" : "top";
|
|
120
|
+
}
|
|
121
|
+
/** 一根柱:类目方向上从 start 起宽 width,数值方向上从 low 到 high */
|
|
122
|
+
function chartBar(context, { start, width, low, high, radius, round, down }) {
|
|
123
|
+
const negative = down ?? (high <= 0 && low < 0);
|
|
124
|
+
const [a, b] = [context.value(low), context.value(high)];
|
|
125
|
+
const end = round ? endOf(context.horizontal, negative) : "none";
|
|
126
|
+
return {
|
|
127
|
+
d: context.horizontal ? barPath(Math.min(a, b), start, Math.abs(b - a), width, radius, end) : barPath(start, Math.min(a, b), width, Math.abs(b - a), radius, end),
|
|
128
|
+
grow: context.horizontal ? negative ? chartMarkStyles.growLeft : chartMarkStyles.growRight : negative ? chartMarkStyles.growDown : chartMarkStyles.growUp
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/** 分组(并排)或堆叠的柱:每根柱带 data-index(第几行),点击下钻按它找行 */
|
|
132
|
+
function chartBars(context, series, { stacked = false, radius, fill, maxWidth }) {
|
|
133
|
+
if (!series.length) return null;
|
|
134
|
+
const groupWidth = Math.min(context.step * (fill ?? (stacked ? .6 : .7)), maxWidth ?? (stacked ? 48 : 96));
|
|
135
|
+
const values = series.map((item) => context.rows.map((row) => context.valueOf(item, row)));
|
|
136
|
+
const stacks = stacked ? stackValues(values) : [];
|
|
137
|
+
const outermost = (index, negative) => {
|
|
138
|
+
for (let s = series.length - 1; s >= 0; s -= 1) {
|
|
139
|
+
const value = values[s][index];
|
|
140
|
+
if (value !== void 0 && value !== 0 && value < 0 === negative) return s;
|
|
141
|
+
}
|
|
142
|
+
return -1;
|
|
143
|
+
};
|
|
144
|
+
const barWidth = stacked ? groupWidth : groupWidth / (series.length + (series.length - 1) * .1);
|
|
145
|
+
return createVNode("g", { "data-part": "bars" }, [context.rows.flatMap((row, index) => {
|
|
146
|
+
const groupStart = context.category(row, index) - groupWidth / 2;
|
|
147
|
+
return series.map((item, s) => {
|
|
148
|
+
const value = values[s][index];
|
|
149
|
+
if (value === void 0 || value === 0) return null;
|
|
150
|
+
const segment = stacked ? stacks[s][index] : {
|
|
151
|
+
low: Math.min(0, value),
|
|
152
|
+
high: Math.max(0, value)
|
|
153
|
+
};
|
|
154
|
+
const { d, grow } = chartBar(context, {
|
|
155
|
+
start: stacked ? groupStart : groupStart + s * barWidth * 1.1,
|
|
156
|
+
width: barWidth,
|
|
157
|
+
low: segment.low,
|
|
158
|
+
high: segment.high,
|
|
159
|
+
radius,
|
|
160
|
+
round: !stacked || outermost(index, value < 0) === s
|
|
161
|
+
});
|
|
162
|
+
return createVNode("path", mergeJsxProps({
|
|
163
|
+
"key": `${item.key}:${index}`,
|
|
164
|
+
"data-part": "bar",
|
|
165
|
+
"data-index": index,
|
|
166
|
+
"d": d
|
|
167
|
+
}, css.attrs(chartMarkStyles.bar, grow, chartSvgStyles.fill(item.color))), null);
|
|
168
|
+
});
|
|
169
|
+
})]);
|
|
170
|
+
}
|
|
171
|
+
/** 线的选项 */
|
|
172
|
+
/** 每个系列一条线(空值处断开) */
|
|
173
|
+
function chartLines(context, series, { curve, width }) {
|
|
174
|
+
return createVNode("g", { "data-part": "lines" }, [series.map((item) => {
|
|
175
|
+
const d = segments(context, (row) => context.valueOf(item, row)).map((part) => linePath(part.map((p) => context.point(p[0], p[1])), curve)).join("");
|
|
176
|
+
return d ? createVNode("path", mergeJsxProps({
|
|
177
|
+
"key": item.key,
|
|
178
|
+
"data-part": "line",
|
|
179
|
+
"d": d,
|
|
180
|
+
"pathLength": 1
|
|
181
|
+
}, css.attrs(chartMarkStyles.line, chartSvgStyles.stroke(item.color), chartMarkStyles.lineWidth(width))), null) : null;
|
|
182
|
+
})]);
|
|
183
|
+
}
|
|
184
|
+
/** 面积的选项 */
|
|
185
|
+
/** 每个系列一片面积,上沿描一条线;重叠时下沿是 0(或数值轴的下端),堆叠时是下面那一层 */
|
|
186
|
+
function chartAreas(context, series, { curve, stacked, opacity }) {
|
|
187
|
+
const [d0, d1] = context.domain;
|
|
188
|
+
const floor = Math.min(Math.max(0, d0), d1);
|
|
189
|
+
return createVNode("g", { "data-part": "areas" }, [series.map((item) => {
|
|
190
|
+
const stack = context.stacks.get(item.key);
|
|
191
|
+
const parts = stacked && stack ? [context.rows.map((_, index) => [
|
|
192
|
+
stack[index].low,
|
|
193
|
+
stack[index].high,
|
|
194
|
+
index
|
|
195
|
+
])] : segments(context, (row) => context.valueOf(item, row)).map((part) => part.map(([, , index]) => [
|
|
196
|
+
floor,
|
|
197
|
+
context.valueOf(item, context.rows[index]),
|
|
198
|
+
index
|
|
199
|
+
]));
|
|
200
|
+
const toPoints = (part, edge) => part.map(([low, high, index]) => context.point(context.category(context.rows[index], index), context.value(edge ? high : low)));
|
|
201
|
+
const area = parts.map((part) => areaPath(toPoints(part, 1), toPoints(part, 0), curve)).join("");
|
|
202
|
+
const top = parts.map((part) => linePath(toPoints(part, 1), curve)).join("");
|
|
203
|
+
return createVNode("g", { "key": item.key }, [createVNode("path", mergeJsxProps({
|
|
204
|
+
"data-part": "area",
|
|
205
|
+
"d": area
|
|
206
|
+
}, css.attrs(chartMarkStyles.area, chartSvgStyles.fill(item.color), chartMarkStyles.fillOpacity(opacity))), null), createVNode("path", mergeJsxProps({
|
|
207
|
+
"data-part": "line",
|
|
208
|
+
"d": top,
|
|
209
|
+
"pathLength": 1
|
|
210
|
+
}, css.attrs(chartMarkStyles.line, chartSvgStyles.stroke(item.color), chartMarkStyles.lineWidth(2))), null)]);
|
|
211
|
+
})]);
|
|
212
|
+
}
|
|
213
|
+
/** 数据点:filled 实心(描一圈表面色),hollow 空心(表面色填充、系列色描边);空值不画 */
|
|
214
|
+
function chartDots(context, series, variant) {
|
|
215
|
+
return createVNode("g", { "data-part": "dots" }, [series.flatMap((item) => context.rows.map((row, index) => {
|
|
216
|
+
const value = context.valueOf(item, row);
|
|
217
|
+
if (value === void 0) return null;
|
|
218
|
+
const [x, y] = context.point(context.category(row, index), context.value(value));
|
|
219
|
+
return createVNode("circle", mergeJsxProps({
|
|
220
|
+
"key": `${item.key}:${index}`,
|
|
221
|
+
"data-part": "dot",
|
|
222
|
+
"cx": x,
|
|
223
|
+
"cy": y,
|
|
224
|
+
"r": variant === "hollow" ? 3.5 : 4
|
|
225
|
+
}, css.attrs(chartMarkStyles.dot, variant === "hollow" ? [chartMarkStyles.hollowDot, chartSvgStyles.stroke(item.color)] : [chartMarkStyles.filledDot, chartSvgStyles.fill(item.color)])), null);
|
|
226
|
+
}))]);
|
|
227
|
+
}
|
|
228
|
+
//#endregion
|
|
229
|
+
export { chartAreas, chartBar, chartBars, chartDots, chartLines, chartMarkStyles };
|
|
230
|
+
|
|
231
|
+
//# sourceMappingURL=marks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marks.js","names":["_createVNode","_mergeProps"],"sources":["../../src/charts/marks.tsx"],"sourcesContent":["/**\n * 直角坐标图表的图形:柱(分组、堆叠)、线、面积、数据点。柱状图、折线图、面积图、组合图、瀑布图按需组合,\n * 坐标都从 XYChartContext 换算(横向时类目在纵轴)。\n *\n * render: (context) => [chartAreas(context, series, { curve: 'monotone' }), chartDots(context, series, 'hollow')]\n *\n * 进场:柱从基线长出来、线从左往右描出、面积与点淡入,时长取主题的 lg(“减少动态效果”时为 0);\n * 用 @starting-style,只在图形第一次出现时播放,数据更新时原地变。\n */\nimport { css, type SxStyles } from '@zerodep-dev/vue-tsx-pro-tsx/styles';\nimport type { VNodeChild } from 'vue';\nimport { t } from '../config/theme/tokens';\nimport { chartSvgStyles } from './plot';\nimport type { ResolvedSeries } from './series';\nimport {\n areaPath,\n barPath,\n linePath,\n type BarEnd,\n type ChartPoint,\n type LineCurves,\n} from './shape';\nimport { stackValues, type StackSegment } from './stack';\nimport type { XYChartContext } from './XYChart';\n\nconst enter = `${t.durations.lg} ${t.easings.standard}`;\n\n/** 图形的样式 */\nexport const chartMarkStyles = css.create({\n // 柱:从基线那一端长出来\n bar: {\n transformBox: 'fill-box',\n transition: `scale ${enter}, opacity ${t.durations.sm} ${t.easings.standard}`,\n },\n growUp: { transformOrigin: 'bottom', scale: { default: '1', '@starting-style': '1 0' } },\n growDown: { transformOrigin: 'top', scale: { default: '1', '@starting-style': '1 0' } },\n growRight: { transformOrigin: 'left', scale: { default: '1', '@starting-style': '0 1' } },\n growLeft: { transformOrigin: 'right', scale: { default: '1', '@starting-style': '0 1' } },\n // 线:pathLength 归一成 1,虚线的偏移从 1 到 0,看起来是从头描到尾\n line: {\n fill: 'none',\n strokeLinejoin: 'round',\n strokeLinecap: 'round',\n strokeDasharray: '1',\n strokeDashoffset: { default: 0, '@starting-style': 1 },\n transition: `stroke-dashoffset ${t.durations.xl} ${t.easings.standard}`,\n pointerEvents: 'none',\n },\n area: {\n stroke: 'none',\n pointerEvents: 'none',\n opacity: { default: 1, '@starting-style': 0 },\n transition: `opacity ${enter}`,\n },\n dot: {\n transformBox: 'fill-box',\n transformOrigin: 'center',\n scale: { default: '1', '@starting-style': '0' },\n transition: `scale ${enter}`,\n pointerEvents: 'none',\n },\n hollowDot: { fill: '_surface', strokeWidth: 2 },\n filledDot: { stroke: '_surface', strokeWidth: 1.5 },\n lineWidth: (width: number) => ({ strokeWidth: width }),\n fillOpacity: (opacity: number) => ({ fillOpacity: opacity }),\n});\n\n/** 一行上一个系列的点:[类目坐标, 数值坐标];空值处断开成几段 */\nfunction segments<T extends object>(\n context: XYChartContext<T>,\n value: (row: T, index: number) => number | undefined,\n): [number, number, number][][] {\n const result: [number, number, number][][] = [];\n let current: [number, number, number][] = [];\n context.rows.forEach((row, index) => {\n const v = value(row, index);\n if (v === undefined) {\n if (current.length) result.push(current);\n current = [];\n return;\n }\n current.push([context.category(row, index), context.value(v), index]);\n });\n if (current.length) result.push(current);\n return result;\n}\n\n/** 柱的选项 */\nexport interface ChartBarOptions {\n /** 堆叠 */\n stacked?: boolean;\n /** 柱末端的圆角(px) */\n radius: number;\n /** 一组柱占一格的比例,默认分组 0.7、堆叠 0.6 */\n fill?: number;\n /** 一组柱最宽多少(px),默认分组 96、堆叠 48 */\n maxWidth?: number;\n}\n\n/** 柱末端朝哪边:正值朝上(横向朝右),负值反过来 */\nfunction endOf(horizontal: boolean, negative: boolean): BarEnd {\n if (horizontal) return negative ? 'left' : 'right';\n return negative ? 'bottom' : 'top';\n}\n\n/** 一根柱:类目方向上从 start 起宽 width,数值方向上从 low 到 high */\nexport function chartBar<T extends object>(\n context: XYChartContext<T>,\n {\n start,\n width,\n low,\n high,\n radius,\n round,\n down,\n }: {\n start: number;\n width: number;\n low: number;\n high: number;\n radius: number;\n /** 末端是圆角 */\n round: boolean;\n /** 朝下(横向时朝左)长:末端在 low 那一头;不写时按正负(负值朝下) */\n down?: boolean;\n },\n): { d: string; grow: SxStyles } {\n const negative = down ?? (high <= 0 && low < 0);\n const [a, b] = [context.value(low), context.value(high)];\n const end = round ? endOf(context.horizontal, negative) : 'none';\n const d = context.horizontal\n ? barPath(Math.min(a, b), start, Math.abs(b - a), width, radius, end)\n : barPath(start, Math.min(a, b), width, Math.abs(b - a), radius, end);\n const grow = context.horizontal\n ? negative\n ? chartMarkStyles.growLeft\n : chartMarkStyles.growRight\n : negative\n ? chartMarkStyles.growDown\n : chartMarkStyles.growUp;\n return { d, grow };\n}\n\n/** 分组(并排)或堆叠的柱:每根柱带 data-index(第几行),点击下钻按它找行 */\nexport function chartBars<T extends object>(\n context: XYChartContext<T>,\n series: readonly ResolvedSeries<T>[],\n { stacked = false, radius, fill, maxWidth }: ChartBarOptions,\n): VNodeChild {\n if (!series.length) return null;\n const groupWidth = Math.min(\n context.step * (fill ?? (stacked ? 0.6 : 0.7)),\n maxWidth ?? (stacked ? 48 : 96),\n );\n const values = series.map((item) => context.rows.map((row) => context.valueOf(item, row)));\n const stacks: StackSegment[][] = stacked ? stackValues(values) : [];\n // 堆叠时只给每一摞最外面的一段圆角(正负各一)\n const outermost = (index: number, negative: boolean) => {\n for (let s = series.length - 1; s >= 0; s -= 1) {\n const value = values[s]![index];\n if (value !== undefined && value !== 0 && value < 0 === negative) return s;\n }\n return -1;\n };\n const barWidth = stacked ? groupWidth : groupWidth / (series.length + (series.length - 1) * 0.1);\n return (\n <g data-part=\"bars\">\n {context.rows.flatMap((row, index) => {\n const groupStart = context.category(row, index) - groupWidth / 2;\n return series.map((item, s) => {\n const value = values[s]![index];\n if (value === undefined || value === 0) return null;\n const segment = stacked\n ? stacks[s]![index]!\n : { low: Math.min(0, value), high: Math.max(0, value) };\n const { d, grow } = chartBar(context, {\n start: stacked ? groupStart : groupStart + s * barWidth * 1.1,\n width: barWidth,\n low: segment.low,\n high: segment.high,\n radius,\n round: !stacked || outermost(index, value < 0) === s,\n });\n return (\n <path\n key={`${item.key}:${index}`}\n data-part=\"bar\"\n data-index={index}\n d={d}\n {...css.attrs(chartMarkStyles.bar, grow, chartSvgStyles.fill(item.color))}\n />\n );\n });\n })}\n </g>\n );\n}\n\n/** 线的选项 */\nexport interface ChartLineOptions {\n /** 曲线 */\n curve: keyof LineCurves;\n /** 线宽(px) */\n width: number;\n}\n\n/** 每个系列一条线(空值处断开) */\nexport function chartLines<T extends object>(\n context: XYChartContext<T>,\n series: readonly ResolvedSeries<T>[],\n { curve, width }: ChartLineOptions,\n): VNodeChild {\n return (\n <g data-part=\"lines\">\n {series.map((item) => {\n const parts = segments(context, (row) => context.valueOf(item, row));\n const d = parts\n .map((part) =>\n linePath(\n part.map((p) => context.point(p[0], p[1])),\n curve,\n ),\n )\n .join('');\n return d ? (\n <path\n key={item.key}\n data-part=\"line\"\n d={d}\n pathLength={1}\n {...css.attrs(\n chartMarkStyles.line,\n chartSvgStyles.stroke(item.color),\n chartMarkStyles.lineWidth(width),\n )}\n />\n ) : null;\n })}\n </g>\n );\n}\n\n/** 面积的选项 */\nexport interface ChartAreaOptions {\n /** 曲线 */\n curve: keyof LineCurves;\n /** 堆叠:用 context.stacks 里的上下沿 */\n stacked: boolean;\n /** 面积的不透明度 */\n opacity: number;\n}\n\n/** 每个系列一片面积,上沿描一条线;重叠时下沿是 0(或数值轴的下端),堆叠时是下面那一层 */\nexport function chartAreas<T extends object>(\n context: XYChartContext<T>,\n series: readonly ResolvedSeries<T>[],\n { curve, stacked, opacity }: ChartAreaOptions,\n): VNodeChild {\n const [d0, d1] = context.domain;\n const floor = Math.min(Math.max(0, d0), d1);\n return (\n <g data-part=\"areas\">\n {series.map((item) => {\n const stack = context.stacks.get(item.key);\n // 堆叠时空值是 0 厚度(面积连续);重叠时空值处断开\n const parts =\n stacked && stack\n ? [\n context.rows.map(\n (_, index) => [stack[index]!.low, stack[index]!.high, index] as const,\n ),\n ]\n : segments(context, (row) => context.valueOf(item, row)).map((part) =>\n part.map(\n ([, , index]) =>\n [floor, context.valueOf(item, context.rows[index]!)!, index] as const,\n ),\n );\n const toPoints = (part: readonly (readonly [number, number, number])[], edge: 0 | 1) =>\n part.map(([low, high, index]): ChartPoint =>\n context.point(\n context.category(context.rows[index]!, index),\n context.value(edge ? high : low),\n ),\n );\n const area = parts\n .map((part) => areaPath(toPoints(part, 1), toPoints(part, 0), curve))\n .join('');\n const top = parts.map((part) => linePath(toPoints(part, 1), curve)).join('');\n return (\n <g key={item.key}>\n <path\n data-part=\"area\"\n d={area}\n {...css.attrs(\n chartMarkStyles.area,\n chartSvgStyles.fill(item.color),\n chartMarkStyles.fillOpacity(opacity),\n )}\n />\n <path\n data-part=\"line\"\n d={top}\n pathLength={1}\n {...css.attrs(\n chartMarkStyles.line,\n chartSvgStyles.stroke(item.color),\n chartMarkStyles.lineWidth(2),\n )}\n />\n </g>\n );\n })}\n </g>\n );\n}\n\n/** 数据点:filled 实心(描一圈表面色),hollow 空心(表面色填充、系列色描边);空值不画 */\nexport function chartDots<T extends object>(\n context: XYChartContext<T>,\n series: readonly ResolvedSeries<T>[],\n variant: 'filled' | 'hollow',\n): VNodeChild {\n return (\n <g data-part=\"dots\">\n {series.flatMap((item) =>\n context.rows.map((row, index) => {\n const value = context.valueOf(item, row);\n if (value === undefined) return null;\n const [x, y] = context.point(context.category(row, index), context.value(value));\n return (\n <circle\n key={`${item.key}:${index}`}\n data-part=\"dot\"\n cx={x}\n cy={y}\n r={variant === 'hollow' ? 3.5 : 4}\n {...css.attrs(\n chartMarkStyles.dot,\n variant === 'hollow'\n ? [chartMarkStyles.hollowDot, chartSvgStyles.stroke(item.color)]\n : [chartMarkStyles.filledDot, chartSvgStyles.fill(item.color)],\n )}\n />\n );\n }),\n )}\n </g>\n );\n}\n"],"mappings":"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"}
|