@publishfx/publish-chart 2.1.5 → 2.1.6

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,7 @@
1
+ **2.1.6** fix(chart): 解决ts错误
2
+ - 2026-03-03T06:38:38+08:00 [fix(chart): 解决ts错误](http://lf.git.oa.mt/publish_platform/web/publish/commit/a1a61c8cbfede6e0993a1101dd4f375ad3383302)
3
+ - 2026-03-03T06:30:33+08:00 [fix(chart): 修复所有遗留问题](http://lf.git.oa.mt/publish_platform/web/publish/commit/73456fbb6fe853fc9069e2c6712851375dd372da)
4
+
1
5
  **2.1.5** fix(chart): 修正ts错误
2
6
  - 2026-03-03T04:41:18+08:00 [fix(chart): 修正ts错误](http://lf.git.oa.mt/publish_platform/web/publish/commit/ed6bc3403d6c06d8c0cce6f0193a447d74b68a3a)
3
7
  - 2026-03-03T04:38:12+08:00 [fix(chart): 组合图代码整理](http://lf.git.oa.mt/publish_platform/web/publish/commit/6a94afb106447e54143f4a29e7d8fa24c718b321)
@@ -217,14 +217,17 @@ export declare function applyScaleYLinear(view: any, options?: ScaleYLinearOptio
217
217
  export interface ApplyAxisXOptions {
218
218
  title?: boolean;
219
219
  isHorizontal?: boolean;
220
- labelAutoHide?: 'greedy' | 'equidistant' | boolean;
221
- /** 为 true 时刻度过多会自动旋转为垂直;为 false 时保持水平,依赖 labelAutoHide 避免重叠。默认 false */
222
- labelAutoRotate?: boolean;
223
220
  grid?: boolean;
224
221
  gridStroke?: string;
225
222
  gridLineWidth?: number;
226
223
  gridLineDash?: number[];
227
224
  gridFilter?: (val: any) => boolean;
225
+ /** X 轴数据点数量,用于计算 label/tick 采样间隔 */
226
+ dataCount?: number;
227
+ /** 图表容器宽度(px),用于计算可容纳的最大标签数 */
228
+ containerWidth?: number;
229
+ /** 单个标签最大显示字符数,超出截断。默认 6 */
230
+ maxLabelChars?: number;
228
231
  }
229
232
  /** 配置 X 轴,挂载在 mark 上(如 line / interval) */
230
233
  export declare function applyAxisX(mark: any, options?: ApplyAxisXOptions): void;
@@ -37,10 +37,30 @@ function applyScaleYLinear(view, options = {}) {
37
37
  }
38
38
  });
39
39
  }
40
+ function calcAxisInterval(dataCount, containerWidth, maxLabelChars, fontSize) {
41
+ if (dataCount <= 1) return 1;
42
+ const charWidth = 0.55 * fontSize;
43
+ const ellipsisWidth = Math.min(maxLabelChars * charWidth, 90);
44
+ const slotWidth = ellipsisWidth + 8;
45
+ const plotWidth = 0.85 * containerWidth;
46
+ const maxLabels = Math.max(Math.floor(plotWidth / slotWidth), 2);
47
+ return Math.max(Math.ceil(dataCount / maxLabels), 1);
48
+ }
49
+ function createAxisFilter(type, interval, _dataCount) {
50
+ return (_datum, index)=>{
51
+ if (0 === index) return true;
52
+ return 'tick' === type ? index % interval === 0 : true;
53
+ };
54
+ }
40
55
  function applyAxisX(mark, options = {}) {
41
- const { title = false, grid = true, gridStroke = '#333', gridLineWidth = 50, gridLineDash = [
56
+ const { title = false, isHorizontal = false, grid = true, gridStroke = '#333', gridLineWidth = 50, gridLineDash = [
42
57
  1000
43
- ], gridFilter } = options;
58
+ ], gridFilter, dataCount = 0, containerWidth = 0, maxLabelChars = 30 } = options;
59
+ const fontSize = 12;
60
+ const needSampling = dataCount > 0 && containerWidth > 0;
61
+ const interval = needSampling ? calcAxisInterval(dataCount, containerWidth, maxLabelChars, fontSize) : 1;
62
+ const axisFilter = needSampling && interval > 1 ? (type)=>createAxisFilter(type, interval, dataCount) : null;
63
+ console.log('axisFilter:', interval);
44
64
  mark.axis('x', {
45
65
  title,
46
66
  grid,
@@ -51,17 +71,18 @@ function applyAxisX(mark, options = {}) {
51
71
  gridFilter
52
72
  },
53
73
  labelAutoRotate: false,
54
- labelFontSize: 12,
74
+ labelFontSize: fontSize,
55
75
  labelFontColor: '#000',
76
+ size: isHorizontal ? Math.floor(containerWidth / 5) : 30,
56
77
  labelAutoEllipsis: {
57
78
  type: 'ellipsis',
58
- maxLength: 50
79
+ maxLength: isHorizontal ? Math.floor(containerWidth / 5) : Math.min(maxLabelChars * fontSize * 0.55, 90)
59
80
  },
60
81
  labelAlign: 'horizontal',
61
- labelAutoHide: {
62
- type: 'hide',
63
- keepHeader: true,
64
- keepTail: true
82
+ labelDx: (_datum, _index, _data)=>0,
83
+ ...axisFilter && {
84
+ tickFilter: axisFilter('tick'),
85
+ labelFilter: axisFilter('label')
65
86
  }
66
87
  });
67
88
  }
@@ -20,7 +20,7 @@ function renderG2BarChart(container, options) {
20
20
  });
21
21
  console.log('isLegend:', legend, isLegend);
22
22
  const view = getMainView(chart);
23
- view.attr('marginLeft', 0).attr('marginBottom', isLegend ? 0 : 16);
23
+ view.attr('marginLeft', 0).attr('marginRight', 0).attr('marginBottom', isLegend ? 0 : 16);
24
24
  if (isHorizontal) view.coordinate({
25
25
  transform: [
26
26
  {
@@ -71,14 +71,27 @@ function renderG2BarChart(container, options) {
71
71
  },
72
72
  cursor: isClickable ? 'pointer' : 'default'
73
73
  });
74
+ const xValueCount = new Set(data.map((d)=>d[x])).size;
74
75
  applyAxisX(view, {
75
76
  grid: false,
76
- isHorizontal
77
+ isHorizontal,
78
+ dataCount: xValueCount,
79
+ containerWidth: container.clientWidth
77
80
  });
78
81
  applyAxisY(view, {
79
82
  labelFormatter: formatAxis
80
83
  });
81
84
  view.legend(false);
85
+ view.interaction('poptip', {
86
+ offsetY: -20,
87
+ offsetX: 0,
88
+ tipBackgroundColor: '#fcfcfc',
89
+ tipColor: '#333',
90
+ tipBorderRadius: '6px',
91
+ tipPadding: '10px 12px',
92
+ tipFontSize: '12px',
93
+ tipBoxShadow: '0 3px 6px -4px rgba(0, 0, 0, 1)'
94
+ });
82
95
  interval.tooltip({
83
96
  items: [
84
97
  (datum)=>({
@@ -105,11 +118,18 @@ function renderG2BarChart(container, options) {
105
118
  }) : null
106
119
  ].filter(Boolean)
107
120
  });
121
+ const tooltipBounding = {
122
+ x: 0,
123
+ y: 0,
124
+ width: container.clientWidth || container.offsetWidth,
125
+ height: height
126
+ };
108
127
  if (tooltipRender) view.interaction('tooltip', {
109
128
  shared: true,
110
129
  crosshairsY: true,
111
130
  wait: 100,
112
131
  marker: false,
132
+ bounding: tooltipBounding,
113
133
  render: (_event, payload)=>{
114
134
  const { title, items } = payload;
115
135
  const lastIsChange = items.filter((item)=>item.isChange);
@@ -121,7 +141,9 @@ function renderG2BarChart(container, options) {
121
141
  return tooltipRender(title, safeItems ?? []) ?? null;
122
142
  }
123
143
  });
124
- else view.interaction('tooltip', true);
144
+ else view.interaction('tooltip', {
145
+ bounding: tooltipBounding
146
+ });
125
147
  applyAuxiliaryLineY(view, auxiliaryLineData);
126
148
  const nodeList = [];
127
149
  console.log('nodeList data:', data);
@@ -53,7 +53,10 @@ export interface RenderG2CombineChartOptions {
53
53
  value: any;
54
54
  isChange?: boolean;
55
55
  compareTime?: string;
56
- }>) => HTMLElement | null;
56
+ }>, position?: {
57
+ left: number;
58
+ top: number;
59
+ }) => HTMLElement | null;
57
60
  /** 辅助线 */
58
61
  auxiliaryLineData?: AuxiliaryLineItem[];
59
62
  /** 将计算出的节点信息传递给外层(用于渲染 NodePopover 等) */
@@ -20,9 +20,12 @@ function renderG2CombineChart(container, options) {
20
20
  view.attr('insetLeft', 0).attr('insetRight', 0).attr('marginLeft', 0).attr('marginRight', 0).attr('marginBottom', 0);
21
21
  console.log('renderG2CombineChart data:', data, 'maxY:', maxY, x, y, 'indicators:', indicators);
22
22
  view.data(data);
23
+ const xValueCount = new Set(data.map((d)=>d[x])).size;
23
24
  applyAxisX(view, {
24
25
  title: false,
25
- grid: false
26
+ grid: false,
27
+ dataCount: xValueCount,
28
+ containerWidth: container.clientWidth
26
29
  });
27
30
  const barColor = themeColors[0] ?? "#5B8FF9";
28
31
  console.log('tooltip: themeColors:', themeColors[0], barColor, isGroup);
@@ -275,7 +278,7 @@ function renderG2CombineChart(container, options) {
275
278
  shared: true,
276
279
  crosshairsY: true,
277
280
  marker: false,
278
- render: (_event, payload)=>{
281
+ render: (event, payload)=>{
279
282
  const { title, items } = payload;
280
283
  const baseItems = items.filter((item)=>!item.isCombine);
281
284
  const combineItems = items.filter((item)=>item.isCombine);
@@ -296,13 +299,66 @@ function renderG2CombineChart(container, options) {
296
299
  };
297
300
  return typeRank(a) - typeRank(b);
298
301
  });
299
- return tooltipRender(title, [
302
+ const content = tooltipRender(title, [
300
303
  ...baseItems,
301
304
  ...sortedCombineItems
302
305
  ]) ?? null;
306
+ if (content) {
307
+ const domEvent = event?.event ?? event;
308
+ const clientX = domEvent?.clientX ?? domEvent?.x ?? 0;
309
+ const clientY = domEvent?.clientY ?? domEvent?.y ?? 0;
310
+ const rect = container.getBoundingClientRect();
311
+ const offsetX = 12;
312
+ const offsetY = 12;
313
+ const applyClamp = ()=>{
314
+ let el = content;
315
+ while(el && el.parentElement){
316
+ const p = el.parentElement;
317
+ if (p.classList?.contains('g2-tooltip')) {
318
+ el = p;
319
+ break;
320
+ }
321
+ el = p;
322
+ }
323
+ const wrapper = el && el.classList?.contains('g2-tooltip') ? el : null;
324
+ if (!wrapper) return;
325
+ const wRect = wrapper.getBoundingClientRect();
326
+ const tooltipW = wRect.width || 260;
327
+ const tooltipH = wRect.height || 300;
328
+ const minLeft = rect.left;
329
+ const maxLeft = rect.right - tooltipW;
330
+ const minTop = rect.top;
331
+ const maxTop = rect.bottom - tooltipH;
332
+ const desiredLeft = clientX + offsetX;
333
+ const desiredTop = clientY + offsetY;
334
+ const left = Math.min(Math.max(desiredLeft, minLeft), Math.max(maxLeft, minLeft));
335
+ const top = Math.min(Math.max(desiredTop, minTop), Math.max(maxTop, minTop));
336
+ wrapper.style.position = 'fixed';
337
+ wrapper.style.left = `${left}px`;
338
+ wrapper.style.top = `${top}px`;
339
+ wrapper.style.transform = 'translate(0px, 0px)';
340
+ wrapper.style.pointerEvents = 'none';
341
+ wrapper.style.zIndex = '9999';
342
+ };
343
+ try {
344
+ applyClamp();
345
+ requestAnimationFrame(applyClamp);
346
+ } catch {}
347
+ }
348
+ return content;
303
349
  }
304
350
  });
305
351
  view.legend(false);
352
+ view.interaction('poptip', {
353
+ offsetY: -20,
354
+ offsetX: 0,
355
+ tipBackgroundColor: '#fcfcfc',
356
+ tipColor: '#333',
357
+ tipBorderRadius: '6px',
358
+ tipPadding: '10px 12px',
359
+ tipFontSize: '12px',
360
+ tipBoxShadow: '0 3px 6px -4px rgba(0, 0, 0, 1)'
361
+ });
306
362
  applyAuxiliaryLineY(view, auxiliaryLineData);
307
363
  const nodeList = [];
308
364
  console.log('nodeList data:', data);
@@ -56,9 +56,12 @@ function renderG2GroupBarChart(container, options) {
56
56
  },
57
57
  stroke: 'transparent'
58
58
  });
59
+ const xValueCount = new Set(data.map((d)=>d[x])).size;
59
60
  applyAxisX(view, {
60
61
  title: false,
61
- grid: false
62
+ grid: false,
63
+ dataCount: xValueCount,
64
+ containerWidth: container.clientWidth
62
65
  });
63
66
  applyAxisY(view, {
64
67
  title: false,
@@ -70,6 +73,7 @@ function renderG2GroupBarChart(container, options) {
70
73
  labelFormatter: formatAxis
71
74
  });
72
75
  view.legend(false);
76
+ view.interaction('poptip', true);
73
77
  interval.tooltip({
74
78
  items: [
75
79
  (datum)=>{
@@ -86,20 +90,38 @@ function renderG2GroupBarChart(container, options) {
86
90
  }
87
91
  ].filter(Boolean)
88
92
  });
89
- if (tooltipRender) interval.interaction('tooltip', {
90
- shared: true,
91
- render: (_event, payload)=>{
92
- const { title, items } = payload;
93
- const lastIsChange = items.filter((item)=>item.isChange);
94
- let safeItems = items;
95
- if (lastIsChange.length > 0) safeItems = [
96
- ...items.filter((item)=>!item.isChange),
97
- lastIsChange[lastIsChange.length - 1]
98
- ];
99
- return tooltipRender(title, safeItems ?? []) ?? null;
100
- }
101
- });
102
- else view.interaction('tooltip', true);
93
+ if (tooltipRender) {
94
+ const tooltipBounding = {
95
+ x: 0,
96
+ y: 0,
97
+ width: container.clientWidth || container.offsetWidth,
98
+ height: height
99
+ };
100
+ interval.interaction('tooltip', {
101
+ shared: true,
102
+ bounding: tooltipBounding,
103
+ render: (_event, payload)=>{
104
+ const { title, items } = payload;
105
+ const lastIsChange = items.filter((item)=>item.isChange);
106
+ let safeItems = items;
107
+ if (lastIsChange.length > 0) safeItems = [
108
+ ...items.filter((item)=>!item.isChange),
109
+ lastIsChange[lastIsChange.length - 1]
110
+ ];
111
+ return tooltipRender(title, safeItems ?? []) ?? null;
112
+ }
113
+ });
114
+ } else {
115
+ const tooltipBounding = {
116
+ x: 0,
117
+ y: 0,
118
+ width: container.clientWidth || container.offsetWidth,
119
+ height: height
120
+ };
121
+ view.interaction('tooltip', {
122
+ bounding: tooltipBounding
123
+ });
124
+ }
103
125
  applyAuxiliaryLineY(view, auxiliaryLineData);
104
126
  const nodeList = [];
105
127
  console.log('nodeList data:', data);
@@ -43,8 +43,11 @@ function renderG2LineChart(container, options) {
43
43
  lineWidth: 2,
44
44
  stroke: (datum)=>getColorByGroupType(datum[0]?.groupType ?? '', colorOpts)
45
45
  });
46
+ const xValueCount = new Set(data.map((d)=>d[x])).size;
46
47
  applyAxisX(view, {
47
- grid: false
48
+ grid: false,
49
+ dataCount: xValueCount,
50
+ containerWidth: container.clientWidth
48
51
  });
49
52
  applyAxisY(view, {
50
53
  labelFormatter: formatAxis
@@ -81,9 +84,16 @@ function renderG2LineChart(container, options) {
81
84
  })
82
85
  ]
83
86
  });
87
+ const tooltipBounding = {
88
+ x: 0,
89
+ y: 0,
90
+ width: container.clientWidth || container.offsetWidth,
91
+ height: height
92
+ };
84
93
  if (tooltipRender) view.interaction('tooltip', {
85
94
  shared: true,
86
95
  marker: false,
96
+ bounding: tooltipBounding,
87
97
  render: (_event, payload)=>{
88
98
  const { title, items } = payload;
89
99
  console.log('tooltipRender:', title, items, indicators);
@@ -112,6 +122,16 @@ function renderG2LineChart(container, options) {
112
122
  }
113
123
  });
114
124
  view.legend(false);
125
+ view.interaction('poptip', {
126
+ offsetY: -20,
127
+ offsetX: 0,
128
+ tipBackgroundColor: '#fcfcfc',
129
+ tipColor: '#333',
130
+ tipBorderRadius: '6px',
131
+ tipPadding: '10px 12px',
132
+ tipFontSize: '12px',
133
+ tipBoxShadow: '0 3px 6px -4px rgba(0, 0, 0, 1)'
134
+ });
115
135
  applyAuxiliaryLineY(view, auxiliaryLineData);
116
136
  const nodeList = [];
117
137
  console.log('nodeList data:', data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@publishfx/publish-chart",
3
- "version": "2.1.5",
3
+ "version": "2.1.6",
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": [