@publishfx/publish-chart 2.1.1 → 2.1.2

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.
@@ -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:
@@ -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
  ]);
@@ -124,18 +140,20 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
124
140
  const items = groupTypes.map((id, index)=>{
125
141
  const colorIndex = index;
126
142
  const indicatorId = id.split("_")[0];
127
- const color = 0 === colorIndex ? themeColors[colorIndex] : lineColors[colorIndex - 1];
143
+ const isCombine = "true" === id.split("_")[1];
144
+ const color = isGroup ? themeColors[colorIndex] || themeColors[0] : 0 === colorIndex ? themeColors[colorIndex] : lineColors[colorIndex - 1];
128
145
  return {
129
146
  id,
130
- label: getIndicatorCompareName(safeIndicatorMap, String(indicatorId)) + (String(indicatorId).includes("_compare") ? `(对比时间:${timeRange?.compareStartTime}~${timeRange?.compareEndTime})` : ""),
147
+ label: isGroup ? isCombine ? getIndicatorCompareName(safeIndicatorMap, String(indicatorId)) : indicatorId : getIndicatorCompareName(safeIndicatorMap, String(indicatorId)) + (String(indicatorId).includes("_compare") ? `(对比时间:${timeRange?.compareStartTime}~${timeRange?.compareEndTime})` : ""),
131
148
  color,
132
149
  isCompare: String(indicatorId).includes("_compare"),
133
- symbol: 0 === colorIndex ? "square" : "line"
150
+ symbol: isGroup ? isCombine ? 'line' : 'square' : 0 === colorIndex ? "square" : "line"
134
151
  };
135
152
  });
136
153
  setLegendItems(items);
137
154
  if (!activeIds.length) setActiveIds(items.map((i)=>i.id));
138
155
  }, [
156
+ isGroup,
139
157
  transformedData,
140
158
  safeIndicatorMap,
141
159
  themeColors,
@@ -187,8 +205,9 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
187
205
  ...i,
188
206
  color: i.color ?? themeColors[0] ?? "#5B8FF9"
189
207
  }));
190
- console.log("safeItems:", safeItems);
208
+ safeItems = safeItems.filter((i)=>i.indicatorId);
191
209
  react_dom.render(/*#__PURE__*/ jsx(G2CompareTooltip, {
210
+ isGroupBar: true,
192
211
  title: title,
193
212
  items: safeItems,
194
213
  safeIndicatorMap: safeIndicatorMap,
@@ -210,7 +229,10 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
210
229
  setViewOffset((layout.paddingLeft ?? 0) + (layout.marginLeft ?? 0));
211
230
  }
212
231
  },
213
- lineColors
232
+ lineColors,
233
+ isGroup,
234
+ legendItems,
235
+ indicatorId: y
214
236
  });
215
237
  chartRef.current = chart;
216
238
  if (onChartClick) chart.on("element:click", (e)=>{
@@ -237,7 +259,9 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
237
259
  safeIndicatorMap,
238
260
  formatter,
239
261
  formatAxis,
240
- onChartClick
262
+ onChartClick,
263
+ isGroup,
264
+ legendItems
241
265
  ]);
242
266
  if (!z) return /*#__PURE__*/ jsx("div", {
243
267
  style: {
@@ -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/更新
@@ -4,7 +4,7 @@ const Y_AXIS_FIELD = 'groupValue';
4
4
  const BAR_Y_FIELD = 'barValue';
5
5
  const LINE_Y_FIELD = 'lineValue';
6
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;
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, isGroup, legendItems = [], indicatorId } = options;
8
8
  const chart = createChart({
9
9
  container,
10
10
  height,
@@ -36,13 +36,21 @@ function renderG2CombineChart(container, options) {
36
36
  ...item,
37
37
  [BAR_Y_FIELD]: item[Y_AXIS_FIELD]
38
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({
39
+ const intervalMaxY = intervalData.reduce((max, item)=>{
40
+ const key = isGroup ? "total" : BAR_Y_FIELD;
41
+ return Math.max(max, item[key]);
42
+ }, 0);
43
+ const interval = view.interval().data(intervalData).encode("x", x).encode("y", BAR_Y_FIELD).encode("color", "groupType").transform(isGroup ? {
44
+ type: 'stackY',
45
+ reverse: true
46
+ } : {
41
47
  type: 'dodgeX'
42
48
  }).style({
43
49
  columnWidthRatio: 0.5,
44
50
  fill: (datum)=>{
45
51
  const groupType = String(datum.groupType ?? '');
52
+ const index = legendItems.findIndex((item)=>item.id === `${groupType}_${datum.isCombine}`);
53
+ if (isGroup) return themeColors[index % themeColors.length] ?? themeColors[0] ?? "#5B8FF9";
46
54
  if (groupType.includes('_compare')) return {
47
55
  image: lines({
48
56
  backgroundColor: '#fff',
@@ -84,7 +92,20 @@ function renderG2CombineChart(container, options) {
84
92
  });
85
93
  console.log('tooltip:', barColor, isCompare);
86
94
  interval.tooltip({
87
- items: [
95
+ items: isGroup ? [
96
+ (datum)=>{
97
+ const groupType = String(datum.groupType ?? '');
98
+ const index = legendItems.findIndex((item)=>item.id === `${groupType}_${datum.isCombine}`);
99
+ return {
100
+ value: datum[Y_AXIS_FIELD],
101
+ name: datum['groupType'],
102
+ indicatorId,
103
+ channel: Y_AXIS_FIELD,
104
+ color: themeColors[index % themeColors.length] ?? themeColors[0] ?? "#5B8FF9",
105
+ percent: `${(100 * Number(datum.percent)).toFixed(2)}%`
106
+ };
107
+ }
108
+ ].filter(Boolean) : [
88
109
  (datum)=>datum.groupType.includes('_compare') ? false : {
89
110
  value: datum[BAR_Y_FIELD],
90
111
  name: datum['groupType'],
@@ -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,
@@ -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.2",
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": [