@publishfx/publish-chart 2.0.3 → 2.1.1

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 (40) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/dist/adapters/DataAdapter.d.ts +7 -3
  3. package/dist/adapters/DataAdapter.js +61 -0
  4. package/dist/components/g2/base/G2BarChart.d.ts +4 -3
  5. package/dist/components/g2/base/G2BarChart.js +194 -53
  6. package/dist/components/g2/base/G2BarLegend.d.ts +17 -0
  7. package/dist/components/g2/base/G2BarLegend.js +196 -0
  8. package/dist/components/g2/base/G2CombineChart.d.ts +9 -0
  9. package/dist/components/g2/base/G2CombineChart.js +305 -0
  10. package/dist/components/g2/base/G2GroupBarChart.d.ts +9 -0
  11. package/dist/components/g2/base/G2GroupBarChart.js +227 -0
  12. package/dist/components/g2/base/G2IndicatorCardChart.d.ts +43 -0
  13. package/dist/components/g2/base/G2IndicatorCardChart.js +156 -0
  14. package/dist/components/g2/base/G2LineChart.d.ts +4 -3
  15. package/dist/components/g2/base/G2LineChart.js +207 -104
  16. package/dist/components/g2/base/G2PieChart.d.ts +9 -0
  17. package/dist/components/g2/base/G2PieChart.js +189 -0
  18. package/dist/components/g2/base/g2Helpers.d.ts +293 -0
  19. package/dist/components/g2/base/g2Helpers.js +178 -0
  20. package/dist/components/g2/base/g2bar.d.ts +64 -0
  21. package/dist/components/g2/base/g2bar.js +196 -0
  22. package/dist/components/g2/base/g2combine.d.ts +71 -0
  23. package/dist/components/g2/base/g2combine.js +322 -0
  24. package/dist/components/g2/base/g2groupbar.d.ts +69 -0
  25. package/dist/components/g2/base/g2groupbar.js +188 -0
  26. package/dist/components/g2/base/g2line.d.ts +77 -0
  27. package/dist/components/g2/base/g2line.js +194 -0
  28. package/dist/components/g2/shared/G2CompareTooltip.d.ts +23 -0
  29. package/dist/components/g2/shared/G2CompareTooltip.js +93 -0
  30. package/dist/components/g2/shared/useG2TooltipContainer.d.ts +1 -0
  31. package/dist/components/g2/shared/useG2TooltipContainer.js +16 -0
  32. package/dist/components/shared/NodeDetail.js +1 -1
  33. package/dist/components/shared/NodePopover.d.ts +1 -0
  34. package/dist/components/shared/NodePopover.js +3 -2
  35. package/dist/core/ChartTypes.d.ts +4 -0
  36. package/dist/index.d.ts +5 -0
  37. package/dist/index.js +5 -1
  38. package/dist/utils/chartHelpers.d.ts +1 -1
  39. package/dist/utils/chartHelpers.js +2 -2
  40. package/package.json +15 -13
@@ -0,0 +1,196 @@
1
+ import { lines } from "@antv/g-pattern";
2
+ import { applyAuxiliaryLineY, applyAxisX, applyAxisY, applyHighlightDate, applyScaleYLinear, createChart, getColorByGroupType, getMainView } from "./g2Helpers.js";
3
+ const Y_AXIS_FIELD = 'groupValue';
4
+ function renderG2BarChart(container, options) {
5
+ const { data, x, y, maxY, timeRange: _timeRange, themeColors, indicators = [], indicatorMap: _indicatorMap = {}, formatAxis, highlightDate = [], isDataTag = false, isLegend = true, isHorizontal = false, isHighlight = true, isCompare = false, legend, formatLabel, height = 300, tooltipRender, auxiliaryLineData = [], onNodeListChange, onChartRender } = options;
6
+ const colorOpts = {
7
+ themeColors,
8
+ primaryKey: y,
9
+ indicators
10
+ };
11
+ const chart = createChart({
12
+ container,
13
+ height,
14
+ autoFit: true
15
+ });
16
+ chart.options({
17
+ marginBottom: 0,
18
+ paddingBottom: 0,
19
+ insetBottom: 0
20
+ });
21
+ console.log('isLegend:', legend, isLegend);
22
+ const view = getMainView(chart);
23
+ view.attr('marginBottom', isLegend ? 0 : 16);
24
+ if (isHorizontal) view.coordinate({
25
+ transform: [
26
+ {
27
+ type: 'transpose'
28
+ }
29
+ ]
30
+ });
31
+ view.data(data);
32
+ applyScaleYLinear(view, {
33
+ field: 'y',
34
+ domainMin: 0,
35
+ domainMax: maxY,
36
+ nice: true,
37
+ clamp: true
38
+ });
39
+ applyHighlightDate(view, x, data, highlightDate, isHighlight);
40
+ console.log('g2bar data:', data, y);
41
+ const interval = view.interval().encode('x', x).encode('y', y).encode('color', 'groupType').transform({
42
+ type: 'dodgeX',
43
+ padding: isHorizontal ? 0.2 : 0
44
+ });
45
+ interval.style({
46
+ columnWidthRatio: 0.6,
47
+ insetLeft: (_d, index, _data, _column)=>{
48
+ if (isCompare) return index % 2 === 0 ? 4 : 0;
49
+ return 4;
50
+ },
51
+ insetRight: (_d, index, _data, _column)=>{
52
+ if (isCompare) return index % 2 === 1 ? 4 : 0;
53
+ return 4;
54
+ },
55
+ fill: (datum)=>{
56
+ const groupType = String(datum.groupType ?? '');
57
+ if (groupType.includes('_compare')) return {
58
+ image: lines({
59
+ backgroundColor: '#fff',
60
+ backgroundOpacity: 0.65,
61
+ stroke: '#6aa1ff',
62
+ lineWidth: 3,
63
+ spacing: 3
64
+ }),
65
+ repetition: 'repeat',
66
+ transform: 'rotate(-30deg)'
67
+ };
68
+ return getColorByGroupType(groupType, colorOpts);
69
+ }
70
+ });
71
+ applyAxisX(view, {
72
+ grid: false
73
+ });
74
+ applyAxisY(view, {
75
+ labelFormatter: formatAxis
76
+ });
77
+ view.legend(false);
78
+ interval.tooltip({
79
+ items: [
80
+ (datum)=>({
81
+ value: datum[Y_AXIS_FIELD],
82
+ name: datum['groupType'],
83
+ indicatorId: datum['groupType'],
84
+ channel: Y_AXIS_FIELD,
85
+ color: getColorByGroupType(datum['groupType'], colorOpts) || 'transparent'
86
+ }),
87
+ isCompare ? (datum)=>({
88
+ value: datum[Y_AXIS_FIELD],
89
+ compareTime: datum?.compareTime,
90
+ name: datum['groupType'],
91
+ indicatorId: datum['groupType'].replace('_compare', ''),
92
+ channel: Y_AXIS_FIELD,
93
+ color: getColorByGroupType(datum['groupType'], colorOpts) || 'transparent'
94
+ }) : null,
95
+ isCompare ? (datum)=>({
96
+ name: datum['groupType'].replace('_compare', '_change'),
97
+ indicatorId: datum['groupType'].replace('_compare', ''),
98
+ value: datum?.change,
99
+ isChange: true,
100
+ color: 'transparent'
101
+ }) : null
102
+ ].filter(Boolean)
103
+ });
104
+ if (tooltipRender) view.interaction('tooltip', {
105
+ shared: true,
106
+ crosshairsY: true,
107
+ wait: 100,
108
+ marker: false,
109
+ render: (_event, payload)=>{
110
+ const { title, items } = payload;
111
+ const lastIsChange = items.filter((item)=>item.isChange);
112
+ let safeItems = items;
113
+ if (lastIsChange.length > 0) safeItems = [
114
+ ...items.filter((item)=>!item.isChange),
115
+ lastIsChange[lastIsChange.length - 1]
116
+ ];
117
+ return tooltipRender(title, safeItems ?? []) ?? null;
118
+ }
119
+ });
120
+ else view.interaction('tooltip', true);
121
+ applyAuxiliaryLineY(view, auxiliaryLineData);
122
+ const nodeList = [];
123
+ console.log('nodeList data:', data);
124
+ data.forEach((item)=>{
125
+ view.shape().data([
126
+ {
127
+ [x]: item[x],
128
+ [y]: 0
129
+ }
130
+ ]).encode('x', x).encode('y', y).tooltip(false).style({
131
+ render: ({ x: px, y: py }, context)=>{
132
+ const { document } = context;
133
+ const g = document.createElement('g', {});
134
+ const { paddingLeft = 24, marginLeft = 12 } = context?.coordinate?.options || {};
135
+ const adjustLeft = paddingLeft + marginLeft;
136
+ if (item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0) {
137
+ nodeList.push({
138
+ pointP: {
139
+ x: px + adjustLeft,
140
+ y: py
141
+ },
142
+ pointData: item.nodeInfos || {},
143
+ color: item.color
144
+ });
145
+ const c1 = document.createElement('circle', {
146
+ style: {
147
+ cx: px,
148
+ cy: py,
149
+ r: 2,
150
+ fill: 'white'
151
+ }
152
+ });
153
+ const c2 = document.createElement('circle', {
154
+ style: {
155
+ cx: px,
156
+ cy: py,
157
+ r: 5,
158
+ fill: item.color
159
+ }
160
+ });
161
+ g.appendChild(c2);
162
+ g.appendChild(c1);
163
+ }
164
+ return g;
165
+ }
166
+ });
167
+ });
168
+ if (isDataTag && formatLabel) interval.label({
169
+ text: (d)=>formatLabel(d),
170
+ position: isHorizontal ? 'right' : 'top',
171
+ offset: 0,
172
+ dy: isHorizontal ? 0 : -15,
173
+ dx: isHorizontal ? 5 : 0,
174
+ textAlign: isHorizontal ? 'left' : 'center',
175
+ transform: [
176
+ {
177
+ type: 'exceedAdjust'
178
+ }
179
+ ]
180
+ });
181
+ chart.render();
182
+ let hasEmittedNodeList = false;
183
+ chart.on('afterrender', (_e)=>{
184
+ if (hasEmittedNodeList) return;
185
+ if (onNodeListChange) onNodeListChange(nodeList);
186
+ console.log('chart.coordinateBBox:', chart.getContext(), view.getCoordinate());
187
+ const views = chart.getContext()?.views;
188
+ const viewCoordinate = views?.[0]?.layout;
189
+ if (onChartRender && viewCoordinate) onChartRender({
190
+ layout: viewCoordinate
191
+ });
192
+ hasEmittedNodeList = true;
193
+ });
194
+ return chart;
195
+ }
196
+ export { renderG2BarChart };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * G2 柱状 + 折线组合图函数式 API
3
+ * 复用 G2BarChart / G2LineChart 的模式:React 负责数据与配置,G2 负责纯渲染
4
+ */
5
+ import { Chart } from "@antv/g2";
6
+ import type { ChartTimeRange, IndicatorInfo } from "../../../core/ChartTypes";
7
+ export interface RenderG2CombineChartOptions {
8
+ /** 已转换后的数据:约定包含 groupName、groupType、groupValue 等字段 */
9
+ data: any[];
10
+ /** X 轴字段,如 groupName */
11
+ x: string;
12
+ /** 柱状图 Y 字段,如 groupValue 或某指标字段 */
13
+ y: string;
14
+ /** 折线图 Y 字段,如另一指标字段 */
15
+ z: string;
16
+ /** 柱状图 Y 轴最大值 */
17
+ maxY: number;
18
+ /** 高亮日期,用于 x 轴 gridFilter */
19
+ highlightDate?: string[];
20
+ /** 主题色数组 */
21
+ themeColors: string[];
22
+ /** 指标映射表 */
23
+ indicatorMap: Record<string, IndicatorInfo>;
24
+ /** 柱状 Y 轴格式化 */
25
+ formatAxis: (val: any) => string;
26
+ /** 折线图 Y 轴格式化 */
27
+ formatLineAxis: (val: any) => string;
28
+ /** 是否显示数据标签 */
29
+ isDataTag?: boolean;
30
+ /** 是否显示自定义 Legend(仅影响 React 层,G2 内部不画 legend) */
31
+ isLegend?: boolean;
32
+ /** 是否启用图例高亮 */
33
+ isHighlight?: boolean;
34
+ /** 是否启用对比期 */
35
+ isCompare?: boolean;
36
+ /** 数据标签格式化:formatLabel(datum) */
37
+ formatLabel?: (datum: any) => string;
38
+ /** 图表高度 */
39
+ height?: number;
40
+ /** 时间范围(目前仅可选,预留与对比期相关的扩展) */
41
+ timeRange?: ChartTimeRange;
42
+ /** 多指标 id 列表,用于按顺序取色 */
43
+ indicators?: string[];
44
+ /** Tooltip 自定义渲染:返回挂载的 DOM,由调用方(如 React)注入 */
45
+ tooltipRender?: (title: string, items: Array<{
46
+ color?: string;
47
+ name: string;
48
+ value: any;
49
+ isChange?: boolean;
50
+ compareTime?: string;
51
+ }>) => HTMLElement | null;
52
+ /** 将计算出的节点信息传递给外层(用于渲染 NodePopover 等) */
53
+ onNodeListChange?: (nodes: Array<{
54
+ pointP: {
55
+ x: number;
56
+ y: number;
57
+ };
58
+ pointData: any;
59
+ color: string;
60
+ }>) => void;
61
+ /** 折线图颜色 */
62
+ lineColors: string[];
63
+ /** 图表首次渲染完成后回调,用于 NodeDetail 获取绘图区宽高与偏移 */
64
+ onChartRender?: (chartProps: {
65
+ layout: any;
66
+ }) => void;
67
+ }
68
+ /**
69
+ * 在容器上渲染 G2 柱状 + 折线组合图,返回 Chart 实例便于 destroy/更新
70
+ */
71
+ export declare function renderG2CombineChart(container: HTMLElement, options: RenderG2CombineChartOptions): Chart;
@@ -0,0 +1,322 @@
1
+ import { lines } from "@antv/g-pattern";
2
+ import { applyAxisX, createChart, getMainView } from "./g2Helpers.js";
3
+ const Y_AXIS_FIELD = 'groupValue';
4
+ const BAR_Y_FIELD = 'barValue';
5
+ const LINE_Y_FIELD = 'lineValue';
6
+ function renderG2CombineChart(container, options) {
7
+ const { data, x, y, z: _z, maxY, themeColors, indicatorMap: _indicatorMap, formatAxis, formatLineAxis, isDataTag = false, isLegend: _isLegend = false, isCompare = false, formatLabel, highlightDate = [], height = 300, isHighlight = true, indicators = [], tooltipRender, onNodeListChange, lineColors, onChartRender } = options;
8
+ const chart = createChart({
9
+ container,
10
+ height,
11
+ autoFit: true
12
+ });
13
+ chart.options({
14
+ marginBottom: 0,
15
+ paddingBottom: 0,
16
+ insetBottom: 0
17
+ });
18
+ const view = getMainView(chart);
19
+ view.attr('marginBottom', 0);
20
+ console.log('renderG2CombineChart data:', data, 'maxY:', maxY, x, y, 'indicators:', indicators);
21
+ view.data(data);
22
+ applyAxisX(view, {
23
+ title: false,
24
+ grid: true,
25
+ gridStroke: '#333',
26
+ gridLineWidth: 50,
27
+ gridLineDash: [
28
+ 1000
29
+ ],
30
+ gridFilter: highlightDate.length > 0 && isHighlight ? (val)=>highlightDate.includes(val?.label) : ()=>false
31
+ });
32
+ const barColor = themeColors[0] ?? "#5B8FF9";
33
+ console.log('tooltip: themeColors:', themeColors[0], barColor);
34
+ console.log('renderG2CombineChart interval data:', data.filter((item)=>!item.isCombine));
35
+ const intervalData = data.filter((item)=>!item.isCombine).map((item)=>({
36
+ ...item,
37
+ [BAR_Y_FIELD]: item[Y_AXIS_FIELD]
38
+ }));
39
+ const intervalMaxY = intervalData.reduce((max, item)=>Math.max(max, item[BAR_Y_FIELD]), 0);
40
+ const interval = view.interval().data(intervalData).encode("x", x).encode("y", BAR_Y_FIELD).encode("color", "groupType").transform({
41
+ type: 'dodgeX'
42
+ }).style({
43
+ columnWidthRatio: 0.5,
44
+ fill: (datum)=>{
45
+ const groupType = String(datum.groupType ?? '');
46
+ if (groupType.includes('_compare')) return {
47
+ image: lines({
48
+ backgroundColor: '#fff',
49
+ backgroundOpacity: 0.65,
50
+ stroke: '#6aa1ff',
51
+ lineWidth: 3,
52
+ spacing: 3
53
+ }),
54
+ repetition: 'repeat',
55
+ transform: 'rotate(-30deg)'
56
+ };
57
+ return barColor;
58
+ },
59
+ stroke: 'transparent'
60
+ });
61
+ interval.scale('y', {
62
+ type: 'linear',
63
+ domainMin: 0,
64
+ domainMax: intervalMaxY,
65
+ nice: true,
66
+ clamp: true,
67
+ key: 'bar',
68
+ tickMethod: (min, max)=>Array.from({
69
+ length: 6
70
+ }, (_, i)=>min + (max - min) * i / 5)
71
+ });
72
+ interval.axis('y', {
73
+ position: 'left',
74
+ title: false,
75
+ grid: true,
76
+ gridStrokeOpacity: 0.2,
77
+ gridLineWidth: 1,
78
+ tickOpacity: 0,
79
+ gridLineDash: [
80
+ 0,
81
+ 0
82
+ ],
83
+ labelFormatter: formatAxis
84
+ });
85
+ console.log('tooltip:', barColor, isCompare);
86
+ interval.tooltip({
87
+ items: [
88
+ (datum)=>datum.groupType.includes('_compare') ? false : {
89
+ value: datum[BAR_Y_FIELD],
90
+ name: datum['groupType'],
91
+ indicatorId: datum['groupType'],
92
+ channel: Y_AXIS_FIELD,
93
+ color: barColor || 'transparent'
94
+ },
95
+ isCompare ? (datum)=>datum.groupType.includes('_compare') ? {
96
+ value: datum[BAR_Y_FIELD],
97
+ compareTime: datum?.compareTime,
98
+ name: datum['groupType'],
99
+ indicatorId: datum['groupType'].replace('_compare', ''),
100
+ channel: Y_AXIS_FIELD,
101
+ color: barColor || 'transparent'
102
+ } : false : false,
103
+ isCompare ? (datum)=>datum.groupType.includes('_compare') ? {
104
+ name: datum['groupType'].replace('_compare', '_change'),
105
+ indicatorId: datum['groupType'].replace('_compare', ''),
106
+ value: datum?.change,
107
+ isChange: true,
108
+ color: 'transparent'
109
+ } : false : false
110
+ ].filter(Boolean)
111
+ });
112
+ console.log('renderG2CombineChart: line data:', data.filter((item)=>item.isCombine));
113
+ const lineData = data.filter((item)=>item.isCombine && !item.groupType.includes('_compare')).map((item)=>({
114
+ ...item,
115
+ [LINE_Y_FIELD]: item[Y_AXIS_FIELD]
116
+ }));
117
+ const compareLineData = data.filter((item)=>item.isCombine && item.groupType.includes('_compare')).map((item)=>({
118
+ ...item,
119
+ [LINE_Y_FIELD]: item[Y_AXIS_FIELD]
120
+ }));
121
+ const lineMaxY = lineData.reduce((max, item)=>Math.max(max, item[LINE_Y_FIELD]), 0);
122
+ const compareLineMaxY = compareLineData.reduce((max, item)=>Math.max(max, item[LINE_Y_FIELD]), 0);
123
+ const lineFinalMaxY = Math.max(lineMaxY, compareLineMaxY);
124
+ console.log('lineFinalMaxY:', lineFinalMaxY);
125
+ const line = view.line().data(lineData).encode("x", x).encode("y", LINE_Y_FIELD).encode('color', 'groupType').style({
126
+ lineWidth: 2,
127
+ stroke: (datum)=>{
128
+ const groupType = String(datum[0]?.groupType ?? '');
129
+ const color = lineColors[indicators.slice(1).indexOf(String(groupType)) ?? 0];
130
+ return color;
131
+ }
132
+ });
133
+ line.tooltip({
134
+ items: [
135
+ (datum)=>({
136
+ value: datum[LINE_Y_FIELD],
137
+ name: datum['groupType'],
138
+ indicatorId: datum['groupType'],
139
+ channel: Y_AXIS_FIELD,
140
+ color: lineColors[indicators.slice(1).indexOf(String(datum['groupType'])) ?? 0] || 'transparent'
141
+ })
142
+ ]
143
+ });
144
+ line.scale('y', {
145
+ type: 'linear',
146
+ domainMin: 0,
147
+ domainMax: lineFinalMaxY,
148
+ nice: true,
149
+ clamp: true,
150
+ key: 'bar',
151
+ independent: true,
152
+ tickMethod: (min, max)=>Array.from({
153
+ length: 6
154
+ }, (_, i)=>min + (max - min) * i / 5)
155
+ });
156
+ line.axis('y', {
157
+ position: 'right',
158
+ title: false,
159
+ grid: true,
160
+ gridStrokeOpacity: 0 === intervalMaxY ? 0.2 : 0,
161
+ gridLineWidth: 1,
162
+ gridLineDash: [
163
+ 0,
164
+ 0
165
+ ],
166
+ tickOpacity: 0,
167
+ labelFormatter: formatLineAxis
168
+ });
169
+ console.log('renderG2CombineChart: compare line data:', compareLineData);
170
+ const compareLine = view.line().data(compareLineData).encode('x', x).encode('y', LINE_Y_FIELD).encode('color', 'groupType').style({
171
+ lineDash: [
172
+ 4,
173
+ 4
174
+ ],
175
+ lineWidth: 2,
176
+ stroke: (datum, index)=>{
177
+ const groupType = String(datum[0]?.groupType ?? '');
178
+ const color = lineColors[indicators.slice(1).indexOf(String(groupType.replace('_compare', ''))) ?? 0];
179
+ console.log('compareLine: 222', 'index:', index, 'indicators:', indicators, 'datum:', datum, 'groupType:', groupType, 'color:', color);
180
+ return color ?? 'transparent';
181
+ }
182
+ });
183
+ compareLine.scale('y', {
184
+ key: 'line'
185
+ });
186
+ compareLine.axis('y', false);
187
+ const hasCompareData = data.some((item)=>item.groupType.includes('_compare'));
188
+ console.log('hasCompareData:', hasCompareData, data);
189
+ if (hasCompareData) compareLine.tooltip({
190
+ items: [
191
+ (datum)=>({
192
+ value: datum[LINE_Y_FIELD],
193
+ compareTime: datum?.compareTime,
194
+ name: datum['groupType'],
195
+ indicatorId: datum['groupType'].replace('_compare', ''),
196
+ channel: Y_AXIS_FIELD,
197
+ color: lineColors[indicators.slice(1).indexOf(String(datum['groupType'])) ?? 0] || 'transparent'
198
+ }),
199
+ (datum)=>({
200
+ name: datum['groupType'].replace('_compare', '_change'),
201
+ indicatorId: datum['groupType'].replace('_compare', ''),
202
+ value: datum?.change,
203
+ isChange: true,
204
+ color: 'transparent'
205
+ })
206
+ ]
207
+ });
208
+ if (tooltipRender) line.interaction('tooltip', {
209
+ shared: true,
210
+ crosshairsY: true,
211
+ marker: false,
212
+ render: (_event, payload)=>{
213
+ const { title, items } = payload;
214
+ console.log('tooltipRender:', title, items, indicators);
215
+ if (indicators.length) {
216
+ const groupedItems = indicators.map((indicator)=>items.filter((i)=>i.indicatorId === String(indicator)));
217
+ console.log(groupedItems.flat(), 'tooltip groupedItems');
218
+ const sortedItems = groupedItems.map((group)=>[
219
+ group.filter((i)=>i.name === i.indicatorId),
220
+ group.filter((i)=>i.compareTime),
221
+ group.filter((i)=>i.name.includes('_change'))
222
+ ].filter(Boolean).flat()).flat();
223
+ console.log(sortedItems, 'tooltip sortedItems');
224
+ const formatItems = sortedItems.map((item)=>({
225
+ ...item,
226
+ color: lineColors[indicators.slice(1).indexOf(String(item?.indicatorId)) ?? 0] || barColor || 'transparent'
227
+ }));
228
+ return tooltipRender(title, formatItems ?? []) ?? null;
229
+ }
230
+ }
231
+ });
232
+ view.legend(false);
233
+ const nodeList = [];
234
+ console.log('nodeList data:', data);
235
+ data.forEach((item)=>{
236
+ view.shape().data([
237
+ {
238
+ [x]: item[x],
239
+ [y]: 0
240
+ }
241
+ ]).encode('x', x).encode('y', y).tooltip(false).scale('y', {
242
+ key: 'node',
243
+ domainMin: 0,
244
+ domainMax: 1,
245
+ nice: true,
246
+ clamp: true
247
+ }).axis('y', {
248
+ grid: false,
249
+ title: false,
250
+ tick: false,
251
+ label: false,
252
+ gridStrokeOpacity: 1,
253
+ gridLineDash: [
254
+ 0,
255
+ 0
256
+ ]
257
+ }).style({
258
+ render: ({ x: px, y: py }, context)=>{
259
+ const { document } = context;
260
+ const g = document.createElement('g', {});
261
+ const { paddingLeft = 24, marginLeft = 12 } = context?.coordinate?.options || {};
262
+ const adjustLeft = paddingLeft + marginLeft;
263
+ if (item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0) {
264
+ nodeList.push({
265
+ pointP: {
266
+ x: px + adjustLeft,
267
+ y: py
268
+ },
269
+ pointData: item.nodeInfos || {},
270
+ color: item.color
271
+ });
272
+ const c1 = document.createElement('circle', {
273
+ style: {
274
+ cx: px,
275
+ cy: py,
276
+ r: 2,
277
+ fill: 'white'
278
+ }
279
+ });
280
+ const c2 = document.createElement('circle', {
281
+ style: {
282
+ cx: px,
283
+ cy: py,
284
+ r: 5,
285
+ fill: item.color
286
+ }
287
+ });
288
+ g.appendChild(c2);
289
+ g.appendChild(c1);
290
+ }
291
+ return g;
292
+ }
293
+ });
294
+ });
295
+ if (isDataTag && formatLabel) {
296
+ interval.label({
297
+ dy: -10,
298
+ dx: -10,
299
+ offset: 0,
300
+ text: (d)=>formatLabel(d)
301
+ });
302
+ line.label({
303
+ dy: -10,
304
+ dx: -10,
305
+ offset: 0,
306
+ text: (d)=>formatLabel(d)
307
+ });
308
+ }
309
+ chart.render();
310
+ let hasEmittedNodeList = false;
311
+ chart.on('afterrender', ()=>{
312
+ if (hasEmittedNodeList) return;
313
+ if (onNodeListChange) onNodeListChange(nodeList);
314
+ const viewLayout = chart.getContext()?.views?.[0]?.layout;
315
+ if (onChartRender && viewLayout) onChartRender({
316
+ layout: viewLayout
317
+ });
318
+ hasEmittedNodeList = true;
319
+ });
320
+ return chart;
321
+ }
322
+ export { renderG2CombineChart };
@@ -0,0 +1,69 @@
1
+ import { type AuxiliaryLineItem } from './g2Helpers';
2
+ import type { ChartTimeRange } from '../../../core/ChartTypes';
3
+ export interface RenderG2BarChartOptions {
4
+ /** 已转换后的数据:约定包含 groupName、groupType、groupValue 等字段 */
5
+ data: any[];
6
+ /** X 轴字段,如 groupName */
7
+ x: string;
8
+ /** Y 轴字段,如 groupValue / cost */
9
+ y: string;
10
+ /** Y 轴最大值,用于 scale domainMax */
11
+ maxY: number;
12
+ /** 时间范围(用于对比期图例文案) */
13
+ timeRange?: ChartTimeRange;
14
+ /** 主题色数组 */
15
+ themeColors: string[];
16
+ /** 多指标 id 列表,用于按顺序取色 */
17
+ indicators?: string[];
18
+ /** 指标名映射,图例与 Tooltip 展示 */
19
+ indicatorMap?: Record<string, {
20
+ indicatorName?: string;
21
+ }>;
22
+ /** Y 轴刻度格式化 */
23
+ formatAxis?: (val: any) => string;
24
+ /** 高亮日期,用于 x 轴 gridFilter */
25
+ highlightDate?: string[];
26
+ /** 是否显示数据标签 */
27
+ isDataTag?: boolean;
28
+ /** 是否显示图例(当有 legend 字段时) */
29
+ isLegend?: boolean;
30
+ /** 是否横向展示 */
31
+ isHorizontal?: boolean;
32
+ /** 是否启用图例高亮 */
33
+ isHighlight?: boolean;
34
+ /** 图例字段名(与 y 不同时表示分组柱),通常为 groupType */
35
+ isCompare?: boolean;
36
+ legend?: string;
37
+ /** 数据标签格式化:formatLabel(datum) */
38
+ formatLabel?: (datum: any) => string;
39
+ /** 图表高度 */
40
+ height?: number;
41
+ /** Tooltip 自定义渲染:返回挂载的 DOM */
42
+ tooltipRender?: (title: string, items: Array<{
43
+ color?: string;
44
+ name: string;
45
+ value: any;
46
+ }>) => HTMLElement | null;
47
+ /** 辅助线 */
48
+ auxiliaryLineData?: AuxiliaryLineItem[];
49
+ /** 将计算出的节点信息传递给外层(用于渲染 NodePopover 等) */
50
+ onNodeListChange?: (nodes: Array<{
51
+ pointP: {
52
+ x: number;
53
+ y: number;
54
+ };
55
+ pointData: any;
56
+ color: string;
57
+ }>) => void;
58
+ /** 图例项列表(用于 tooltip 取色与文案) */
59
+ legendItems?: Array<{
60
+ id: string;
61
+ [key: string]: any;
62
+ }>;
63
+ /** 当前指标 id(用于 tooltip 展示) */
64
+ indicatorId?: string;
65
+ }
66
+ /**
67
+ * 在容器上渲染 G2 柱状图,返回 Chart 实例便于 destroy/更新
68
+ */
69
+ export declare function renderG2GroupBarChart(container: HTMLElement, options: RenderG2BarChartOptions): any;