@publishfx/publish-chart 2.1.12 → 2.1.14

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,16 @@
1
+ **2.1.14** fix(chart): 修复组合图折线指标传空判断
2
+ - 2026-03-05T02:35:21+08:00 [fix(chart): 修复组合图折线指标传空判断](http://lf.git.oa.mt/publish_platform/web/publish/commit/abad3dc8688a3a06d57e2ef1c3884593f5bba88e)
3
+ - 2026-03-05T02:30:07+08:00 [fix(chart): 副轴和非副轴分别定义偏移](http://lf.git.oa.mt/publish_platform/web/publish/commit/6390674b94bcffb02e2145ecc51927a20d89d4a0)
4
+ - 2026-03-05T02:28:42+08:00 [fix(chart): 为了规避辅助线文本避让的问题仍然使用render渲染辅助线](http://lf.git.oa.mt/publish_platform/web/publish/commit/a005f7455772ee64b3e1b951de6eec7fc1529bc5)
5
+ - 2026-03-05T02:19:27+08:00 [fix(chart): 分组时不进行补充处理](http://lf.git.oa.mt/publish_platform/web/publish/commit/0dcc076cf441b16cb6a7a02aee5f6736c1574bc0)
6
+ - 2026-03-05T02:15:09+08:00 [fix(chart): 处理缺失数据导致的tooltip文本缺失问题](http://lf.git.oa.mt/publish_platform/web/publish/commit/ab1c7394ed7b80b5ed17237f59d6c222ad6f253b)
7
+ - 2026-03-05T01:16:46+08:00 [fix(chart): 着重函数axis调整减少顶部空白](http://lf.git.oa.mt/publish_platform/web/publish/commit/6100c4c96a98aa690a61783a64ae4cc3e1c3309f)
8
+ - 2026-03-05T01:03:57+08:00 [feat(chart): 处理图表tooltip和节点tooltip的冲突问题](http://lf.git.oa.mt/publish_platform/web/publish/commit/b502392f558e0d8fdec18c551f52c6f3dc6f9eb2)
9
+ - 2026-03-04T22:36:24+08:00 [fix(chart): 组合图数据处理](http://lf.git.oa.mt/publish_platform/web/publish/commit/6622bc898bdd8feed1655b1573545299164af09c)
10
+ - 2026-03-04T22:18:28+08:00 [fix(chart): 组合图tooltip滚动显示问题](http://lf.git.oa.mt/publish_platform/web/publish/commit/6180fdf4417da43bef0800b450f4d739ca1ab6ee)
11
+ - 2026-03-04T21:28:25+08:00 [fix(chart): 可视化看板、编辑看板tooltip位置问题](http://lf.git.oa.mt/publish_platform/web/publish/commit/c58e1851d1286fcf4290ede2435603e378a747ba)
12
+ - 2026-03-04T21:17:52+08:00 [fix(chart): 组合图total计算更新](http://lf.git.oa.mt/publish_platform/web/publish/commit/937597110cc96672a2f7fda5899cd6df660bd251)
13
+
1
14
  **2.1.11** fix(chart): 组合图去掉主轴过滤逻辑,以支持tooltip展示
2
15
  - 2026-03-04T20:56:34+08:00 [fix(chart): 组合图去掉主轴过滤逻辑,以支持tooltip展示](http://lf.git.oa.mt/publish_platform/web/publish/commit/215222fb1ae535a52aea475d3a8447cdc61dfa19)
3
16
  - 2026-03-04T20:30:34+08:00 [fix(chart): 组合图数据处理逻辑优化](http://lf.git.oa.mt/publish_platform/web/publish/commit/bab29eb2897d1b7b60877c234d8cc14b4d79b9a9)
@@ -145,6 +145,12 @@ class DataAdapter {
145
145
  }
146
146
  });
147
147
  console.log('tdv:', tdv.rows);
148
+ tdv.transform({
149
+ type: 'filter',
150
+ callback (row) {
151
+ return !row[config.y] || '-' !== row[config.y];
152
+ }
153
+ });
148
154
  console.log('tdv:', tdv.rows);
149
155
  if (config.isDescend) tdv.transform({
150
156
  type: 'sort',
@@ -61,7 +61,7 @@ const lineColors = [
61
61
  const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap, onChartClick, legend = "", config, nodeSetting = {
62
62
  showType: 0,
63
63
  type: []
64
- }, indicators = [], auxiliaryLineData, highlightDate, timeRange, isGroup })=>{
64
+ }, indicators = [], auxiliaryLineData, highlightDate, timeRange, isGroup, isTooltipContent = false })=>{
65
65
  const { formatter, dataTransform, config: contextConfig } = useChartContext();
66
66
  const tooltipContainerRef = useG2TooltipContainer();
67
67
  const isGroupRef = useRef(isGroup);
@@ -129,7 +129,7 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
129
129
  y
130
130
  ]);
131
131
  const formatLineAxis = useCallback((val)=>{
132
- const indicatorId = indicators?.length > 1 ? '' : safeZ;
132
+ const indicatorId = indicators?.length > 2 ? '' : safeZ;
133
133
  return getAxisFormat(val, safeIndicatorMap, indicatorId);
134
134
  }, [
135
135
  safeIndicatorMap,
@@ -272,7 +272,8 @@ const G2CombineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorM
272
272
  lineColors,
273
273
  legendItems,
274
274
  indicatorId: y,
275
- isGroup: isGroupRef.current
275
+ isGroup: isGroupRef.current,
276
+ isTooltipContent
276
277
  });
277
278
  chartRef.current = chart;
278
279
  if (onChartClick) chart.on("plot:click", (_e)=>{
@@ -54,7 +54,7 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
54
54
  contextConfig.nodeMap
55
55
  ]);
56
56
  const nodeData = transformedData.filter((item)=>item.nodeInfos?.info?.length > 0 || item.nodeInfos?.infosCompare?.length > 0);
57
- console.log('nodeData:', nodeData);
57
+ console.log("nodeData:", nodeData);
58
58
  const { minY, maxY } = useMemo(()=>{
59
59
  const dataValues = transformedData.filter((item)=>"-" !== item[safeY] && void 0 !== item[safeY] && null !== item[safeY]).map((item)=>Number(item[safeY]));
60
60
  const compareValues = transformedData.filter((item)=>"-" !== item["subGroupValue"] && null != item["subGroupValue"]).map((item)=>Number(item["subGroupValue"]));
@@ -77,7 +77,7 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
77
77
  auxiliaryLineData
78
78
  ]);
79
79
  const formatAxis = useCallback((val)=>{
80
- const indicatorId = indicators?.length > 1 ? '' : safeLegend;
80
+ const indicatorId = indicators?.length > 1 ? "" : safeLegend;
81
81
  return getAxisFormat(val, safeIndicatorMap, indicatorId);
82
82
  }, [
83
83
  safeIndicatorMap,
@@ -175,6 +175,7 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
175
175
  legendSize: 12,
176
176
  useStrictTicks: true,
177
177
  onNodeListChange: (nodes)=>{
178
+ console.log("setXYList:", nodes);
178
179
  setXYList(nodes);
179
180
  },
180
181
  onChartRender: (chartProps)=>{
@@ -186,15 +187,20 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
186
187
  }
187
188
  });
188
189
  chartRef.current = chart;
189
- if (onChartClick) chart.on("plot:click", (_e)=>{
190
- const tooltipTitle = currentTooltipTitleRef.current;
191
- if (null != tooltipTitle) {
192
- console.log('使用 tooltip title 触发下钻:', tooltipTitle);
193
- onChartClick({
194
- title: tooltipTitle
195
- });
196
- }
197
- });
190
+ if (onChartClick) {
191
+ chart.on("plot:click", (_e)=>{
192
+ const tooltipTitle = currentTooltipTitleRef.current;
193
+ if (null != tooltipTitle) {
194
+ console.log("使用 tooltip title 触发下钻:", tooltipTitle);
195
+ onChartClick({
196
+ title: tooltipTitle
197
+ });
198
+ }
199
+ });
200
+ chart.on("plot:pointerenter:", (event)=>{
201
+ console.log("plot:pointerenter:", event);
202
+ });
203
+ }
198
204
  return ()=>{
199
205
  if (chartRef.current) {
200
206
  chartRef.current.off("plot:click");
@@ -255,7 +261,7 @@ const G2LineChart = ({ height = 300, data, x = "", y = "", z = "", indicatorMap,
255
261
  children: xyList?.map((item, index)=>/*#__PURE__*/ jsx(NodePopover, {
256
262
  style: {
257
263
  position: "absolute",
258
- top: item.pointP?.y + 10,
264
+ top: item.pointP?.y + 12,
259
265
  left: item.pointP?.x,
260
266
  width: 12,
261
267
  height: 12,
@@ -307,3 +307,5 @@ export declare function applyNodeData(view: any, nodeData: any[], x: string, y:
307
307
  }[];
308
308
  export declare function adjustDomainMax(domainMin: number, domainMax: number): number;
309
309
  export declare const sortByIndicators: (arr: string[], indicators: string[]) => string[];
310
+ export declare function intervalSort(a: any, b: any): number;
311
+ export declare function fillMissingIndicator(baseItems: any[], safeTitle: string, isCompare: boolean, isGroup?: boolean): any[];
@@ -151,19 +151,14 @@ function applyAuxiliaryLineY(view, lines, options = {}) {
151
151
  console.log('applyAuxiliaryLineY:', lines);
152
152
  const { stroke = '#F4664A', strokeOpacity = 1, labelMaxLength = 5 } = options;
153
153
  lines.forEach((auxLine)=>{
154
- console.log('lines:', auxLine);
155
154
  view.lineY().encode('y', auxLine.value).style('stroke', stroke).style('strokeOpacity', strokeOpacity).style('lineWidth', 1).style('shadowColor', 'transparent').scale('y', {
156
155
  key: auxLine?.axis === 'right' ? 'line' : 'main'
157
156
  }).axis('x', false).label({
158
157
  dx: 0,
159
158
  dy: 0,
160
- text: splitTextToMultiline(auxLine.name, labelMaxLength, '\n'),
159
+ text: splitTextToMultiline(auxLine.name, labelMaxLength, '<br />'),
161
160
  position: auxLine?.axis === 'right' ? 'bottom-right' : 'bottom-left',
162
- style: {
163
- fill: stroke,
164
- shadowColor: 'transparent',
165
- fillOpacity: 1
166
- }
161
+ render: (text)=>`<div style="background-color: transparent; padding: 5px; border-radius: 5px;font-size: 14px;position: absolute;left: ${auxLine?.axis === 'right' ? '-105px' : '0px'}; top: -24px; width: 100px;color: ${stroke}; font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;">${text}</div>`
167
162
  });
168
163
  });
169
164
  }
@@ -186,13 +181,7 @@ function applyHighlightDate(view, x, data, highlightDate, isHighlight) {
186
181
  domainMin: 0,
187
182
  domainMax: 100,
188
183
  independent: true
189
- }).tooltip(false).axis('y', {
190
- position: 'top',
191
- title: false,
192
- grid: false,
193
- label: false,
194
- tick: false
195
- });
184
+ }).tooltip(false).axis('y', false);
196
185
  highlightInterval.style({
197
186
  columnWidthRatio: 0.6,
198
187
  fill: '#cccccc',
@@ -203,13 +192,7 @@ function applyHighlightDate(view, x, data, highlightDate, isHighlight) {
203
192
  domainMin: 0,
204
193
  domainMax: 100,
205
194
  independent: true
206
- }).tooltip(true).axis('y', {
207
- position: 'top',
208
- title: false,
209
- grid: false,
210
- label: false,
211
- tick: false
212
- }).style({
195
+ }).tooltip(true).axis('y', false).style({
213
196
  stroke: 'transparent',
214
197
  strokeOpacity: 1
215
198
  });
@@ -242,7 +225,7 @@ function applyNodeData(view, nodeData, x, y) {
242
225
  const c1 = document.createElement('circle', {
243
226
  style: {
244
227
  cx: px,
245
- cy: py,
228
+ cy: py + 3,
246
229
  r: 2,
247
230
  fill: 'white'
248
231
  }
@@ -250,7 +233,7 @@ function applyNodeData(view, nodeData, x, y) {
250
233
  const c2 = document.createElement('circle', {
251
234
  style: {
252
235
  cx: px,
253
- cy: py,
236
+ cy: py + 3,
254
237
  r: 5,
255
238
  fill: item.color
256
239
  }
@@ -275,4 +258,60 @@ const sortByIndicators = (arr, indicators)=>arr.sort((a, b)=>{
275
258
  if (-1 !== indexA && -1 !== indexB) return indexA - indexB;
276
259
  return 0;
277
260
  });
278
- export { adjustDomainMax, applyAuxiliaryLineY, applyAxisX, applyAxisY, applyHighlightDate, applyLegendColor, applyNodeData, applyScaleYLinear, createChart, getColorByGroupType, getMainView, sortByIndicators };
261
+ function intervalSort(a, b) {
262
+ const itemRank = (item)=>{
263
+ if (item.isChange) return 2;
264
+ if (item.name.includes('_compare')) return 1;
265
+ return 0;
266
+ };
267
+ return itemRank(a) - itemRank(b);
268
+ }
269
+ function fillMissingIndicator(baseItems, safeTitle, isCompare, isGroup = false) {
270
+ const indicatorIds = baseItems.filter((item)=>item.indicatorId).map((item)=>item.indicatorId);
271
+ const indicatorIdSet = new Map(indicatorIds.map((id)=>[
272
+ id,
273
+ 0
274
+ ]));
275
+ console.log('baseItems:', baseItems);
276
+ if (isCompare && !isGroup) {
277
+ baseItems.forEach((item)=>{
278
+ if (item.indicatorId) indicatorIdSet.set(item.indicatorId, (indicatorIdSet.get(item.indicatorId) ?? 0) + 1);
279
+ });
280
+ indicatorIdSet.forEach((count, indicatorId)=>{
281
+ if (3 !== count) {
282
+ const color = baseItems.filter((item)=>'transparent' !== item.color).map((item)=>item.color)[0];
283
+ if (!baseItems.find((item)=>item.indicatorId === indicatorId && item.name === indicatorId)) baseItems.push({
284
+ indicatorId: indicatorId,
285
+ name: indicatorId,
286
+ value: '-',
287
+ x: safeTitle,
288
+ color: color
289
+ });
290
+ if (!baseItems.find((item)=>item.indicatorId === indicatorId && item.name === indicatorId + '_compare')) baseItems.push({
291
+ indicatorId: indicatorId,
292
+ name: indicatorId + '_compare',
293
+ tipType: 'compareline',
294
+ value: '-',
295
+ x: safeTitle
296
+ });
297
+ if (!baseItems.find((item)=>item.indicatorId === indicatorId && item.name === indicatorId + '_change')) baseItems.push({
298
+ indicatorId: indicatorId,
299
+ name: indicatorId + '_change',
300
+ isChange: true,
301
+ value: '-',
302
+ x: safeTitle
303
+ });
304
+ }
305
+ });
306
+ }
307
+ const safeItems = baseItems.map((item)=>{
308
+ if (item.x !== safeTitle) return {
309
+ ...item,
310
+ value: '-'
311
+ };
312
+ return item;
313
+ }).sort(intervalSort);
314
+ console.log('safeItems:', safeItems);
315
+ return safeItems;
316
+ }
317
+ export { adjustDomainMax, applyAuxiliaryLineY, applyAxisX, applyAxisY, applyHighlightDate, applyLegendColor, applyNodeData, applyScaleYLinear, createChart, fillMissingIndicator, getColorByGroupType, getMainView, intervalSort, sortByIndicators };
@@ -85,6 +85,8 @@ export interface RenderG2CombineChartOptions {
85
85
  }>;
86
86
  /** 当前指标 id(用于 tooltip 展示) */
87
87
  indicatorId?: string;
88
+ /** 是否将 tooltip 挂载到 body(用于可视化看板、编辑看板场景,避免被父容器裁剪) */
89
+ isTooltipContent?: boolean;
88
90
  }
89
91
  /**
90
92
  * 在容器上渲染 G2 柱状 + 折线组合图,返回 Chart 实例便于 destroy/更新
@@ -1,11 +1,11 @@
1
1
  import { lines } from "@antv/g-pattern";
2
- import { applyAuxiliaryLineY, applyAxisX, applyHighlightDate, applyNodeData, applyScaleYLinear, createChart, getMainView } from "./g2Helpers.js";
2
+ import { applyAuxiliaryLineY, applyAxisX, applyHighlightDate, applyNodeData, applyScaleYLinear, createChart, fillMissingIndicator, 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, 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;
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, isTooltipContent = false } = options;
9
9
  const chart = createChart({
10
10
  container,
11
11
  height,
@@ -38,11 +38,10 @@ function renderG2CombineChart(container, options) {
38
38
  console.log('renderG2CombineChart interval data:', intervalData);
39
39
  const intervalMaxY = intervalData.reduce((max, item)=>{
40
40
  const key = isGroup ? "total" : BAR_Y_FIELD;
41
- console.log('intervalMaxY item:', key, item[key], intervalData);
41
+ console.log('tdv item:', key, item[key], intervalData);
42
42
  if ('-' === item[key] || void 0 === item[key] || null === item[key] || '' === item[key]) return max;
43
43
  return Math.max(max, item[key]);
44
44
  }, 0);
45
- console.log('intervalMaxY:', intervalMaxY);
46
45
  console.log('tdv:', intervalMaxY);
47
46
  const auxLeftValues = auxiliaryLineData?.length ? auxiliaryLineData.filter((item)=>'left' === item.axis).map((item)=>item.value) : [];
48
47
  const maxAuxLeft = auxLeftValues.length ? Math.max(...auxLeftValues) : 0;
@@ -58,7 +57,6 @@ function renderG2CombineChart(container, options) {
58
57
  }).style({
59
58
  columnWidthRatio: 0.6,
60
59
  insetLeft: (_d, index, _data, _column)=>{
61
- console.log('insetLeft:', index, isCompare);
62
60
  if (isGroup) return 0;
63
61
  if (isCompare) return index % 2 === 0 ? 0 : 0;
64
62
  return 0;
@@ -256,7 +254,6 @@ function renderG2CombineChart(container, options) {
256
254
  });
257
255
  compareLine.axis('y', false);
258
256
  const hasCompareData = data.some((item)=>item.groupType.includes('_compare'));
259
- console.log('hasCompareData:', hasCompareData, data);
260
257
  if (hasCompareData) compareLine.tooltip({
261
258
  items: [
262
259
  (datum)=>datum.groupType.includes('_compare') ? {
@@ -265,7 +262,7 @@ function renderG2CombineChart(container, options) {
265
262
  name: datum['groupType'],
266
263
  indicatorId: datum['groupType'].replace('_compare', ''),
267
264
  channel: Y_AXIS_FIELD,
268
- color: lineColors[indicators.slice(1).indexOf(String(datum['groupType'])) ?? 0] || 'transparent',
265
+ color: lineColors[indicators.slice(1).indexOf(String(datum['groupType']).replace('_compare', '')) ?? 0] || 'trans1parent',
269
266
  isCombine: true,
270
267
  tipType: 'compareline',
271
268
  x: datum[x]
@@ -282,102 +279,131 @@ function renderG2CombineChart(container, options) {
282
279
  } : false
283
280
  ].filter(Boolean)
284
281
  });
285
- if (tooltipRender) {
286
- const intervalSort = (item)=>{
287
- if (item.isChange) return 2;
288
- if (item.name.includes('_compare')) return 1;
289
- return 0;
290
- };
291
- view.interaction('tooltip', {
292
- shared: true,
293
- crosshairsY: true,
294
- marker: false,
295
- render: (event, payload)=>{
296
- const { title, items } = payload;
297
- let safeTitle = title.replace(/,.*$/, '');
298
- const baseItems = items.filter((item)=>!item.isCombine);
299
- const safeItems = baseItems.map((item)=>{
300
- if (item.x !== safeTitle) return {
301
- ...item,
302
- value: '-'
303
- };
304
- return item;
305
- }).sort(intervalSort);
306
- const combineItems = items.filter((item)=>item.isCombine);
307
- const safeCombineItems = combineItems.map((item)=>{
308
- if (item.x !== safeTitle) return {
309
- ...item,
310
- value: '-'
311
- };
312
- return item;
313
- });
314
- const indicatorOrder = new Map(indicators.map((id, i)=>[
315
- id,
316
- i
317
- ]));
318
- const sortedCombineItems = [
319
- ...safeCombineItems
320
- ].sort((a, b)=>{
321
- const orderA = indicatorOrder.get(a.indicatorId) ?? 1 / 0;
322
- const orderB = indicatorOrder.get(b.indicatorId) ?? 1 / 0;
323
- if (orderA !== orderB) return orderA - orderB;
324
- const typeRank = (item)=>{
325
- if (item.isChange) return 2;
326
- if ('compareline' === item.tipType) return 1;
327
- return 0;
328
- };
329
- return typeRank(a) - typeRank(b);
330
- });
331
- const content = tooltipRender(safeTitle, [
332
- ...safeItems,
333
- ...sortedCombineItems
334
- ]) ?? null;
335
- if (content) {
336
- const domEvent = event?.event ?? event;
337
- const clientX = domEvent?.clientX ?? domEvent?.x ?? 0;
338
- const clientY = domEvent?.clientY ?? domEvent?.y ?? 0;
339
- const rect = container.getBoundingClientRect();
340
- const offsetX = 12;
341
- const offsetY = 12;
342
- const applyClamp = ()=>{
343
- let el = content;
344
- while(el && el.parentElement){
345
- const p = el.parentElement;
346
- if (p.classList?.contains('g2-tooltip')) {
347
- el = p;
348
- break;
349
- }
282
+ if (tooltipRender) view.interaction('tooltip', {
283
+ shared: true,
284
+ crosshairsY: true,
285
+ marker: false,
286
+ ...isTooltipContent ? {
287
+ mount: 'body'
288
+ } : {},
289
+ render: (event, payload)=>{
290
+ const { title, items } = payload;
291
+ console.log('tooltipRender:', title, items, isCompare);
292
+ let safeTitle = title.replace(/,.*$/, '');
293
+ const baseItems = items.filter((item)=>item.hasOwnProperty('isCombine') && !item.isCombine);
294
+ const safeItems = fillMissingIndicator(baseItems, safeTitle, isCompare, isGroup);
295
+ const combineItems = items.filter((item)=>item.hasOwnProperty('isCombine') && item.isCombine);
296
+ const safeCombineItems = fillMissingIndicator(combineItems, safeTitle, isCompare, isGroup);
297
+ const indicatorOrder = new Map(indicators.map((id, i)=>[
298
+ id,
299
+ i
300
+ ]));
301
+ const sortedCombineItems = [
302
+ ...safeCombineItems
303
+ ].sort((a, b)=>{
304
+ const orderA = indicatorOrder.get(a.indicatorId) ?? 1 / 0;
305
+ const orderB = indicatorOrder.get(b.indicatorId) ?? 1 / 0;
306
+ if (orderA !== orderB) return orderA - orderB;
307
+ const typeRank = (item)=>{
308
+ if (item.isChange) return 2;
309
+ if ('compareline' === item.tipType) return 1;
310
+ return 0;
311
+ };
312
+ return typeRank(a) - typeRank(b);
313
+ });
314
+ const content = tooltipRender(safeTitle, [
315
+ ...safeItems,
316
+ ...sortedCombineItems
317
+ ]) ?? null;
318
+ if (content && isTooltipContent) {
319
+ const domEvent = event?.event ?? event;
320
+ const canvas = container.querySelector('canvas');
321
+ const canvasRect = canvas ? canvas.getBoundingClientRect() : container.getBoundingClientRect();
322
+ const canvasX = domEvent?.canvasX ?? domEvent?.x ?? 0;
323
+ const canvasY = domEvent?.canvasY ?? domEvent?.y ?? 0;
324
+ const clientX = canvasRect.left + canvasX;
325
+ const clientY = canvasRect.top + canvasY;
326
+ const offsetX = 12;
327
+ const offsetY = 12;
328
+ const applyPosition = ()=>{
329
+ let el = content;
330
+ while(el && el.parentElement){
331
+ const p = el.parentElement;
332
+ if (p.classList?.contains('g2-tooltip')) {
350
333
  el = p;
334
+ break;
351
335
  }
352
- const wrapper = el && el.classList?.contains('g2-tooltip') ? el : null;
353
- if (!wrapper) return;
354
- const wRect = wrapper.getBoundingClientRect();
355
- const tooltipW = wRect.width || 260;
356
- const tooltipH = wRect.height || 300;
357
- const minLeft = rect.left;
358
- const maxLeft = rect.right - tooltipW;
359
- const minTop = rect.top;
360
- const maxTop = rect.bottom - tooltipH;
361
- const desiredLeft = clientX + offsetX;
362
- const desiredTop = clientY + offsetY;
363
- const left = Math.min(Math.max(desiredLeft, minLeft), Math.max(maxLeft, minLeft));
364
- const top = Math.min(Math.max(desiredTop, minTop), Math.max(maxTop, minTop));
365
- wrapper.style.position = 'fixed';
366
- wrapper.style.left = `${left}px`;
367
- wrapper.style.top = `${top}px`;
368
- wrapper.style.transform = 'translate(0px, 0px)';
369
- wrapper.style.pointerEvents = 'none';
370
- wrapper.style.zIndex = '9999';
371
- };
372
- try {
373
- applyClamp();
374
- requestAnimationFrame(applyClamp);
375
- } catch {}
376
- }
377
- return content;
336
+ el = p;
337
+ }
338
+ const wrapper = el && el.classList?.contains('g2-tooltip') ? el : null;
339
+ if (!wrapper) return;
340
+ const wRect = wrapper.getBoundingClientRect();
341
+ const tooltipW = wRect.width || 260;
342
+ const tooltipH = wRect.height || 300;
343
+ const viewportWidth = window.innerWidth;
344
+ const viewportHeight = window.innerHeight;
345
+ let left = clientX + offsetX;
346
+ let top = clientY + offsetY;
347
+ if (left + tooltipW > viewportWidth - 10) left = clientX - tooltipW - offsetX;
348
+ if (top + tooltipH > viewportHeight - 10) top = clientY - tooltipH - offsetY;
349
+ if (left < 10) left = 10;
350
+ if (top < 10) top = 10;
351
+ wrapper.style.position = 'fixed';
352
+ wrapper.style.left = `${left}px`;
353
+ wrapper.style.top = `${top}px`;
354
+ wrapper.style.transform = 'none';
355
+ wrapper.style.pointerEvents = 'none';
356
+ wrapper.style.zIndex = '99999';
357
+ };
358
+ try {
359
+ applyPosition();
360
+ requestAnimationFrame(applyPosition);
361
+ } catch {}
362
+ } else if (content && !isTooltipContent) {
363
+ const domEvent = event?.event ?? event;
364
+ const clientX = domEvent?.clientX ?? domEvent?.x ?? 0;
365
+ const clientY = domEvent?.clientY ?? domEvent?.y ?? 0;
366
+ const rect = container.getBoundingClientRect();
367
+ const offsetX = 12;
368
+ const offsetY = 12;
369
+ const applyClamp = ()=>{
370
+ let el = content;
371
+ while(el && el.parentElement){
372
+ const p = el.parentElement;
373
+ if (p.classList?.contains('g2-tooltip')) {
374
+ el = p;
375
+ break;
376
+ }
377
+ el = p;
378
+ }
379
+ const wrapper = el && el.classList?.contains('g2-tooltip') ? el : null;
380
+ if (!wrapper) return;
381
+ const wRect = wrapper.getBoundingClientRect();
382
+ const tooltipW = wRect.width || 260;
383
+ const tooltipH = wRect.height || 300;
384
+ const minLeft = rect.left;
385
+ const maxLeft = rect.right - tooltipW;
386
+ const minTop = rect.top;
387
+ const maxTop = rect.bottom - tooltipH;
388
+ const desiredLeft = clientX + offsetX;
389
+ const desiredTop = clientY + offsetY;
390
+ const left = Math.min(Math.max(desiredLeft, minLeft), Math.max(maxLeft, minLeft));
391
+ const top = Math.min(Math.max(desiredTop, minTop), Math.max(maxTop, minTop));
392
+ wrapper.style.position = 'fixed';
393
+ wrapper.style.left = `${left}px`;
394
+ wrapper.style.top = `${top}px`;
395
+ wrapper.style.transform = 'translate(0px, 0px)';
396
+ wrapper.style.pointerEvents = 'none';
397
+ wrapper.style.zIndex = '9999';
398
+ };
399
+ try {
400
+ applyClamp();
401
+ requestAnimationFrame(applyClamp);
402
+ } catch {}
378
403
  }
379
- });
380
- }
404
+ return content;
405
+ }
406
+ });
381
407
  view.legend(false);
382
408
  view.interaction('poptip', {
383
409
  offsetY: -20,
@@ -33,7 +33,7 @@ function renderG2LineChart(container, options) {
33
33
  lineWidth: 2,
34
34
  stroke: (datum)=>getColorByGroupType(datum[0]?.groupType ?? '', colorOpts)
35
35
  });
36
- const compareLine = view.line().data(data.filter((item)=>item.groupType.includes('_compare'))).encode('x', x).encode('y', Y_AXIS_FIELD).encode('color', 'groupType').style({
36
+ const compareLine = 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({
37
37
  lineDash: [
38
38
  4,
39
39
  4
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
  type NodeInfoItem = {
3
3
  area: string;
4
4
  description: string;
@@ -15,19 +15,25 @@ const NodePopover = ({ style, pointData, pointP })=>{
15
15
  return /*#__PURE__*/ jsx(Fragment, {
16
16
  children: /*#__PURE__*/ jsx(Popover, {
17
17
  blurToHide: true,
18
- unmountOnExit: true,
18
+ unmountOnExit: false,
19
19
  position: "right",
20
20
  style: {
21
- maxWidth: 'auto'
21
+ maxWidth: "auto"
22
22
  },
23
23
  content: /*#__PURE__*/ jsx(Fragment, {
24
24
  children: /*#__PURE__*/ jsx(NodePopoverContent, {
25
25
  nodeInfos: nodeInfos
26
26
  })
27
27
  }),
28
+ onVisibleChange: (visible)=>{
29
+ if (visible) {
30
+ const tooltip = document.querySelector(".g2-tooltip");
31
+ if (tooltip) tooltip.style.visibility = "hidden";
32
+ }
33
+ },
28
34
  children: /*#__PURE__*/ jsx("div", {
29
35
  style: {
30
- position: 'absolute',
36
+ position: "absolute",
31
37
  top: pointP.y - 10,
32
38
  left: pointP.x - 10,
33
39
  zIndex: 999,
@@ -100,6 +100,7 @@ export interface BaseChartProps {
100
100
  highlightDate?: string[];
101
101
  /** 是否为分组柱状(组合图等场景) */
102
102
  isGroup?: boolean;
103
+ isTooltipContent?: boolean;
103
104
  }
104
105
  /**
105
106
  * 业务组件 Props(可选,通过 Context 注入)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@publishfx/publish-chart",
3
- "version": "2.1.12",
3
+ "version": "2.1.14",
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": [