@publishfx/publish-chart 2.1.1 → 2.1.3

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/CHANGELOG.md CHANGED
@@ -1,4 +1,13 @@
1
- **2.1.1** feat(chart): 柱状图支持crossharisY
1
+ **2.1.3** fix(chart): 组合图分组时inset置为0
2
+ - 2026-02-28T23:48:20+08:00 [fix(chart): 组合图分组时inset置为0](http://lf.git.oa.mt/publish_platform/web/publish/commit/047e02d3cfbce21101277f48e904864163b2a02c)
3
+ - 2026-02-28T22:42:20+08:00 [feat(chart): 组合图tooltip数据调整](http://lf.git.oa.mt/publish_platform/web/publish/commit/f79461050699b0755c8837e26b035083ec980cf1)
4
+ - 2026-02-28T20:42:35+08:00 [feat(chart): 组合图默认值](http://lf.git.oa.mt/publish_platform/web/publish/commit/97613e165dc16ff1d415e01facafa11db4125a24)
5
+ - 2026-02-28T20:42:08+08:00 [feat(chart): 组合图tooltips](http://lf.git.oa.mt/publish_platform/web/publish/commit/910af4376c2149ed44816d3eae4a3188f2601f54)
6
+ - 2026-02-28T20:31:15+08:00 [feat(chart): 组合图增加着重日功能](http://lf.git.oa.mt/publish_platform/web/publish/commit/f88ce5905022454d3ac611cd16de73f6ae8c8d12)
7
+ - 2026-02-28T20:08:16+08:00 [feat(chart): 设置着重interval的ratio为0.6](http://lf.git.oa.mt/publish_platform/web/publish/commit/057cb33eabe87d077b46b6271eea63a5e2879640)
8
+ - 2026-02-28T20:02:39+08:00 [fix(chart): 修复组合图的ts错误](http://lf.git.oa.mt/publish_platform/web/publish/commit/a01f19528e46ee13d39f6de85c8ffc5fa9405ec5)
9
+ - 2026-02-28T19:10:04+08:00 [feat(chart): 组合图支持分组](http://lf.git.oa.mt/publish_platform/web/publish/commit/525c1bbe47027ca3c4550adfea1c36e43c4dad34)
10
+ - 2026-02-28T18:45:52+08:00 [feat(chart): 着重日逻辑优化](http://lf.git.oa.mt/publish_platform/web/publish/commit/3d57801fccaf67f69d3c08d19cc750fa36a2fa42)
2
11
  - 2026-02-28T18:37:26+08:00 [feat(chart): 柱状图支持crossharisY](http://lf.git.oa.mt/publish_platform/web/publish/commit/b77a0932f1710144915d209c0186640bafdff492)
3
12
 
4
13
  **2.1.1** feat(chart): 柱状图支持crossharisY
@@ -1,5 +1,5 @@
1
1
  export interface TransformConfig {
2
- type: 'bar' | 'groupBar' | 'line' | 'barLine' | 'groupCompare';
2
+ type: 'bar' | 'groupBar' | 'line' | 'barLine' | 'groupBarLine' | 'groupCompare';
3
3
  x?: string;
4
4
  y?: string;
5
5
  z?: string;
@@ -30,6 +30,10 @@ export declare class DataAdapter {
30
30
  * 柱状折线组合图数据转换
31
31
  */
32
32
  private static transformForBarLine;
33
+ /**
34
+ * 分组柱状折线组合图数据转换
35
+ */
36
+ private static transformForGroupBarLine;
33
37
  /**
34
38
  * 分组对比图数据转换
35
39
  */
@@ -11,6 +11,8 @@ class DataAdapter {
11
11
  return this.transformForLine(data, config);
12
12
  case 'barLine':
13
13
  return this.transformForBarLine(data, config);
14
+ case 'groupBarLine':
15
+ return this.transformForGroupBarLine(data, config);
14
16
  case 'groupCompare':
15
17
  return this.transformForGroupCompare(data, config);
16
18
  default:
@@ -33,7 +35,7 @@ class DataAdapter {
33
35
  callback: (a, b)=>{
34
36
  if ('-' === a[config.y]) return config.isHorizontal ? -1 : 1;
35
37
  if ('-' === b[config.y]) return config.isHorizontal ? 1 : -1;
36
- return config.isHorizontal ? a[config.y] - b[config.y] : b[config.y] - a[config.y];
38
+ return b[config.y] - a[config.y];
37
39
  }
38
40
  });
39
41
  }
@@ -129,6 +131,71 @@ class DataAdapter {
129
131
  });
130
132
  return dv.rows;
131
133
  }
134
+ static transformForGroupBarLine(data, config) {
135
+ const ds = new lib();
136
+ const dv = ds.createView().source(data);
137
+ const tdv = ds.createView().source(data);
138
+ if (config.y && config.x) {
139
+ dv.transform({
140
+ type: 'map',
141
+ callback: (row)=>{
142
+ row[config.y] = '' !== row[config.y] ? +row[config.y] : '-';
143
+ return row;
144
+ }
145
+ });
146
+ tdv.transform({
147
+ type: 'map',
148
+ callback: (row)=>{
149
+ row[config.y] = '' !== row[config.y] ? +row[config.y] : '-';
150
+ return row;
151
+ }
152
+ });
153
+ tdv.transform({
154
+ type: 'filter',
155
+ callback (row) {
156
+ return !row.isCombine;
157
+ }
158
+ });
159
+ tdv.transform({
160
+ type: 'filter',
161
+ callback (row) {
162
+ return !row[config.y] || '-' !== row[config.y];
163
+ }
164
+ });
165
+ tdv.transform({
166
+ type: 'aggregate',
167
+ fields: [
168
+ config.y
169
+ ],
170
+ groupBy: [
171
+ config.x
172
+ ],
173
+ operations: [
174
+ 'sum'
175
+ ],
176
+ as: [
177
+ 'total'
178
+ ]
179
+ });
180
+ tdv.transform({
181
+ type: 'sort',
182
+ callback (a, b) {
183
+ return b.total - a.total;
184
+ }
185
+ });
186
+ const xKey = config.x ?? 'x';
187
+ const sortData = tdv.rows.map((item)=>item[xKey]);
188
+ if (config.isDescend) dv.transform({
189
+ type: 'sort',
190
+ callback (a, b) {
191
+ if (-1 === sortData.indexOf(a[xKey])) return 1;
192
+ if (-1 === sortData.indexOf(b[xKey])) return -1;
193
+ return sortData.indexOf(a[xKey]) - sortData.indexOf(b[xKey]);
194
+ }
195
+ });
196
+ }
197
+ return dv.rows;
198
+ }
132
199
  static transformForGroupCompare(data, _config) {
133
200
  return data;
134
201
  }
@@ -60,18 +60,26 @@ const lineColors = [
60
60
  const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap, onChartClick, legend = "", config, nodeSetting = {
61
61
  showType: 0,
62
62
  type: []
63
- }, indicators = [], auxiliaryLineData, highlightDate, timeRange })=>{
63
+ }, indicators = [], auxiliaryLineData, highlightDate, timeRange, isGroup })=>{
64
64
  const { formatter, dataTransform, config: contextConfig } = useChartContext();
65
65
  const tooltipContainerRef = useG2TooltipContainer();
66
- console.log("G2CombineChart props:", data, x, y, z, indicatorMap, indicators, legend, config, nodeSetting);
66
+ console.log("G2CombineChart props:", data, x, y, z, indicators, legend, config, nodeSetting);
67
67
  const themeColors = contextConfig?.theme?.colors || [];
68
68
  const safeIndicatorMap = indicatorMap || contextConfig.indicatorMap || {};
69
- const safeLegend = "groupType" !== legend ? legend || y : y;
69
+ const safeLegend = useMemo(()=>{
70
+ if (isGroup) return legend || 'groupType';
71
+ if ("groupType" === legend) return y;
72
+ return legend || y;
73
+ }, [
74
+ isGroup,
75
+ legend,
76
+ y
77
+ ]);
70
78
  const safeZ = z;
71
79
  const safeY = "groupValue";
72
80
  const isCompare = timeRange?.compareStartTime !== "";
73
81
  const chartConfig = config || {};
74
- const { isDataTag = false, isLegend = true } = chartConfig;
82
+ const { isDataTag = false, isLegend = true, isDescend = false } = chartConfig;
75
83
  const [xyList, setXYList] = useState([]);
76
84
  const [activeIds, setActiveIds] = useState([]);
77
85
  const [legendItems, setLegendItems] = useState([]);
@@ -81,7 +89,12 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
81
89
  data = result;
82
90
  }
83
91
  console.log("G2CombineChart transformedData2:", data);
84
- const result = DataAdapter.transform(data, "barLine", {
92
+ const result = isGroup ? DataAdapter.transform(data, "groupBarLine", {
93
+ type: "barLine",
94
+ x,
95
+ y: safeY,
96
+ isDescend
97
+ }) : DataAdapter.transform(data, "barLine", {
85
98
  type: "barLine",
86
99
  x,
87
100
  y: safeY,
@@ -89,6 +102,7 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
89
102
  });
90
103
  return result.map((item)=>dataTransform.processNodeInfo(item, contextConfig.nodeMap));
91
104
  }, [
105
+ isGroup,
92
106
  data,
93
107
  x,
94
108
  safeY,
@@ -98,11 +112,13 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
98
112
  ]);
99
113
  console.log("G2CombineChart transformedData:", transformedData);
100
114
  const { maxY } = useMemo(()=>{
101
- const yValues = transformedData.filter((item)=>"-" !== item[safeY] && void 0 !== item[safeY] && null !== item[safeY]).map((item)=>Number(item[safeY]) || 0);
115
+ const key = isGroup ? "total" : safeY;
116
+ const yValues = transformedData.filter((item)=>"-" !== item[key] && void 0 !== item[key] && null !== item[key]).map((item)=>Number(item[key]) || 0);
102
117
  return {
103
118
  maxY: yValues.length > 0 ? Math.max(...yValues) : 0
104
119
  };
105
120
  }, [
121
+ isGroup,
106
122
  transformedData,
107
123
  safeY
108
124
  ]);
@@ -121,21 +137,25 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
121
137
  return;
122
138
  }
123
139
  const groupTypes = Array.from(new Set(transformedData.map((d)=>d.groupType.replace("_compare", "") + "_" + d.isCombine).filter((v)=>null != v)));
140
+ const lineGroupTypeArr = groupTypes.filter((v)=>"true" === v.split("_")[1]);
124
141
  const items = groupTypes.map((id, index)=>{
125
142
  const colorIndex = index;
126
143
  const indicatorId = id.split("_")[0];
127
- const color = 0 === colorIndex ? themeColors[colorIndex] : lineColors[colorIndex - 1];
144
+ const isCombine = "true" === id.split("_")[1];
145
+ const lineGroupTypeIndex = lineGroupTypeArr.indexOf(id);
146
+ const color = isGroup ? isCombine ? lineColors[lineGroupTypeIndex] || lineColors[0] : themeColors[colorIndex] || themeColors[0] : 0 === colorIndex ? themeColors[colorIndex] : lineColors[colorIndex - 1];
128
147
  return {
129
148
  id,
130
- label: getIndicatorCompareName(safeIndicatorMap, String(indicatorId)) + (String(indicatorId).includes("_compare") ? `(对比时间:${timeRange?.compareStartTime}~${timeRange?.compareEndTime})` : ""),
149
+ label: isGroup ? isCombine ? getIndicatorCompareName(safeIndicatorMap, String(indicatorId)) : indicatorId : getIndicatorCompareName(safeIndicatorMap, String(indicatorId)) + (String(indicatorId).includes("_compare") ? `(对比时间:${timeRange?.compareStartTime}~${timeRange?.compareEndTime})` : ""),
131
150
  color,
132
151
  isCompare: String(indicatorId).includes("_compare"),
133
- symbol: 0 === colorIndex ? "square" : "line"
152
+ symbol: isGroup ? isCombine ? 'line' : 'square' : 0 === colorIndex ? "square" : "line"
134
153
  };
135
154
  });
136
155
  setLegendItems(items);
137
156
  if (!activeIds.length) setActiveIds(items.map((i)=>i.id));
138
157
  }, [
158
+ isGroup,
139
159
  transformedData,
140
160
  safeIndicatorMap,
141
161
  themeColors,
@@ -177,7 +197,7 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
177
197
  height: height - canvasMarginBottom,
178
198
  formatLabel: isDataTag ? (d)=>{
179
199
  const indicatorId = d.groupType.split("_")[0];
180
- return "-" === formatter.formatIndicator(d.groupValue, safeIndicatorMap[indicatorId]) ? "" : formatter.formatIndicator(d.groupValue, safeIndicatorMap[indicatorId]);
200
+ return isGroup ? d.isCombine ? "-" === formatter.formatIndicator(d.groupValue, safeIndicatorMap[z]) ? "" : formatter.formatIndicator(d.groupValue, safeIndicatorMap[z]) : "-" === formatter.formatIndicator(d['total'], safeIndicatorMap[y]) ? "" : formatter.formatIndicator(d['total'], safeIndicatorMap[y]) : "-" === formatter.formatIndicator(d.groupValue, safeIndicatorMap[indicatorId]) ? "" : formatter.formatIndicator(d.groupValue, safeIndicatorMap[indicatorId]);
181
201
  } : void 0,
182
202
  indicators,
183
203
  tooltipRender: (title, items)=>{
@@ -187,8 +207,9 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
187
207
  ...i,
188
208
  color: i.color ?? themeColors[0] ?? "#5B8FF9"
189
209
  }));
190
- console.log("safeItems:", safeItems);
210
+ safeItems = safeItems.filter((i)=>i.indicatorId);
191
211
  react_dom.render(/*#__PURE__*/ jsx(G2CompareTooltip, {
212
+ isGroupBar: isGroup,
192
213
  title: title,
193
214
  items: safeItems,
194
215
  safeIndicatorMap: safeIndicatorMap,
@@ -210,7 +231,10 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
210
231
  setViewOffset((layout.paddingLeft ?? 0) + (layout.marginLeft ?? 0));
211
232
  }
212
233
  },
213
- lineColors
234
+ lineColors,
235
+ isGroup,
236
+ legendItems,
237
+ indicatorId: y
214
238
  });
215
239
  chartRef.current = chart;
216
240
  if (onChartClick) chart.on("element:click", (e)=>{
@@ -237,7 +261,9 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
237
261
  safeIndicatorMap,
238
262
  formatter,
239
263
  formatAxis,
240
- onChartClick
264
+ onChartClick,
265
+ isGroup,
266
+ legendItems
241
267
  ]);
242
268
  if (!z) return /*#__PURE__*/ jsx("div", {
243
269
  style: {
@@ -153,11 +153,14 @@ function applyHighlightDate(view, x, data, highlightDate, isHighlight) {
153
153
  domainMax: 100,
154
154
  independent: true
155
155
  }).tooltip(false).axis('y', {
156
+ position: 'right',
156
157
  title: false,
157
158
  grid: false,
158
- label: false
159
+ label: false,
160
+ tick: false
159
161
  });
160
162
  highlightInterval.style({
163
+ columnWidthRatio: 0.6,
161
164
  fill: '#cccccc',
162
165
  fillOpacity: isHighlight ? 0.3 : 0
163
166
  });
@@ -169,7 +172,8 @@ function applyHighlightDate(view, x, data, highlightDate, isHighlight) {
169
172
  }).tooltip(true).axis('y', {
170
173
  title: false,
171
174
  grid: false,
172
- label: false
175
+ label: false,
176
+ tick: false
173
177
  }).style({
174
178
  stroke: 'transparent',
175
179
  strokeOpacity: 0
@@ -45,10 +45,12 @@ function renderG2BarChart(container, options) {
45
45
  interval.style({
46
46
  columnWidthRatio: 0.6,
47
47
  insetLeft: (_d, index, _data, _column)=>{
48
+ if (isHorizontal) return 0;
48
49
  if (isCompare) return index % 2 === 0 ? 4 : 0;
49
50
  return 4;
50
51
  },
51
52
  insetRight: (_d, index, _data, _column)=>{
53
+ if (isHorizontal) return 0;
52
54
  if (isCompare) return index % 2 === 1 ? 4 : 0;
53
55
  return 4;
54
56
  },
@@ -64,6 +64,15 @@ export interface RenderG2CombineChartOptions {
64
64
  onChartRender?: (chartProps: {
65
65
  layout: any;
66
66
  }) => void;
67
+ /** 是否为分组柱状(影响 legend / tooltip 文案) */
68
+ isGroup?: boolean;
69
+ /** 图例项列表(用于 tooltip 取色与文案) */
70
+ legendItems?: Array<{
71
+ id: string;
72
+ [key: string]: any;
73
+ }>;
74
+ /** 当前指标 id(用于 tooltip 展示) */
75
+ indicatorId?: string;
67
76
  }
68
77
  /**
69
78
  * 在容器上渲染 G2 柱状 + 折线组合图,返回 Chart 实例便于 destroy/更新
@@ -1,10 +1,11 @@
1
1
  import { lines } from "@antv/g-pattern";
2
- import { applyAxisX, createChart, getMainView } from "./g2Helpers.js";
2
+ import { applyAxisX, applyHighlightDate, createChart, getMainView } from "./g2Helpers.js";
3
+ import { getIndicatorCompareName } from "../../../utils/indicatorHelpers.js";
3
4
  const Y_AXIS_FIELD = 'groupValue';
4
5
  const BAR_Y_FIELD = 'barValue';
5
6
  const LINE_Y_FIELD = 'lineValue';
6
7
  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 { 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, isGroup, legendItems = [], indicatorId } = options;
8
9
  const chart = createChart({
9
10
  container,
10
11
  height,
@@ -21,28 +22,42 @@ function renderG2CombineChart(container, options) {
21
22
  view.data(data);
22
23
  applyAxisX(view, {
23
24
  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
25
+ grid: false
31
26
  });
32
27
  const barColor = themeColors[0] ?? "#5B8FF9";
33
- console.log('tooltip: themeColors:', themeColors[0], barColor);
28
+ console.log('tooltip: themeColors:', themeColors[0], barColor, isGroup);
34
29
  console.log('renderG2CombineChart interval data:', data.filter((item)=>!item.isCombine));
30
+ applyHighlightDate(view, x, data, highlightDate, isHighlight);
35
31
  const intervalData = data.filter((item)=>!item.isCombine).map((item)=>({
36
32
  ...item,
37
33
  [BAR_Y_FIELD]: item[Y_AXIS_FIELD]
38
34
  }));
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'
35
+ const intervalMaxY = intervalData.reduce((max, item)=>{
36
+ const key = isGroup ? "total" : BAR_Y_FIELD;
37
+ return Math.max(max, item[key]);
38
+ }, 0);
39
+ const interval = view.interval().data(intervalData).encode("x", x).encode("y", BAR_Y_FIELD).encode("color", "groupType").transform(isGroup ? {
40
+ type: 'stackY',
41
+ reverse: true
42
+ } : {
43
+ type: 'dodgeX',
44
+ padding: 0
42
45
  }).style({
43
- columnWidthRatio: 0.5,
46
+ columnWidthRatio: 0.6,
47
+ insetLeft: (_d, index, _data, _column)=>{
48
+ if (isGroup) return 0;
49
+ if (isCompare) return index % 2 === 0 ? 4 : 0;
50
+ return 4;
51
+ },
52
+ insetRight: (_d, index, _data, _column)=>{
53
+ if (isGroup) return 0;
54
+ if (isCompare) return index % 2 === 1 ? 4 : 0;
55
+ return 4;
56
+ },
44
57
  fill: (datum)=>{
45
58
  const groupType = String(datum.groupType ?? '');
59
+ const index = legendItems.findIndex((item)=>item.id === `${groupType}_${datum.isCombine}`);
60
+ if (isGroup) return themeColors[index % themeColors.length] ?? themeColors[0] ?? "#5B8FF9";
46
61
  if (groupType.includes('_compare')) return {
47
62
  image: lines({
48
63
  backgroundColor: '#fff',
@@ -84,13 +99,28 @@ function renderG2CombineChart(container, options) {
84
99
  });
85
100
  console.log('tooltip:', barColor, isCompare);
86
101
  interval.tooltip({
87
- items: [
102
+ items: isGroup ? [
103
+ (datum)=>{
104
+ const groupType = String(datum.groupType ?? '');
105
+ const index = legendItems.findIndex((item)=>item.id === `${groupType}_${datum.isCombine}`);
106
+ return {
107
+ value: datum[Y_AXIS_FIELD],
108
+ name: datum['groupType'],
109
+ indicatorId,
110
+ channel: Y_AXIS_FIELD,
111
+ color: themeColors[index % themeColors.length] ?? themeColors[0] ?? "#5B8FF9",
112
+ percent: `${(100 * Number(datum.percent)).toFixed(2)}%`,
113
+ isCombine: false
114
+ };
115
+ }
116
+ ].filter(Boolean) : [
88
117
  (datum)=>datum.groupType.includes('_compare') ? false : {
89
118
  value: datum[BAR_Y_FIELD],
90
119
  name: datum['groupType'],
91
120
  indicatorId: datum['groupType'],
92
121
  channel: Y_AXIS_FIELD,
93
- color: barColor || 'transparent'
122
+ color: barColor || 'transparent',
123
+ isCombine: false
94
124
  },
95
125
  isCompare ? (datum)=>datum.groupType.includes('_compare') ? {
96
126
  value: datum[BAR_Y_FIELD],
@@ -98,14 +128,16 @@ function renderG2CombineChart(container, options) {
98
128
  name: datum['groupType'],
99
129
  indicatorId: datum['groupType'].replace('_compare', ''),
100
130
  channel: Y_AXIS_FIELD,
101
- color: barColor || 'transparent'
131
+ color: barColor || 'transparent',
132
+ isCombine: false
102
133
  } : false : false,
103
134
  isCompare ? (datum)=>datum.groupType.includes('_compare') ? {
104
135
  name: datum['groupType'].replace('_compare', '_change'),
105
136
  indicatorId: datum['groupType'].replace('_compare', ''),
106
137
  value: datum?.change,
107
138
  isChange: true,
108
- color: 'transparent'
139
+ color: 'transparent',
140
+ isCombine: false
109
141
  } : false : false
110
142
  ].filter(Boolean)
111
143
  });
@@ -118,6 +150,7 @@ function renderG2CombineChart(container, options) {
118
150
  ...item,
119
151
  [LINE_Y_FIELD]: item[Y_AXIS_FIELD]
120
152
  }));
153
+ console.log('compareLineData:', compareLineData);
121
154
  const lineMaxY = lineData.reduce((max, item)=>Math.max(max, item[LINE_Y_FIELD]), 0);
122
155
  const compareLineMaxY = compareLineData.reduce((max, item)=>Math.max(max, item[LINE_Y_FIELD]), 0);
123
156
  const lineFinalMaxY = Math.max(lineMaxY, compareLineMaxY);
@@ -125,20 +158,35 @@ function renderG2CombineChart(container, options) {
125
158
  const line = view.line().data(lineData).encode("x", x).encode("y", LINE_Y_FIELD).encode('color', 'groupType').style({
126
159
  lineWidth: 2,
127
160
  stroke: (datum)=>{
161
+ const groupTypeSet = new Set(lineData.map((item)=>item.groupType));
162
+ const groupTypeArr = [
163
+ ...groupTypeSet
164
+ ];
128
165
  const groupType = String(datum[0]?.groupType ?? '');
129
- const color = lineColors[indicators.slice(1).indexOf(String(groupType)) ?? 0];
166
+ const index = groupTypeArr.findIndex((item)=>item === groupType);
167
+ const color = isGroup ? lineColors[index] || lineColors[0] : lineColors[indicators.slice(1).indexOf(String(groupType)) ?? 0];
130
168
  return color;
131
169
  }
132
170
  });
133
171
  line.tooltip({
134
172
  items: [
135
- (datum)=>({
173
+ (datum)=>{
174
+ const groupTypeSet = new Set(lineData.map((item)=>item.groupType));
175
+ const groupTypeArr = [
176
+ ...groupTypeSet
177
+ ];
178
+ const groupType = String(datum[0]?.groupType ?? '');
179
+ const index = groupTypeArr.findIndex((item)=>item === groupType);
180
+ return {
136
181
  value: datum[LINE_Y_FIELD],
137
- name: datum['groupType'],
182
+ name: isGroup ? getIndicatorCompareName(_indicatorMap, datum['groupType']) : datum['groupType'],
138
183
  indicatorId: datum['groupType'],
139
184
  channel: Y_AXIS_FIELD,
140
- color: lineColors[indicators.slice(1).indexOf(String(datum['groupType'])) ?? 0] || 'transparent'
141
- })
185
+ color: isGroup ? lineColors[index] || lineColors[0] : lineColors[indicators.slice(1).indexOf(String(datum['groupType'])) ?? 0] || 'transparent',
186
+ isCombine: true,
187
+ tipType: 'line'
188
+ };
189
+ }
142
190
  ]
143
191
  });
144
192
  line.scale('y', {
@@ -188,32 +236,45 @@ function renderG2CombineChart(container, options) {
188
236
  console.log('hasCompareData:', hasCompareData, data);
189
237
  if (hasCompareData) compareLine.tooltip({
190
238
  items: [
191
- (datum)=>({
239
+ (datum)=>datum.groupType.includes('_compare') ? {
192
240
  value: datum[LINE_Y_FIELD],
193
241
  compareTime: datum?.compareTime,
194
242
  name: datum['groupType'],
195
243
  indicatorId: datum['groupType'].replace('_compare', ''),
196
244
  channel: Y_AXIS_FIELD,
197
- color: lineColors[indicators.slice(1).indexOf(String(datum['groupType'])) ?? 0] || 'transparent'
198
- }),
199
- (datum)=>({
245
+ color: lineColors[indicators.slice(1).indexOf(String(datum['groupType'])) ?? 0] || 'transparent',
246
+ isCombine: true,
247
+ tipType: 'compareline'
248
+ } : false,
249
+ (datum)=>datum.groupType.includes('_compare') ? {
200
250
  name: datum['groupType'].replace('_compare', '_change'),
201
251
  indicatorId: datum['groupType'].replace('_compare', ''),
252
+ color: 'blue',
202
253
  value: datum?.change,
203
254
  isChange: true,
204
- color: 'transparent'
205
- })
206
- ]
255
+ isCombine: true,
256
+ tipType: 'compareline'
257
+ } : false
258
+ ].filter(Boolean)
207
259
  });
208
- if (tooltipRender) line.interaction('tooltip', {
260
+ if (tooltipRender) view.interaction('tooltip', {
209
261
  shared: true,
210
262
  crosshairsY: true,
211
263
  marker: false,
212
264
  render: (_event, payload)=>{
213
265
  const { title, items } = payload;
266
+ const baseItems = items.filter((item)=>!item.isCombine);
267
+ const combineItems = items.filter((item)=>item.isCombine);
214
268
  console.log('tooltipRender:', title, items, indicators);
269
+ if (isGroup) return tooltipRender(title, [
270
+ ...baseItems,
271
+ ...combineItems
272
+ ]) ?? null;
215
273
  if (indicators.length) {
216
- const groupedItems = indicators.map((indicator)=>items.filter((i)=>i.indicatorId === String(indicator)));
274
+ const groupedItems = indicators.map((indicator, index)=>{
275
+ if (0 === index) return items.filter((i)=>!i.isCombine).filter((i)=>i.indicatorId === String(indicator));
276
+ return items.filter((i)=>i.isCombine).filter((i)=>i.indicatorId === String(indicator));
277
+ });
217
278
  console.log(groupedItems.flat(), 'tooltip groupedItems');
218
279
  const sortedItems = groupedItems.map((group)=>[
219
280
  group.filter((i)=>i.name === i.indicatorId),
@@ -223,8 +284,9 @@ function renderG2CombineChart(container, options) {
223
284
  console.log(sortedItems, 'tooltip sortedItems');
224
285
  const formatItems = sortedItems.map((item)=>({
225
286
  ...item,
226
- color: lineColors[indicators.slice(1).indexOf(String(item?.indicatorId)) ?? 0] || barColor || 'transparent'
287
+ color: item.isCombine ? lineColors[indicators.slice(1).indexOf(String(item?.indicatorId)) ?? 0] || barColor || 'transparent' : barColor || 'transparent'
227
288
  }));
289
+ console.log(formatItems, 'tooltip formatItems');
228
290
  return tooltipRender(title, formatItems ?? []) ?? null;
229
291
  }
230
292
  }
@@ -293,11 +355,27 @@ function renderG2CombineChart(container, options) {
293
355
  });
294
356
  });
295
357
  if (isDataTag && formatLabel) {
358
+ const groupedByX = intervalData.reduce((acc, item)=>{
359
+ const key = item[x];
360
+ if (!acc[key]) acc[key] = [];
361
+ acc[key].push(item);
362
+ return acc;
363
+ }, {});
364
+ const lastItemsInEachStack = new Set();
365
+ Object.values(groupedByX).forEach((group)=>{
366
+ group.sort((a, b)=>a[y] - b[y]);
367
+ const lastItem = group[group.length - 1];
368
+ lastItemsInEachStack.add(lastItem);
369
+ });
296
370
  interval.label({
297
- dy: -10,
371
+ dy: isGroup ? -16 : -10,
298
372
  dx: -10,
299
373
  offset: 0,
300
- text: (d)=>formatLabel(d)
374
+ text: (d)=>{
375
+ if (!isGroup) return formatLabel(d);
376
+ if (lastItemsInEachStack.has(d)) return formatLabel(d);
377
+ return '';
378
+ }
301
379
  });
302
380
  line.label({
303
381
  dy: -10,
@@ -53,7 +53,8 @@ function renderG2GroupBarChart(container, options) {
53
53
  transform: 'rotate(-30deg)'
54
54
  };
55
55
  return themeColors[index % themeColors.length] ?? themeColors[0] ?? "#5B8FF9";
56
- }
56
+ },
57
+ stroke: 'transparent'
57
58
  });
58
59
  applyAxisX(view, {
59
60
  title: false,
@@ -30,10 +30,10 @@ function renderG2LineChart(container, options) {
30
30
  clamp: true
31
31
  });
32
32
  applyHighlightDate(view, x, data, highlightDate, isHighlight);
33
- console.log('g2linets:', x, Y_AXIS_FIELD, data);
34
- const line = view.line().data(data.filter((item)=>!item.groupType.includes('_compare'))).encode('x', x).encode('y', Y_AXIS_FIELD).encode('color', 'groupType').style({
33
+ console.log('g2linets:', x, Y_AXIS_FIELD, data, indicators);
34
+ const line = view.line().data(data.filter((item)=>!item.groupType.includes('_compare'))).encode('x', x).encode('y', Y_AXIS_FIELD).encode('color', 'groupType').encode('series', 'groupType').style({
35
35
  lineWidth: 2,
36
- stroke: (_datum, index)=>themeColors[index] ?? themeColors[0]
36
+ stroke: (datum)=>getColorByGroupType(datum[0]?.groupType ?? '', colorOpts)
37
37
  });
38
38
  const compareLine = view.line().data(data.filter((item)=>item.groupType.includes('_compare'))).encode('x', x).encode('y', Y_AXIS_FIELD).encode('color', 'groupType').style({
39
39
  lineDash: [
@@ -41,7 +41,7 @@ function renderG2LineChart(container, options) {
41
41
  4
42
42
  ],
43
43
  lineWidth: 2,
44
- stroke: (_datum, index)=>themeColors[index] ?? themeColors[0]
44
+ stroke: (datum)=>getColorByGroupType(datum[0]?.groupType ?? '', colorOpts)
45
45
  });
46
46
  applyAxisX(view, {
47
47
  grid: false
@@ -98,6 +98,8 @@ export interface BaseChartProps {
98
98
  auxiliaryLineData?: AuxiliaryLineData[];
99
99
  /** 高亮日期数组 */
100
100
  highlightDate?: string[];
101
+ /** 是否为分组柱状(组合图等场景) */
102
+ isGroup?: boolean;
101
103
  }
102
104
  /**
103
105
  * 业务组件 Props(可选,通过 Context 注入)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@publishfx/publish-chart",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "A React chart component library for the Publish platform, including BarChart, LineChart, BarLineChart and other visualization components",
5
5
  "type": "module",
6
6
  "keywords": [