@publishfx/publish-chart 2.1.6 → 2.1.8

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,3 +1,21 @@
1
+ **2.1.8** feat(chart): 柱状、折线、组合图的节点单独传递
2
+ - 2026-03-04T11:59:34+08:00 [feat(chart): 柱状、折线、组合图的节点单独传递](http://lf.git.oa.mt/publish_platform/web/publish/commit/5ef7b6c79b51438f7ae49edce74e060e5ffbd595)
3
+ - 2026-03-04T11:45:15+08:00 [fix(chart): 将node信息单独传递](http://lf.git.oa.mt/publish_platform/web/publish/commit/20b4209876bd464ff63674480eb3a308e7007a02)
4
+ - 2026-03-04T00:58:03+08:00 [fix(chart): 辅助线问题统一修复](http://lf.git.oa.mt/publish_platform/web/publish/commit/c40294f244ee7d8036ed1e92594b5e51980b55d0)
5
+ - 2026-03-04T00:18:41+08:00 [fix(chart): 辅助线scale统一设置为key:main](http://lf.git.oa.mt/publish_platform/web/publish/commit/67bf1b6913dd301aa3f1d840909e53bd6c6efcb2)
6
+ - 2026-03-03T23:26:48+08:00 [fix(chart): 组合图对比时间color设置修改](http://lf.git.oa.mt/publish_platform/web/publish/commit/3835d8c1ddc7937550daf45122f335f678e0730b)
7
+ - 2026-03-03T23:01:20+08:00 [fix(chart): inset边距去掉](http://lf.git.oa.mt/publish_platform/web/publish/commit/b96fec0d5939c9836caf5f8ceb51a988410d5e28)
8
+ - 2026-03-03T21:37:11+08:00 [feat(chart): 折线图图例根据indicators排序](http://lf.git.oa.mt/publish_platform/web/publish/commit/2d366548ba1aa170659f9c645f95045f4f510924)
9
+
10
+ **2.1.7** fix(chart): 修复折线图有空数据的异常场景
11
+ - 2026-03-03T17:50:03+08:00 [fix(chart): 修复折线图有空数据的异常场景](http://lf.git.oa.mt/publish_platform/web/publish/commit/3465ede843d4fb156932871cdf042315dbb17096)
12
+ - 2026-03-03T17:38:27+08:00 [fix(chart): 组合图柱数据缺失问题优化](http://lf.git.oa.mt/publish_platform/web/publish/commit/fa55e35a7569b9e7000d2c4dc5d09eee3b60bfff)
13
+ - 2026-03-03T17:35:16+08:00 [fix: tserror](http://lf.git.oa.mt/publish_platform/web/publish/commit/995efdbe45391ecdb06ef6838c65d9bc87c33efa)
14
+ - 2026-03-03T17:28:25+08:00 [feat: 去掉element:click](http://lf.git.oa.mt/publish_platform/web/publish/commit/5bb84001d505392306f4dfd8300e7d21f47fe95b)
15
+ - 2026-03-03T17:26:42+08:00 [fix: 折线图点击无法下钻](http://lf.git.oa.mt/publish_platform/web/publish/commit/5395a60b96d9db398d5a4c5c8610481cbba8362a)
16
+ - 2026-03-03T16:36:31+08:00 [fix: label缩略时要设置minLength](http://lf.git.oa.mt/publish_platform/web/publish/commit/b11ff5ff52376442f3a9b057b942f0d47c4f9ee5)
17
+ - 2026-03-03T14:19:39+08:00 [feat(chart): 组合图排序代码整理](http://lf.git.oa.mt/publish_platform/web/publish/commit/baab4ed6bbd0a3bac46fccb1d3875af241368770)
18
+
1
19
  **2.1.6** fix(chart): 解决ts错误
2
20
  - 2026-03-03T06:38:38+08:00 [fix(chart): 解决ts错误](http://lf.git.oa.mt/publish_platform/web/publish/commit/a1a61c8cbfede6e0993a1101dd4f375ad3383302)
3
21
  - 2026-03-03T06:30:33+08:00 [fix(chart): 修复所有遗留问题](http://lf.git.oa.mt/publish_platform/web/publish/commit/73456fbb6fe853fc9069e2c6712851375dd372da)
@@ -106,7 +106,7 @@ class DataAdapter {
106
106
  if (config.y) dv.transform({
107
107
  type: 'map',
108
108
  callback: (row)=>{
109
- row[config.y] = '' !== row[config.y] ? +row[config.y] : '-';
109
+ row[config.y] = '' !== row[config.y] && '-' !== row[config.y] && null !== row[config.y] ? +row[config.y] : '-';
110
110
  return row;
111
111
  }
112
112
  });
@@ -158,10 +158,15 @@ class DataAdapter {
158
158
  });
159
159
  const xKey = config.x ?? 'x';
160
160
  const sortData = tdv.rows.map((item)=>item[xKey]);
161
- if (config.isDescend) combinedv.rows.sort((a, b)=>sortData.indexOf(a[xKey]) - sortData.indexOf(b[xKey]));
162
- else combinedv.rows.sort((a, b)=>sortData.indexOf(a[xKey]) - sortData.indexOf(b[xKey]));
161
+ combinedv.rows.sort((a, b)=>{
162
+ const aIndex = sortData.indexOf(a[xKey]);
163
+ const bIndex = sortData.indexOf(b[xKey]);
164
+ if (-1 === aIndex) return 1;
165
+ if (-1 === bIndex) return -1;
166
+ return aIndex - bIndex;
167
+ });
163
168
  }
164
- console.log('renderG2CombineChart transformedData:leftData:', tdv.rows, 'rightData:', combinedv.rows);
169
+ console.log('leftData:', tdv.rows, 'rightData:', combinedv.rows);
165
170
  return {
166
171
  transformedData: dv.rows,
167
172
  leftData: tdv.rows,
@@ -50,6 +50,7 @@ const G2BarChart = ({ height = 300, data, x = "", y = "", indicatorMap, onChartC
50
50
  contextConfig.nodeMap
51
51
  ]);
52
52
  console.log("transformedData: bar final", transformedData);
53
+ const nodeData = transformedData.filter((item)=>item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0);
53
54
  const maxY = useMemo(()=>{
54
55
  const values = transformedData.filter((item)=>"-" !== item[safeY] && void 0 !== item[safeY] && null !== item[safeY]).map((item)=>Number(item[safeY]) || 0);
55
56
  const dataMax = values.length > 0 ? Math.max(...values) : 0;
@@ -110,6 +111,7 @@ const G2BarChart = ({ height = 300, data, x = "", y = "", indicatorMap, onChartC
110
111
  }
111
112
  const chart = renderG2BarChart(containerRef.current, {
112
113
  data: filteredData,
114
+ nodeData,
113
115
  x,
114
116
  y: safeY,
115
117
  maxY,
@@ -149,7 +151,7 @@ const G2BarChart = ({ height = 300, data, x = "", y = "", indicatorMap, onChartC
149
151
  },
150
152
  auxiliaryLineData: auxiliaryLineData ?? [],
151
153
  onNodeListChange: (nodes)=>{
152
- console.log("g2bar node list:", nodes, nodes[0], nodes[1]);
154
+ console.log("g2bar node list:", nodes);
153
155
  setXYList(nodes);
154
156
  },
155
157
  timeRange,
@@ -11,6 +11,7 @@ import useG2TooltipContainer from "../shared/useG2TooltipContainer.js";
11
11
  import { getIndicatorCompareName } from "../../../utils/indicatorHelpers.js";
12
12
  import { renderG2CombineChart } from "./g2combine.js";
13
13
  import { G2BarLegend } from "./G2BarLegend.js";
14
+ import { sortByIndicators } from "./g2Helpers.js";
14
15
  const transformDataToGroupBarLineFormat = (data, x = "groupName", y = "", indicators)=>{
15
16
  if (!data || 0 === data.length) return [];
16
17
  return data.map((item)=>{
@@ -109,6 +110,7 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
109
110
  isDescend
110
111
  ]);
111
112
  console.log("G2CombineChart transformedData:", transformedData, leftData, rightData);
113
+ const nodeData = transformedData.filter((item)=>item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0);
112
114
  const { maxY } = useMemo(()=>{
113
115
  const key = isGroupRef.current ? "total" : safeY;
114
116
  const yValues = transformedData.filter((item)=>"-" !== item[key] && void 0 !== item[key] && null !== item[key]).map((item)=>Number(item[key]) || 0);
@@ -134,8 +136,9 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
134
136
  return;
135
137
  }
136
138
  const groupTypes = Array.from(new Set(transformedData.map((d)=>d.groupType.replace("_compare", "") + "_" + d.isCombine).filter((v)=>null != v)));
137
- const lineGroupTypeArr = groupTypes.filter((v)=>"true" === v.split("_")[1]);
138
- const items = groupTypes.map((id, index)=>{
139
+ const sortedGroupTypes = sortByIndicators(groupTypes, indicators);
140
+ const lineGroupTypeArr = sortedGroupTypes.filter((v)=>"true" === v.split("_")[1]);
141
+ const items = sortedGroupTypes.map((id, index)=>{
139
142
  const colorIndex = index;
140
143
  const indicatorId = id.split("_")[0];
141
144
  const isCombine = "true" === id.split("_")[1];
@@ -160,7 +163,8 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
160
163
  }, [
161
164
  transformedData,
162
165
  safeIndicatorMap,
163
- themeColors
166
+ themeColors,
167
+ indicators
164
168
  ]);
165
169
  const filterLeftData = useMemo(()=>{
166
170
  if (!activeIds.length) return leftData;
@@ -202,6 +206,7 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
202
206
  console.log("canvasMarginBottom:", canvasMarginBottom);
203
207
  const chart = renderG2CombineChart(containerRef.current, {
204
208
  data: filteredData,
209
+ nodeData,
205
210
  x,
206
211
  y: safeY,
207
212
  z,
@@ -7,6 +7,7 @@ import { DataAdapter } from "../../../adapters/DataAdapter.js";
7
7
  import { NodePopover } from "../../shared/NodePopover.js";
8
8
  import { NodeDetail } from "../../shared/NodeDetail.js";
9
9
  import { transformIndicatorList } from "../../../utils/dataTransform.js";
10
+ import { sortByIndicators } from "./g2Helpers.js";
10
11
  import G2CompareTooltip from "../shared/G2CompareTooltip.js";
11
12
  import useG2TooltipContainer from "../shared/useG2TooltipContainer.js";
12
13
  import { getIndicatorCompareName } from "../../../utils/indicatorHelpers.js";
@@ -31,6 +32,7 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
31
32
  const [legendItems, setLegendItems] = useState([]);
32
33
  const containerRef = useRef(null);
33
34
  const chartRef = useRef(null);
35
+ const currentTooltipTitleRef = useRef(null);
34
36
  const [viewWidth, setViewWidth] = useState(0);
35
37
  const [viewOffset, setViewOffset] = useState(0);
36
38
  const transformedData = useMemo(()=>{
@@ -51,6 +53,8 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
51
53
  dataTransform,
52
54
  contextConfig.nodeMap
53
55
  ]);
56
+ const nodeData = transformedData.filter((item)=>item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0);
57
+ console.log('nodeData:', nodeData);
54
58
  const { minY, maxY } = useMemo(()=>{
55
59
  const dataValues = transformedData.filter((item)=>"-" !== item[safeY] && void 0 !== item[safeY] && null !== item[safeY]).map((item)=>Number(item[safeY]));
56
60
  const compareValues = transformedData.filter((item)=>"-" !== item["subGroupValue"] && null != item["subGroupValue"]).map((item)=>Number(item["subGroupValue"]));
@@ -83,7 +87,8 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
83
87
  return;
84
88
  }
85
89
  const groupTypes = Array.from(new Set(transformedData.map((d)=>d.groupType).filter((v)=>null != v)));
86
- const items = groupTypes.map((id, index)=>{
90
+ const sortedGroupTypes = sortByIndicators(groupTypes, indicators);
91
+ const items = sortedGroupTypes.map((id, index)=>{
87
92
  const colorIndex = isCompare ? Math.floor(index / 2) : index;
88
93
  return {
89
94
  id: String(id),
@@ -104,7 +109,8 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
104
109
  }, [
105
110
  transformedData,
106
111
  safeIndicatorMap,
107
- themeColors
112
+ themeColors,
113
+ indicators
108
114
  ]);
109
115
  const filteredData = useMemo(()=>{
110
116
  if (!activeIds.length) return transformedData;
@@ -123,6 +129,7 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
123
129
  console.log("G2LineChart", x, y, minY, maxY);
124
130
  const chart = renderG2LineChart(containerRef.current, {
125
131
  data: filteredData,
132
+ nodeData,
126
133
  x,
127
134
  y: safeY,
128
135
  minY,
@@ -143,6 +150,7 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
143
150
  } : void 0,
144
151
  height: height - canvasMarginBottom,
145
152
  tooltipRender: (title, items)=>{
153
+ currentTooltipTitleRef.current = title;
146
154
  const container = tooltipContainerRef.current;
147
155
  if (!container) return null;
148
156
  let safeItems = items.map((i)=>({
@@ -174,15 +182,18 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
174
182
  }
175
183
  });
176
184
  chartRef.current = chart;
177
- if (onChartClick) chart.on("element:click", (e)=>{
178
- const datum = e.data?.data;
179
- if (datum) onChartClick({
180
- title: datum[x]
181
- });
185
+ if (onChartClick) chart.on("plot:click", (_e)=>{
186
+ const tooltipTitle = currentTooltipTitleRef.current;
187
+ if (null != tooltipTitle) {
188
+ console.log('使用 tooltip title 触发下钻:', tooltipTitle);
189
+ onChartClick({
190
+ title: tooltipTitle
191
+ });
192
+ }
182
193
  });
183
194
  return ()=>{
184
195
  if (chartRef.current) {
185
- chartRef.current.off("element:click");
196
+ chartRef.current.off("plot:click");
186
197
  chartRef.current.off("element:mouseenter");
187
198
  chartRef.current.off("element:mouseleave");
188
199
  chartRef.current.destroy();
@@ -194,6 +194,7 @@ export declare function getMainView(chart: Chart): import("@antv/g2/lib/api/exte
194
194
  'composition.view': any;
195
195
  }>;
196
196
  export interface ScaleYLinearOptions {
197
+ key?: string;
197
198
  field?: string;
198
199
  domainMin?: number;
199
200
  domainMax?: number;
@@ -296,4 +297,13 @@ export interface GetColorByGroupTypeOptions {
296
297
  */
297
298
  export declare function getColorByGroupType(groupType: string, options: GetColorByGroupTypeOptions): string;
298
299
  export declare function applyHighlightDate(view: any, x: string, data: any, highlightDate: string[], isHighlight: boolean): void;
300
+ export declare function applyNodeData(view: any, nodeData: any[], x: string, y: string): {
301
+ pointP: {
302
+ x: number;
303
+ y: number;
304
+ };
305
+ pointData: any;
306
+ color: string;
307
+ }[];
299
308
  export declare function adjustDomainMax(domainMin: number, domainMax: number): number;
309
+ export declare const sortByIndicators: (arr: string[], indicators: string[]) => string[];
@@ -14,7 +14,7 @@ function getMainView(chart) {
14
14
  return layer.view();
15
15
  }
16
16
  function applyScaleYLinear(view, options = {}) {
17
- const { field = 'y', domainMin = 0, domainMax, nice = true, clamp = true, tickCount = 5, minLimit, maxLimit, tickMethod } = options;
17
+ const { field = 'y', domainMin = 0, domainMax, nice = true, clamp = true, tickCount = 5, minLimit, maxLimit, tickMethod, key } = options;
18
18
  view.scale({
19
19
  [field]: {
20
20
  type: 'linear',
@@ -25,6 +25,7 @@ function applyScaleYLinear(view, options = {}) {
25
25
  clamp,
26
26
  nice,
27
27
  tickCount,
28
+ key,
28
29
  ...null != minLimit && {
29
30
  minLimit
30
31
  },
@@ -76,6 +77,7 @@ function applyAxisX(mark, options = {}) {
76
77
  size: isHorizontal ? Math.floor(containerWidth / 5) : 30,
77
78
  labelAutoEllipsis: {
78
79
  type: 'ellipsis',
80
+ minLength: 80,
79
81
  maxLength: isHorizontal ? Math.floor(containerWidth / 5) : Math.min(maxLabelChars * fontSize * 0.55, 90)
80
82
  },
81
83
  labelAlign: 'horizontal',
@@ -147,18 +149,19 @@ function applyAuxiliaryLineY(view, lines, options = {}) {
147
149
  console.log('applyAuxiliaryLineY:', lines);
148
150
  const { stroke = '#F4664A', strokeOpacity = 1, labelMaxLength = 5 } = options;
149
151
  lines.forEach((auxLine)=>{
150
- view.lineY().encode('y', auxLine.value).style('stroke', stroke).style('strokeOpacity', strokeOpacity).style('lineWidth', 1).style('shadowColor', 'transparent').axis('y', {
151
- title: false,
152
- grid: false,
153
- label: false,
154
- tick: false
155
- }).label({
152
+ console.log('lines:', auxLine);
153
+ view.lineY().encode('y', auxLine.value).style('stroke', stroke).style('strokeOpacity', strokeOpacity).style('lineWidth', 1).style('shadowColor', 'transparent').scale('y', {
154
+ key: auxLine?.axis === 'right' ? 'line' : 'main'
155
+ }).axis('x', false).label({
156
156
  dx: 0,
157
- dy: -5,
158
- text: splitTextToMultiline(auxLine.name, labelMaxLength, '<br />'),
157
+ dy: 0,
158
+ text: splitTextToMultiline(auxLine.name, labelMaxLength, '\n'),
159
159
  position: auxLine?.axis === 'right' ? 'bottom-right' : 'bottom-left',
160
- style: {},
161
- render: (text)=>`<div style="background-color: transparent; padding: 5px; border-radius: 5px;font-size: 12px;position: absolute;left: -4px; top: -24px; width: 100px;color: ${stroke}; font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;">${text}</div>`
160
+ style: {
161
+ fill: stroke,
162
+ shadowColor: 'transparent',
163
+ fillOpacity: 1
164
+ }
162
165
  });
163
166
  });
164
167
  }
@@ -182,7 +185,7 @@ function applyHighlightDate(view, x, data, highlightDate, isHighlight) {
182
185
  domainMax: 100,
183
186
  independent: true
184
187
  }).tooltip(false).axis('y', {
185
- position: 'right',
188
+ position: 'top',
186
189
  title: false,
187
190
  grid: false,
188
191
  label: false,
@@ -199,16 +202,75 @@ function applyHighlightDate(view, x, data, highlightDate, isHighlight) {
199
202
  domainMax: 100,
200
203
  independent: true
201
204
  }).tooltip(true).axis('y', {
205
+ position: 'top',
202
206
  title: false,
203
207
  grid: false,
204
208
  label: false,
205
209
  tick: false
206
210
  }).style({
207
211
  stroke: 'transparent',
208
- strokeOpacity: 0
212
+ strokeOpacity: 1
209
213
  });
210
214
  }
215
+ function applyNodeData(view, nodeData, x, y) {
216
+ const nodeList = [];
217
+ nodeData.forEach((item)=>{
218
+ view.shape().data([
219
+ {
220
+ [x]: item[x],
221
+ [y]: 0
222
+ }
223
+ ]).encode('x', x).encode('y', y).tooltip(false).scale('y', {
224
+ key: 'main'
225
+ }).style({
226
+ render: ({ x: px, y: py }, context)=>{
227
+ const { document } = context;
228
+ const g = document.createElement('g', {});
229
+ const { paddingLeft = 24, marginLeft = 12 } = context?.coordinate?.options || {};
230
+ const adjustLeft = paddingLeft + marginLeft;
231
+ if (item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0) {
232
+ nodeList.push({
233
+ pointP: {
234
+ x: px + adjustLeft,
235
+ y: py
236
+ },
237
+ pointData: item.nodeInfos || {},
238
+ color: item.color
239
+ });
240
+ const c1 = document.createElement('circle', {
241
+ style: {
242
+ cx: px,
243
+ cy: py,
244
+ r: 2,
245
+ fill: 'white'
246
+ }
247
+ });
248
+ const c2 = document.createElement('circle', {
249
+ style: {
250
+ cx: px,
251
+ cy: py,
252
+ r: 5,
253
+ fill: item.color
254
+ }
255
+ });
256
+ g.appendChild(c2);
257
+ g.appendChild(c1);
258
+ }
259
+ return g;
260
+ }
261
+ });
262
+ });
263
+ return nodeList;
264
+ }
211
265
  function adjustDomainMax(domainMin, domainMax) {
212
266
  return domainMax === domainMin ? domainMin > 0 ? 1.1 * domainMax : domainMax + 1 : domainMax;
213
267
  }
214
- export { adjustDomainMax, applyAuxiliaryLineY, applyAxisX, applyAxisY, applyHighlightDate, applyLegendColor, applyScaleYLinear, createChart, getColorByGroupType, getMainView };
268
+ const sortByIndicators = (arr, indicators)=>arr.sort((a, b)=>{
269
+ const baseA = a.split('_')[0];
270
+ const baseB = b.split('_')[0];
271
+ const indexA = indicators.indexOf(baseA);
272
+ const indexB = indicators.indexOf(baseB);
273
+ if (-1 !== indexA && -1 !== indexB) return indexA - indexB;
274
+ return 0;
275
+ });
276
+ export { adjustDomainMax, applyAuxiliaryLineY, applyAxisX, applyAxisY, applyHighlightDate, applyLegendColor, applyNodeData, applyScaleYLinear, createChart, getColorByGroupType, getMainView, sortByIndicators };
@@ -3,6 +3,8 @@ import type { ChartTimeRange } from '../../../core/ChartTypes';
3
3
  export interface RenderG2BarChartOptions {
4
4
  /** 已转换后的数据:约定包含 groupName、groupType、groupValue 等字段 */
5
5
  data: any[];
6
+ /** 节点数据 */
7
+ nodeData: any[];
6
8
  /** X 轴字段,如 groupName */
7
9
  x: string;
8
10
  /** Y 轴字段,如 groupValue / cost */
@@ -1,8 +1,10 @@
1
1
  import { lines } from "@antv/g-pattern";
2
- import { applyAuxiliaryLineY, applyAxisX, applyAxisY, applyHighlightDate, applyScaleYLinear, createChart, getColorByGroupType, getMainView } from "./g2Helpers.js";
2
+ import { applyAuxiliaryLineY, applyAxisX, applyAxisY, applyHighlightDate, applyNodeData, applyScaleYLinear, createChart, getColorByGroupType, getMainView } from "./g2Helpers.js";
3
3
  const Y_AXIS_FIELD = 'groupValue';
4
+ const CLOSE_NODE_DEBUG = false;
5
+ const CLOSE_HIGHLIGHT_DEBUG = false;
4
6
  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, isClickable = false, legend, formatLabel, height = 300, tooltipRender, auxiliaryLineData = [], onNodeListChange, onChartRender } = options;
7
+ const { data, nodeData, x, y, maxY, timeRange: _timeRange, themeColors, indicators = [], indicatorMap: _indicatorMap = {}, formatAxis, highlightDate = [], isDataTag = false, isLegend = true, isHorizontal = false, isHighlight = true, isCompare = false, isClickable = false, legend, formatLabel, height = 300, tooltipRender, auxiliaryLineData = [], onNodeListChange, onChartRender } = options;
6
8
  const colorOpts = {
7
9
  themeColors,
8
10
  primaryKey: y,
@@ -30,13 +32,11 @@ function renderG2BarChart(container, options) {
30
32
  });
31
33
  view.data(data);
32
34
  applyScaleYLinear(view, {
33
- field: 'y',
34
35
  domainMin: 0,
35
36
  domainMax: maxY,
36
- nice: true,
37
- clamp: true
37
+ key: 'main'
38
38
  });
39
- applyHighlightDate(view, x, data, highlightDate, isHighlight);
39
+ if (!CLOSE_HIGHLIGHT_DEBUG) applyHighlightDate(view, x, data, highlightDate, isHighlight);
40
40
  console.log('g2bar data:', data, y);
41
41
  const interval = view.interval().encode('x', x).encode('y', y).encode('color', 'groupType').transform({
42
42
  type: 'dodgeX',
@@ -145,52 +145,11 @@ function renderG2BarChart(container, options) {
145
145
  bounding: tooltipBounding
146
146
  });
147
147
  applyAuxiliaryLineY(view, auxiliaryLineData);
148
- const nodeList = [];
149
148
  console.log('nodeList data:', data);
150
- data.forEach((item)=>{
151
- view.shape().data([
152
- {
153
- [x]: item[x],
154
- [y]: 0
155
- }
156
- ]).encode('x', x).encode('y', y).tooltip(false).style({
157
- render: ({ x: px, y: py }, context)=>{
158
- const { document } = context;
159
- const g = document.createElement('g', {});
160
- const { paddingLeft = 24, marginLeft = 12 } = context?.coordinate?.options || {};
161
- const adjustLeft = paddingLeft + marginLeft;
162
- if (item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0) {
163
- nodeList.push({
164
- pointP: {
165
- x: px + adjustLeft,
166
- y: py
167
- },
168
- pointData: item.nodeInfos || {},
169
- color: item.color
170
- });
171
- const c1 = document.createElement('circle', {
172
- style: {
173
- cx: px,
174
- cy: py,
175
- r: 2,
176
- fill: 'white'
177
- }
178
- });
179
- const c2 = document.createElement('circle', {
180
- style: {
181
- cx: px,
182
- cy: py,
183
- r: 5,
184
- fill: item.color
185
- }
186
- });
187
- g.appendChild(c2);
188
- g.appendChild(c1);
189
- }
190
- return g;
191
- }
192
- });
193
- });
149
+ if (!CLOSE_NODE_DEBUG) {
150
+ const nodeList = applyNodeData(view, nodeData, x, y);
151
+ onNodeListChange?.(nodeList);
152
+ }
194
153
  if (isDataTag && formatLabel) interval.label({
195
154
  text: (d)=>formatLabel(d),
196
155
  position: isHorizontal ? 'right' : 'top',
@@ -208,7 +167,6 @@ function renderG2BarChart(container, options) {
208
167
  let hasEmittedNodeList = false;
209
168
  chart.on('afterrender', (_e)=>{
210
169
  if (hasEmittedNodeList) return;
211
- if (onNodeListChange) onNodeListChange(nodeList);
212
170
  console.log('chart.coordinateBBox:', chart.getContext(), view.getCoordinate());
213
171
  const views = chart.getContext()?.views;
214
172
  const viewCoordinate = views?.[0]?.layout;
@@ -8,6 +8,8 @@ import { type AuxiliaryLineItem } from "./g2Helpers";
8
8
  export interface RenderG2CombineChartOptions {
9
9
  /** 已转换后的数据:约定包含 groupName、groupType、groupValue 等字段 */
10
10
  data: any[];
11
+ /** 节点数据 */
12
+ nodeData: any[];
11
13
  /** X 轴字段,如 groupName */
12
14
  x: string;
13
15
  /** 柱状图 Y 字段,如 groupValue 或某指标字段 */
@@ -1,11 +1,11 @@
1
1
  import { lines } from "@antv/g-pattern";
2
- import { applyAuxiliaryLineY, applyAxisX, applyHighlightDate, createChart, getMainView } from "./g2Helpers.js";
2
+ import { applyAuxiliaryLineY, applyAxisX, applyHighlightDate, applyNodeData, applyScaleYLinear, createChart, getMainView } from "./g2Helpers.js";
3
3
  import { getIndicatorCompareName } from "../../../utils/indicatorHelpers.js";
4
4
  const Y_AXIS_FIELD = 'groupValue';
5
5
  const BAR_Y_FIELD = 'barValue';
6
6
  const LINE_Y_FIELD = 'lineValue';
7
7
  function renderG2CombineChart(container, options) {
8
- const { data, x, y, z: _z, maxY, themeColors, indicatorMap: _indicatorMap, formatAxis, formatLineAxis, isDataTag = true, isCombineDataTag = true, isLegend: _isLegend = false, isCompare = false, formatLabel, highlightDate = [], height = 300, isHighlight = true, isClickable = false, indicators = [], tooltipRender, auxiliaryLineData = [], onNodeListChange, lineColors, onChartRender, isGroup, legendItems = [], indicatorId } = options;
8
+ const { data, nodeData, x, y, z: _z, maxY, themeColors, indicatorMap: _indicatorMap, formatAxis, formatLineAxis, isDataTag = true, isCombineDataTag = true, isLegend: _isLegend = false, isCompare = false, formatLabel, highlightDate = [], height = 300, isHighlight = true, isClickable = false, indicators = [], tooltipRender, auxiliaryLineData = [], onNodeListChange, lineColors, onChartRender, isGroup, legendItems = [], indicatorId } = options;
9
9
  const chart = createChart({
10
10
  container,
11
11
  height,
@@ -52,14 +52,15 @@ function renderG2CombineChart(container, options) {
52
52
  }).style({
53
53
  columnWidthRatio: 0.6,
54
54
  insetLeft: (_d, index, _data, _column)=>{
55
+ console.log('insetLeft:', index, isCompare);
55
56
  if (isGroup) return 0;
56
- if (isCompare) return index % 2 === 0 ? 4 : 0;
57
- return 4;
57
+ if (isCompare) return index % 2 === 0 ? 0 : 0;
58
+ return 0;
58
59
  },
59
60
  insetRight: (_d, index, _data, _column)=>{
60
61
  if (isGroup) return 0;
61
- if (isCompare) return index % 2 === 1 ? 4 : 0;
62
- return 4;
62
+ if (isCompare) return index % 2 === 1 ? 0 : 0;
63
+ return 0;
63
64
  },
64
65
  fill: (datum)=>{
65
66
  const groupType = String(datum.groupType ?? '');
@@ -81,17 +82,15 @@ function renderG2CombineChart(container, options) {
81
82
  cursor: isClickable ? 'pointer' : 'default',
82
83
  stroke: 'transparent'
83
84
  });
84
- interval.scale('y', {
85
- type: 'linear',
85
+ const chartScale = {
86
86
  domainMin: 0,
87
87
  domainMax: finalIntervalMax,
88
- nice: true,
89
- clamp: true,
90
- key: 'bar',
88
+ key: 'main',
91
89
  tickMethod: (min, max)=>Array.from({
92
90
  length: 6
93
91
  }, (_, i)=>min + (max - min) * i / 5)
94
- });
92
+ };
93
+ applyScaleYLinear(interval, chartScale);
95
94
  interval.axis('y', {
96
95
  position: 'left',
97
96
  title: false,
@@ -198,18 +197,15 @@ function renderG2CombineChart(container, options) {
198
197
  }
199
198
  ]
200
199
  });
201
- line.scale('y', {
202
- type: 'linear',
200
+ const chartSideScale = {
203
201
  domainMin: 0,
204
202
  domainMax: finalLineMax,
205
- nice: true,
206
- clamp: true,
207
203
  key: 'line',
208
- independent: true,
209
204
  tickMethod: (min, max)=>Array.from({
210
205
  length: 6
211
206
  }, (_, i)=>min + (max - min) * i / 5)
212
- });
207
+ };
208
+ applyScaleYLinear(line, chartSideScale);
213
209
  line.axis('y', {
214
210
  position: 'right',
215
211
  title: false,
@@ -266,7 +262,7 @@ function renderG2CombineChart(container, options) {
266
262
  (datum)=>datum.groupType.includes('_compare') ? {
267
263
  name: datum['groupType'].replace('_compare', '_change'),
268
264
  indicatorId: datum['groupType'].replace('_compare', ''),
269
- color: 'blue',
265
+ color: 'transparent',
270
266
  value: datum?.change,
271
267
  isChange: true,
272
268
  isCombine: true,
@@ -360,68 +356,8 @@ function renderG2CombineChart(container, options) {
360
356
  tipBoxShadow: '0 3px 6px -4px rgba(0, 0, 0, 1)'
361
357
  });
362
358
  applyAuxiliaryLineY(view, auxiliaryLineData);
363
- const nodeList = [];
364
- console.log('nodeList data:', data);
365
- data.forEach((item)=>{
366
- view.shape().data([
367
- {
368
- [x]: item[x],
369
- [y]: 0
370
- }
371
- ]).encode('x', x).encode('y', y).tooltip(false).scale('y', {
372
- key: 'node',
373
- domainMin: 0,
374
- domainMax: 1,
375
- nice: true,
376
- clamp: true
377
- }).axis('y', {
378
- grid: false,
379
- title: false,
380
- tick: false,
381
- label: false,
382
- gridStrokeOpacity: 1,
383
- gridLineDash: [
384
- 0,
385
- 0
386
- ]
387
- }).style({
388
- render: ({ x: px, y: py }, context)=>{
389
- const { document } = context;
390
- const g = document.createElement('g', {});
391
- const { paddingLeft = 24, marginLeft = 12 } = context?.coordinate?.options || {};
392
- const adjustLeft = paddingLeft + marginLeft;
393
- if (item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0) {
394
- nodeList.push({
395
- pointP: {
396
- x: px + adjustLeft,
397
- y: py
398
- },
399
- pointData: item.nodeInfos || {},
400
- color: item.color
401
- });
402
- const c1 = document.createElement('circle', {
403
- style: {
404
- cx: px,
405
- cy: py,
406
- r: 2,
407
- fill: 'white'
408
- }
409
- });
410
- const c2 = document.createElement('circle', {
411
- style: {
412
- cx: px,
413
- cy: py,
414
- r: 5,
415
- fill: item.color
416
- }
417
- });
418
- g.appendChild(c2);
419
- g.appendChild(c1);
420
- }
421
- return g;
422
- }
423
- });
424
- });
359
+ const nodeList = applyNodeData(view, nodeData, x, 'groupValue');
360
+ onNodeListChange?.(nodeList);
425
361
  if (formatLabel) {
426
362
  if (isDataTag) {
427
363
  const groupedByX = intervalData.reduce((acc, item)=>{
@@ -7,6 +7,8 @@ import { ChartTimeRange } from '../../../core/ChartTypes';
7
7
  export interface RenderG2LineChartOptions {
8
8
  /** 已转换后的数据(含 groupValue,groupType 可能带 _compare) */
9
9
  data: any[];
10
+ /** 节点数据 */
11
+ nodeData: any[];
10
12
  /** X 轴字段,如 groupName */
11
13
  x: string;
12
14
  /** 主指标 key,用于取色与图例 */
@@ -1,7 +1,7 @@
1
- import { applyAuxiliaryLineY, applyAxisX, applyAxisY, applyHighlightDate, applyScaleYLinear, createChart, getColorByGroupType, getMainView } from "./g2Helpers.js";
1
+ import { applyAuxiliaryLineY, applyAxisX, applyAxisY, applyHighlightDate, applyNodeData, applyScaleYLinear, createChart, getColorByGroupType, getMainView } from "./g2Helpers.js";
2
2
  const Y_AXIS_FIELD = 'groupValue';
3
3
  function renderG2LineChart(container, options) {
4
- const { data, x, y, minY, maxY, timeRange: _timeRange, themeColors, indicators = [], indicatorMap: _indicatorMap = {}, formatAxis, highlightDate = [], auxiliaryLineData = [], isDataTag = false, isLegend = true, isHighlight = true, formatLabel, height = 300, legendLength: _legendLength, legendSize: _legendSize, tooltipRender, onNodeListChange, onChartRender } = options;
4
+ const { data, nodeData, x, y, minY, maxY, timeRange: _timeRange, themeColors, indicators = [], indicatorMap: _indicatorMap = {}, formatAxis, highlightDate = [], auxiliaryLineData = [], isDataTag = false, isLegend = true, isHighlight = true, formatLabel, height = 300, legendLength: _legendLength, legendSize: _legendSize, tooltipRender, onNodeListChange, onChartRender } = options;
5
5
  console.log('g2line data:', data, x, y);
6
6
  const colorOpts = {
7
7
  themeColors,
@@ -23,11 +23,9 @@ function renderG2LineChart(container, options) {
23
23
  view.data(data);
24
24
  const domainMin = minY ?? 0;
25
25
  applyScaleYLinear(view, {
26
- field: 'y',
27
26
  domainMin,
28
27
  domainMax: maxY,
29
- nice: true,
30
- clamp: true
28
+ key: 'main'
31
29
  });
32
30
  applyHighlightDate(view, x, data, highlightDate, isHighlight);
33
31
  console.log('g2linets:', x, Y_AXIS_FIELD, data, indicators);
@@ -80,7 +78,8 @@ function renderG2LineChart(container, options) {
80
78
  indicatorId: datum['groupType'].replace('_compare', ''),
81
79
  value: datum?.change,
82
80
  isChange: true,
83
- color: 'transparent'
81
+ color: 'transparent',
82
+ hidden: indicators?.length > 1
84
83
  })
85
84
  ]
86
85
  });
@@ -133,52 +132,8 @@ function renderG2LineChart(container, options) {
133
132
  tipBoxShadow: '0 3px 6px -4px rgba(0, 0, 0, 1)'
134
133
  });
135
134
  applyAuxiliaryLineY(view, auxiliaryLineData);
136
- const nodeList = [];
137
- console.log('nodeList data:', data);
138
- data.forEach((item)=>{
139
- view.shape().data([
140
- {
141
- [x]: item[x],
142
- [y]: 0
143
- }
144
- ]).encode('x', x).encode('y', y).tooltip(false).style({
145
- render: ({ x: px, y: py }, context)=>{
146
- const { document } = context;
147
- const g = document.createElement('g', {});
148
- const { paddingLeft = 24, marginLeft = 12 } = context?.coordinate?.options || {};
149
- const adjustLeft = paddingLeft + marginLeft;
150
- if (item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0) {
151
- nodeList.push({
152
- pointP: {
153
- x: px + adjustLeft,
154
- y: py
155
- },
156
- pointData: item.nodeInfos || {},
157
- color: item.color
158
- });
159
- const c1 = document.createElement('circle', {
160
- style: {
161
- cx: px,
162
- cy: py,
163
- r: 2,
164
- fill: 'white'
165
- }
166
- });
167
- const c2 = document.createElement('circle', {
168
- style: {
169
- cx: px,
170
- cy: py,
171
- r: 5,
172
- fill: item.color
173
- }
174
- });
175
- g.appendChild(c2);
176
- g.appendChild(c1);
177
- }
178
- return g;
179
- }
180
- });
181
- });
135
+ const nodeList = applyNodeData(view, nodeData, x, y);
136
+ onNodeListChange?.(nodeList);
182
137
  if (isDataTag && formatLabel) {
183
138
  line.label({
184
139
  dy: -10,
@@ -6,6 +6,7 @@ type Item = {
6
6
  compareTime?: undefined | string;
7
7
  indicatorId?: string;
8
8
  percent?: string | number;
9
+ hidden?: boolean;
9
10
  };
10
11
  interface Props {
11
12
  isGroupBar?: boolean;
@@ -13,14 +13,14 @@ const G2CompareTooltip = ({ isGroupBar = false, title, items, safeIndicatorMap,
13
13
  /*#__PURE__*/ jsx("div", {
14
14
  children: title
15
15
  }),
16
- items?.map(({ color, value, isChange, compareTime, indicatorId, name, percent }, index)=>{
16
+ items?.map(({ color, value, isChange, compareTime, indicatorId, name, percent, hidden }, index)=>{
17
17
  let isFirst = false;
18
18
  if (0 === index) auxiIndicatorId = indicatorId ?? "";
19
19
  if (color && !uniqueColors.includes(color)) {
20
20
  isFirst = true;
21
21
  uniqueColors.push(color);
22
22
  }
23
- return /*#__PURE__*/ jsxs("div", {
23
+ return !hidden && /*#__PURE__*/ jsxs("div", {
24
24
  style: {
25
25
  display: "flex",
26
26
  justifyContent: "space-between",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@publishfx/publish-chart",
3
- "version": "2.1.6",
3
+ "version": "2.1.8",
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": [