onesight-charts 1.4.2 → 1.4.4

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,13 +1,13 @@
1
1
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
- function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
3
- function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
- function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
5
- function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
6
2
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
7
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
8
4
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
9
5
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
10
6
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
8
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
9
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
10
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
11
11
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
12
12
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
13
13
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
@@ -15,7 +15,7 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
15
15
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
16
16
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
17
17
  import * as echarts from 'echarts';
18
- import React, { useEffect, useRef, useState, useCallback } from 'react';
18
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
19
19
  import { changeDataTypeEn, computeFloat, dealBarPath, numberFormatNull } from "../../utils/chartUtils";
20
20
  import Pagination from "../pagination";
21
21
  import "./style.scss";
@@ -43,67 +43,28 @@ function CommonBar(props) {
43
43
  callbackGetPage = _props$callbackGetPag === void 0 ? function () {} : _props$callbackGetPag,
44
44
  _props$handleClick = props.handleClick,
45
45
  handleClick = _props$handleClick === void 0 ? function () {} : _props$handleClick;
46
- // 总数页码数
47
46
  var _useState = useState(0),
48
47
  _useState2 = _slicedToArray(_useState, 2),
49
48
  total = _useState2[0],
50
49
  setTotal = _useState2[1];
51
50
  var chart = useRef(null);
52
- // 当前页下标
53
51
  var _useState3 = useState(1),
54
52
  _useState4 = _slicedToArray(_useState3, 2),
55
53
  currentPage = _useState4[0],
56
54
  setCurrentPage = _useState4[1];
57
55
  var chartRef = useRef(null);
58
- // 存储上一次的依赖项值,用于深度比较
59
56
  var prevDepsRef = useRef(null);
60
- // 为每个组件实例生成唯一的 tooltip 类名,避免多实例冲突
61
57
  var tooltipClassNameRef = useRef("onesight-chart-common-bar-tooltip-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9)));
62
- useEffect(function () {
63
- // 深度比较依赖项,只有当内容真正改变时才执行
64
- var currentDeps = JSON.stringify({
65
- currentPage: currentPage,
66
- data: data
67
- });
68
- var prevDeps = prevDepsRef.current;
69
-
70
- // 如果内容没有改变,不执行
71
- if (prevDeps !== null && currentDeps === prevDeps) {
72
- return;
73
- }
74
-
75
- // 更新存储的值
76
- prevDepsRef.current = currentDeps;
77
- var copyData = JSON.parse(JSON.stringify(data));
78
- var splice_data = copyData.slice((currentPage - 1) * number, currentPage * number);
79
- if (data.length) {
80
- setTotal(Math.ceil(data.length / number));
81
- }
82
- init(splice_data);
83
- callbackGetPage(currentPage);
84
- // 使用 setTimeout 确保 DOM 已经更新后再绑定事件
85
- setTimeout(function () {
86
- bindClickEvents();
87
- }, 0);
88
- return function () {
89
- unbindClickEvents();
90
- };
91
- }, [currentPage, data, bindClickEvents, unbindClickEvents]);
92
58
  var paginationCb = function paginationCb(currData, page) {
93
59
  setCurrentPage(page);
94
60
  };
95
61
  var onChartClick = useCallback(function (event) {
96
- // 确保只处理当前组件实例的 tooltip
97
62
  var tooltipElement = event.target.closest(".".concat(tooltipClassNameRef.current));
98
- if (!tooltipElement) {
99
- return;
100
- }
63
+ if (!tooltipElement) return;
101
64
  var seriesNameElement = event.target.closest('.item');
102
65
  if (seriesNameElement) {
103
66
  var seriesItem = seriesNameElement.getAttribute('data-series-item');
104
- if (!seriesItem) {
105
- return;
106
- }
67
+ if (!seriesItem) return;
107
68
  var seriesData = JSON.parse(seriesItem);
108
69
  handleClick && handleClick('tooltipType', seriesData);
109
70
  }
@@ -120,6 +81,26 @@ function CommonBar(props) {
120
81
  chartElement.removeEventListener('click', onChartClick);
121
82
  }
122
83
  }, [onChartClick]);
84
+ useEffect(function () {
85
+ var currentDeps = JSON.stringify({
86
+ currentPage: currentPage,
87
+ data: data
88
+ });
89
+ var prevDeps = prevDepsRef.current;
90
+ if (prevDeps !== null && currentDeps === prevDeps) return;
91
+ prevDepsRef.current = currentDeps;
92
+ var copyData = JSON.parse(JSON.stringify(data));
93
+ var splice_data = copyData.slice((currentPage - 1) * number, currentPage * number);
94
+ if (data.length) setTotal(Math.ceil(data.length / number));
95
+ init(splice_data);
96
+ callbackGetPage(currentPage);
97
+ setTimeout(function () {
98
+ bindClickEvents();
99
+ }, 0);
100
+ return function () {
101
+ unbindClickEvents();
102
+ };
103
+ }, [currentPage, data, bindClickEvents, unbindClickEvents, number, callbackGetPage]);
123
104
  function toggleAxisPointer(myChart, show) {
124
105
  myChart.setOption({
125
106
  tooltip: {
@@ -131,49 +112,32 @@ function CommonBar(props) {
131
112
  }
132
113
  });
133
114
  }
134
-
135
- // 将 JSON 字符串转义为安全的 HTML 属性值
136
115
  function escapeHtmlAttribute(jsonString) {
137
116
  return String(jsonString).replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
138
117
  }
139
118
  var calculateWidth = function calculateWidth(len) {
140
- if (len === 1 || len === 2 || len === 3) {
141
- return 42;
142
- } else if (len === 4) {
143
- return 40;
144
- } else if (len === 5) {
145
- return 32;
146
- } else if (len === 6) {
147
- return 26;
148
- } else if (len === 7) {
149
- return 24;
150
- } else if (len === 8) {
151
- return 20;
152
- } else if (len === 9) {
153
- return 18;
154
- } else if (len === 10) {
155
- return 16;
156
- }
119
+ if (len === 1 || len === 2 || len === 3) return 42;
120
+ if (len === 4) return 40;
121
+ if (len === 5) return 32;
122
+ if (len === 6) return 26;
123
+ if (len === 7) return 24;
124
+ if (len === 8) return 20;
125
+ if (len === 9) return 18;
126
+ if (len === 10) return 16;
127
+ return 16;
157
128
  };
158
129
  function setBarData(myChart, newData) {
159
130
  if (!myChart) return;
160
131
  myChart.setOption({
161
- series: [
162
- // 背景柱(seriesIndex 0)保持不变
163
- {},
164
- // 前景柱(seriesIndex 1)换成新数组
165
- {
132
+ series: [{}, {
166
133
  data: newData
167
134
  }]
168
- }, false); // 第二个参数 false → 不合并全量 option
135
+ }, false);
169
136
  }
170
137
  var ICON_SIZE = 18;
171
138
  var ICON_GAP = 0;
172
-
173
- // 生成 y 轴富文本样式:为每一行创建 iconN,并且给 label 做截断
174
139
  function makeYAxisRich(rows) {
175
140
  var maxLabelWidth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 188;
176
- // 检查是否有任何行包含 platformIcon
177
141
  var hasAnyIcon = rows.some(function (row) {
178
142
  return row.platformIcon;
179
143
  });
@@ -184,14 +148,10 @@ function CommonBar(props) {
184
148
  fontWeight: 500,
185
149
  lineHeight: 20,
186
150
  align: 'right',
187
- // 文本宽度 = 总宽 - 图标宽度 - 间距
188
- // width: Math.max(0, maxLabelWidth - ICON_SIZE - ICON_GAP),
189
151
  overflow: 'truncate',
190
152
  ellipsis: '...',
191
- // 如果没有任何图标,则不需要左边距
192
153
  padding: hasAnyIcon ? [0, 0, 0, ICON_GAP] : [0, 0, 0, 0]
193
154
  },
194
- // 为没有图标的项目创建一个空的样式
195
155
  noIcon: {
196
156
  width: 0,
197
157
  height: 0
@@ -204,13 +164,11 @@ function CommonBar(props) {
204
164
  height: ICON_SIZE,
205
165
  align: 'right',
206
166
  borderRadius: 4,
207
- // 这里用图片作为文本块的背景
208
167
  backgroundColor: {
209
168
  image: row.platformIcon
210
- } // 建议传绝对路径或 public 下的路径
169
+ }
211
170
  };
212
171
  } else {
213
- // 为没有图标的项目创建空样式
214
172
  rich["icon".concat(i)] = {
215
173
  width: 0,
216
174
  height: 0
@@ -219,36 +177,20 @@ function CommonBar(props) {
219
177
  });
220
178
  return rich;
221
179
  }
222
-
223
- // 单行 label 的最大显示区域(和 axisLabel.width 一致)
224
180
  var MAX_LABEL_WIDTH = 188;
225
-
226
- // 如果该条有平台 icon,就要扣掉 icon 宽度+间距;否则直接用全部
227
181
  function getMaxTextWidthForRow(hasIcon) {
228
182
  return hasIcon ? MAX_LABEL_WIDTH - ICON_SIZE - ICON_GAP : MAX_LABEL_WIDTH;
229
183
  }
230
-
231
- // 返回一个“中间省略”的文本,尽量贴近 maxWidthPx 宽度
232
184
  function middleEllipsis(labelText, maxWidthPx) {
233
185
  var font = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '14px sans-serif';
234
186
  if (!labelText) return '';
235
-
236
- // 先测整段的宽度
237
187
  var fullRect = echarts.format.getTextRect(labelText, font);
238
- if (fullRect.width <= maxWidthPx) {
239
- // 不超宽,直接用原文
240
- return labelText;
241
- }
242
-
243
- // 需要省略 -> 我们要找到前半段+后半段的长度
244
- // 方案:从头和尾慢慢加字符,直到超过 maxWidthPx
188
+ if (fullRect.width <= maxWidthPx) return labelText;
245
189
  var DOT = '...';
246
190
  var dotW = echarts.format.getTextRect(DOT, font).width;
247
-
248
- // 我们会不断尝试 prefixLen / suffixLen 的组合
249
191
  var prefixLen = 1;
250
192
  var suffixLen = 1;
251
- var best = DOT; // 兜底
193
+ var best = DOT;
252
194
  var bestW = dotW;
253
195
  while (prefixLen < labelText.length && suffixLen < labelText.length) {
254
196
  var head = labelText.slice(0, prefixLen);
@@ -256,23 +198,28 @@ function CommonBar(props) {
256
198
  var candidate = head + DOT + tail;
257
199
  var w = echarts.format.getTextRect(candidate, font).width;
258
200
  if (w <= maxWidthPx) {
259
- // 还能放得下 => 记录成当前最佳,然后再尝试加长
260
201
  best = candidate;
261
202
  bestW = w;
262
- // 优先多给前缀,视觉更贴设计稿(你可以反过来)
263
203
  prefixLen++;
264
- if (prefixLen % 2 === 0) {
265
- suffixLen++;
266
- }
204
+ if (prefixLen % 2 === 0) suffixLen++;
267
205
  } else {
268
- // 超了,就停。这个 best 就是我们要的
269
206
  break;
270
207
  }
271
208
  }
272
209
  return best;
273
210
  }
211
+
212
+ // 取真实 grid 宽度(包含 containLabel 的最终结果)
213
+ function getGridPlotWidth(myChart) {
214
+ try {
215
+ var _myChart$getModel, _myChart$getModel$get, _grid$coordinateSyste, _grid$coordinateSyste2;
216
+ var grid = (_myChart$getModel = myChart.getModel()) === null || _myChart$getModel === void 0 || (_myChart$getModel$get = _myChart$getModel.getComponent) === null || _myChart$getModel$get === void 0 ? void 0 : _myChart$getModel$get.call(_myChart$getModel, 'grid');
217
+ var rect = grid === null || grid === void 0 || (_grid$coordinateSyste = grid.coordinateSystem) === null || _grid$coordinateSyste === void 0 || (_grid$coordinateSyste2 = _grid$coordinateSyste.getRect) === null || _grid$coordinateSyste2 === void 0 ? void 0 : _grid$coordinateSyste2.call(_grid$coordinateSyste);
218
+ if (rect !== null && rect !== void 0 && rect.width) return rect.width;
219
+ } catch (e) {}
220
+ return myChart.getWidth();
221
+ }
274
222
  var init = function init(currentData) {
275
- var _data$;
276
223
  var myChart = null;
277
224
  var myDom = chartRef.current;
278
225
  myChart = echarts.getInstanceByDom(myDom);
@@ -282,153 +229,200 @@ function CommonBar(props) {
282
229
  renderer: 'svg'
283
230
  });
284
231
  }
285
- var fadedData = null; // 缓存上一帧,避免重复 setOption
232
+
233
+ // 清理旧事件(避免分页/重绘叠加)
234
+ myChart.off('showTip');
235
+ myChart.off('hideTip');
236
+ myChart.off('finished');
237
+ myChart.getZr().off('click');
238
+ var fadedData = null;
286
239
  var lastIndex = null;
287
240
  var axisData = currentData.map(function (item) {
288
241
  return item.format || item.name || '-';
289
242
  });
290
- var seriesData = currentData.map(function (item) {
291
- // 优先使用每项自己的颜色,如果没有则使用默认的 barColor
292
- var itemColor = item.color || barColor;
293
- if (showProportion) {
294
- return {
295
- name: item.name || '-',
296
- value: (item === null || item === void 0 ? void 0 : item.proportion) || 0,
297
- label: {
298
- // 负数就把文字放左边,正数/0 放右边
299
- position: (item === null || item === void 0 ? void 0 : item.proportion) < 0 ? 'left' : 'right'
300
- },
301
- itemStyle: item !== null && item !== void 0 && item.proportion ? {
302
- color: itemColor
303
- } : {
304
- color: 'rgba(29, 169, 160, 0)'
305
- }
306
- };
307
- } else {
308
- return {
309
- name: item.name || '-',
310
- value: item.value || 0,
311
- label: {
312
- // 负数就把文字放左边,正数/0 放右边
313
- position: item.value < 0 ? 'left' : 'right'
314
- },
315
- itemStyle: item.value ? {
316
- color: itemColor
317
- } : {
318
- color: 'rgba(29, 169, 160, 0)'
319
- }
320
- };
321
- }
322
- });
323
- var originalData = seriesData.map(function (d) {
324
- return _objectSpread(_objectSpread({}, d), {}, {
325
- itemStyle: _objectSpread(_objectSpread({}, d.itemStyle || {}), {}, {
326
- opacity: 1
327
- })
328
- });
243
+
244
+ // 是否启用 yAxis icon(建议用当前页判断)
245
+ var yIconFlag = currentData === null || currentData === void 0 ? void 0 : currentData.some(function (d) {
246
+ return d === null || d === void 0 ? void 0 : d.platformIcon;
329
247
  });
330
- var maxDataValue = Math.max.apply(Math, _toConsumableArray(currentData.map(function (item) {
331
- return showProportion ? item === null || item === void 0 ? void 0 : item.proportion : item.value;
332
- })));
333
- // ① 先测出 Y 轴中最长的类目文本宽度
334
- var ySample = axisData.reduce(function (a, b) {
335
- return a.length > b.length ? a : b;
336
- }, '');
337
- var yLabelWidth = echarts.format.getTextRect(ySample, '14px sans-serif').width;
338
- // 你在 axisLabel 里写了 margin: 10
339
- var axisLabelGap = 10;
340
- var chartWidth = myChart.getWidth();
341
- var leftPadding = 12;
342
- var rightPadding = 0;
343
- var gridWidth = chartWidth - leftPadding - rightPadding;
344
- var dealYLabelWidth = yLabelWidth > 188 ? 188 : yLabelWidth;
345
- // ③ 真正柱子可用的像素宽度
346
- var barAreaWidth = gridWidth - dealYLabelWidth - axisLabelGap;
347
- var sampleText = showProportion ? computeFloat(maxDataValue) : numberFormatNull(maxDataValue);
348
- var labelWidth = echarts.format.getTextRect(sampleText, '14px sans-serif').width;
349
- var extra = 15;
350
- var yIconFlag = (_data$ = data[0]) === null || _data$ === void 0 ? void 0 : _data$.platformIcon;
351
248
  var valueAccessor = function valueAccessor(item) {
352
249
  return showProportion ? (item === null || item === void 0 ? void 0 : item.proportion) || 0 : item.value || 0;
353
250
  };
354
- var minDataValue = Math.min.apply(Math, _toConsumableArray(currentData.map(valueAccessor)));
355
- var hasNegative = minDataValue < 0;
356
- var allNegative = maxDataValue < 0; // 检查是否所有数据都是负数
251
+ var rawVals = currentData.map(valueAccessor);
252
+ var rawMax = Math.max.apply(Math, [0].concat(_toConsumableArray(rawVals)));
253
+ var rawMin = Math.min.apply(Math, [0].concat(_toConsumableArray(rawVals)));
254
+ var FONT = '14px sans-serif';
255
+ var formatLabel = function formatLabel(v) {
256
+ return showProportion ? computeFloat(v) : numberFormatNull(v);
257
+ };
357
258
 
358
- var bgValue;
359
- // 如果所有数据都是负数,bgValue 应该设置为 0,让 xAxis.max 至少是 0
360
- if (allNegative) {
361
- bgValue = 0;
362
- } else if (barAreaWidth > labelWidth + extra) {
363
- bgValue = maxDataValue * barAreaWidth / (barAreaWidth - labelWidth - extra);
364
- } else {
365
- var overflowPx = labelWidth + extra - barAreaWidth; // 还差多少像素
366
- var unitPerPx = maxDataValue / barAreaWidth; // 1 像素 ≈ 多少数据值
367
- bgValue = maxDataValue + overflowPx * unitPerPx; // 把缺的像素折算到数据值
259
+ // 右侧(正数)最长 label
260
+ var rightLabelText = rawMax > 0 ? formatLabel(rawMax) : '';
261
+ var rightLabelW = rightLabelText ? echarts.format.getTextRect(rightLabelText, FONT).width : 0;
262
+
263
+ // 左侧(负数)最长 label(带负号)
264
+ var leftLabelText = rawMin < 0 ? formatLabel(rawMin) : '';
265
+ var leftLabelW = leftLabelText ? echarts.format.getTextRect(leftLabelText, FONT).width : 0;
266
+ var LABEL_DISTANCE = 5; // 要和 series.label.distance 保持一致
267
+ var SAFE_PX = 24; // 建议稍大一点,避免字体/渲染误差
268
+ var rightSpacePx = rawMax > 0 ? rightLabelW + LABEL_DISTANCE + SAFE_PX : 0;
269
+ var leftSpacePx = rawMin < 0 ? leftLabelW + LABEL_DISTANCE + SAFE_PX : 0;
270
+
271
+ // 先用一个“基础 option”把 grid 跑出来,拿到真实 plotWidth
272
+ var baseOption = {
273
+ tooltip: {
274
+ show: false
275
+ },
276
+ animation: false,
277
+ legend: {
278
+ show: false
279
+ },
280
+ grid: {
281
+ top: 0,
282
+ bottom: 0,
283
+ left: 12,
284
+ right: 0,
285
+ containLabel: true
286
+ },
287
+ xAxis: {
288
+ type: 'value',
289
+ min: rawMin,
290
+ max: rawMax,
291
+ show: false,
292
+ axisLine: {
293
+ show: false
294
+ },
295
+ axisLabel: {
296
+ show: false
297
+ },
298
+ splitLine: {
299
+ show: false
300
+ },
301
+ boundaryGap: false
302
+ },
303
+ yAxis: {
304
+ type: 'category',
305
+ inverse: true,
306
+ axisLabel: {
307
+ margin: rawMin < 0 ? 40 : 10,
308
+ color: '#273333',
309
+ fontSize: 14,
310
+ fontWeight: 500,
311
+ lineHeight: 20,
312
+ show: true,
313
+ interval: 0,
314
+ rotate: 0,
315
+ overflow: 'truncate',
316
+ ellipsis: '...',
317
+ formatter: function formatter(value, index) {
318
+ var _currentData$index;
319
+ var rowHasIcon = !!(yIconFlag && (_currentData$index = currentData[index]) !== null && _currentData$index !== void 0 && _currentData$index.platformIcon);
320
+ var maxPx = getMaxTextWidthForRow(rowHasIcon);
321
+ var finalText = middleEllipsis(value, maxPx, FONT);
322
+ if (yIconFlag) return "{icon".concat(index, "|} {label|").concat(finalText, "}");
323
+ return finalText;
324
+ }
325
+ },
326
+ axisTick: {
327
+ show: false
328
+ },
329
+ axisLine: {
330
+ show: false
331
+ },
332
+ splitLine: {
333
+ show: false
334
+ },
335
+ data: axisData
336
+ },
337
+ series: [{
338
+ type: 'bar',
339
+ data: rawVals
340
+ }]
341
+ };
342
+ if (yIconFlag) {
343
+ baseOption.yAxis.axisLabel.rich = makeYAxisRich(currentData);
368
344
  }
345
+ myChart.setOption(baseOption, true);
346
+ var plotW = Math.max(1, getGridPlotWidth(myChart));
369
347
 
370
- // 计算负数的最小背景值(类似正数的 bgValue)
371
- var minBgValue = 0;
372
- if (hasNegative) {
373
- var absMinDataValue = Math.abs(minDataValue);
374
- var absMaxDataValue = Math.abs(maxDataValue);
375
- var minLabelSample = showProportion ? computeFloat(absMinDataValue) : numberFormatNull(absMinDataValue);
376
- var minLabelWidth = echarts.format.getTextRect(minLabelSample, '14px sans-serif').width;
377
- var minExtra = 15;
348
+ // === 用真实 plotW 计算 xAxis min/max(保证左右 label 都在 grid 里)===
349
+ var calcAxisRange = function calcAxisRange(baseMin, baseMax) {
350
+ var rL = Math.min(0.45, Math.max(0, leftSpacePx / plotW));
351
+ var rR = Math.min(0.45, Math.max(0, rightSpacePx / plotW));
352
+ var denom = Math.max(0.1, 1 - rL - rR);
353
+ var baseSpan = baseMax - baseMin;
354
+ if (!isFinite(baseSpan) || baseSpan === 0) baseSpan = 1;
355
+ var span = baseSpan / denom;
356
+ var xMin = baseMin - rL * span;
357
+ var xMax = baseMax + rR * span;
358
+ return {
359
+ xMin: xMin,
360
+ xMax: xMax,
361
+ span: span
362
+ };
363
+ };
378
364
 
379
- // 计算整个x轴的数据范围(从最小负数到最大正数)
380
- var totalDataRange = absMinDataValue + absMaxDataValue;
365
+ // 方案B:最小可见像素 4px
366
+ var MIN_BAR_PX = 4;
367
+ var minVisibleAbsFloor = showProportion ? 0 : 1;
381
368
 
382
- // 计算负数部分应该占用的像素宽度
383
- var negativeBarAreaWidth;
384
- // 如果所有数据都是负数,使用整个 barAreaWidth 来显示负数
385
- if (allNegative) {
386
- negativeBarAreaWidth = barAreaWidth;
387
- } else if (totalDataRange > 0) {
388
- if (absMinDataValue < absMaxDataValue * 0.3) {
389
- // 负数很小,只给必要的空间(标签宽度 + 一些余量)
390
- negativeBarAreaWidth = Math.min(minLabelWidth + minExtra + 30, barAreaWidth * 0.25);
391
- } else {
392
- // 按比例分配,但确保至少能显示标签
393
- var ratio = absMinDataValue / totalDataRange;
394
- negativeBarAreaWidth = barAreaWidth * ratio;
395
- negativeBarAreaWidth = Math.max(negativeBarAreaWidth, minLabelWidth + minExtra + 20);
396
- }
397
- } else {
398
- negativeBarAreaWidth = barAreaWidth * 0.5;
399
- }
369
+ // 迭代两次:先算 axis,再算 minVisible,再确保 axis 能包含 minVisible
370
+ var baseMin = rawMin;
371
+ var baseMax = rawMax;
372
+ var axis = calcAxisRange(baseMin, baseMax);
373
+ var minVisibleValue = axis.span * (MIN_BAR_PX / plotW) || minVisibleAbsFloor;
374
+ minVisibleValue = Math.max(minVisibleValue, minVisibleAbsFloor);
375
+ var hasPos = rawMax > 0;
376
+ var hasNeg = rawMin < 0;
400
377
 
401
- // 计算 minBgValue:让负数柱子尽可能紧凑,只留出标签空间
402
- // 负数柱子占用的像素 = negativeBarAreaWidth - minLabelWidth - minExtra
403
- var availableBarWidth = Math.max(1, negativeBarAreaWidth - minLabelWidth - minExtra);
404
- // 计算每像素对应的数据值
405
- var dataPerPixel = absMinDataValue / availableBarWidth;
406
- // minBgValue 需要比 minDataValue 更小,以容纳左边的标签
407
- var labelSpaceInData = (minLabelWidth + minExtra) * dataPerPixel;
408
- minBgValue = -(absMinDataValue + labelSpaceInData);
378
+ // 如果 clamp 后的可见值会超过 rawMax/rawMin,则把 baseMin/baseMax 扩一下再算一次 axis
379
+ var effectiveMax = hasPos ? Math.max(rawMax, minVisibleValue) : 0;
380
+ var effectiveMin = hasNeg ? Math.min(rawMin, -minVisibleValue) : 0;
381
+ if (effectiveMax !== baseMax || effectiveMin !== baseMin) {
382
+ baseMax = effectiveMax;
383
+ baseMin = effectiveMin;
384
+ axis = calcAxisRange(baseMin, baseMax);
385
+ minVisibleValue = axis.span * (MIN_BAR_PX / plotW) || minVisibleAbsFloor;
386
+ minVisibleValue = Math.max(minVisibleValue, minVisibleAbsFloor);
387
+ }
388
+ var xAxisMin = axis.xMin;
389
+ var xAxisMax = axis.xMax;
409
390
 
410
- // 如果同时有正数,重新计算正数的 bgValue,使用剩余空间
411
- // 如果所有数据都是负数,bgValue 保持为 0
412
- if (maxDataValue > 0 && !allNegative) {
413
- var positiveBarAreaWidth = barAreaWidth - negativeBarAreaWidth;
414
- if (positiveBarAreaWidth > labelWidth + extra) {
415
- bgValue = maxDataValue * positiveBarAreaWidth / (positiveBarAreaWidth - labelWidth - extra);
416
- } else {
417
- var _overflowPx = labelWidth + extra - positiveBarAreaWidth;
418
- var _unitPerPx = maxDataValue / Math.max(positiveBarAreaWidth, 1);
419
- bgValue = maxDataValue + _overflowPx * _unitPerPx;
391
+ // 前景 seriesData:rawValue 用于展示,value 用于绘制(钳制最小 4px)
392
+ var seriesData = currentData.map(function (item) {
393
+ var itemColor = item.color || barColor;
394
+ var raw = valueAccessor(item);
395
+ var displayValue = raw === 0 ? 0 : Math.sign(raw) * Math.max(Math.abs(raw), minVisibleValue);
396
+ return {
397
+ name: item.name || '-',
398
+ rawValue: raw,
399
+ value: displayValue,
400
+ label: {
401
+ position: raw < 0 ? 'left' : 'right'
402
+ },
403
+ itemStyle: raw ? {
404
+ color: itemColor
405
+ } : {
406
+ color: 'rgba(29, 169, 160, 0)'
420
407
  }
421
- }
422
- }
408
+ };
409
+ });
410
+ var originalData = seriesData.map(function (d) {
411
+ return _objectSpread(_objectSpread({}, d), {}, {
412
+ itemStyle: _objectSpread(_objectSpread({}, d.itemStyle || {}), {}, {
413
+ opacity: 1
414
+ })
415
+ });
416
+ });
423
417
  var option = {
424
418
  tooltip: {
425
419
  className: "onesight-chart-common-bar-tooltip ".concat(tooltipClassNameRef.current),
426
420
  trigger: 'axis',
427
421
  enterable: true,
422
+ padding: 0,
428
423
  // showContent: true,
429
424
  // alwaysShowContent: true,
430
425
  // hideDelay: 1000000000,
431
- padding: 0,
432
426
  position: function position(point, params, dom) {
433
427
  var tooltipHeight = (dom === null || dom === void 0 ? void 0 : dom.offsetHeight) || 0;
434
428
  var currentHeight = myDom.offsetHeight;
@@ -452,26 +446,24 @@ function CommonBar(props) {
452
446
  var _res$, _res$2;
453
447
  if (!res.some(function (i) {
454
448
  return i.value !== undefined && i.value !== null;
455
- })) {
456
- return '';
457
- }
449
+ })) return '';
458
450
  var dataArr = [res[1]];
459
451
  var currentColor = ((_res$ = res[1]) === null || _res$ === void 0 ? void 0 : _res$.color) || '#1DA9A0';
460
452
  var triangleWidth = 280;
461
- // 获取当前数据项的索引,以便从 currentData 中获取 alias
462
453
  var dataIndex = (_res$2 = res[1]) === null || _res$2 === void 0 ? void 0 : _res$2.dataIndex;
463
454
  var originalItem = currentData[dataIndex];
464
- return "<div class='onesight-chart-common-bar-tooltip-box' style=\"width:278px;position: relative;\">\n ".concat(isTooltipTitleShow ? "<div class=\"tooltip-head\">\n ".concat(res[0].format || res[0].name, "\n </div>") : '', "\n <div class='tooltip-body'>\n ").concat(dataArr.map(function (item) {
465
- // 合并原始数据的 alias、alias2 和 aliasArray 字段到 item 中
455
+ return "<div class='onesight-chart-common-bar-tooltip-box' style=\"width:278px;position: relative;\">\n ".concat(isTooltipTitleShow ? "<div class=\"tooltip-head\">".concat(res[0].format || res[0].name, "</div>") : '', "\n ").concat(originalItem !== null && originalItem !== void 0 && originalItem.currentTime ? "<div class=\"tooltip-time\">".concat(originalItem === null || originalItem === void 0 ? void 0 : originalItem.currentTime, "</div>") : '', "\n <div class='tooltip-body'>\n ").concat(dataArr.map(function (item) {
456
+ var _item$data;
457
+ var raw = (item === null || item === void 0 || (_item$data = item.data) === null || _item$data === void 0 ? void 0 : _item$data.rawValue) !== undefined ? item.data.rawValue : item.value;
466
458
  var itemWithAlias = _objectSpread(_objectSpread({}, item), {}, {
467
459
  alias: originalItem === null || originalItem === void 0 ? void 0 : originalItem.alias,
468
460
  alias2: originalItem === null || originalItem === void 0 ? void 0 : originalItem.alias2,
469
- aliasArray: originalItem === null || originalItem === void 0 ? void 0 : originalItem.aliasArray
461
+ aliasArray: originalItem === null || originalItem === void 0 ? void 0 : originalItem.aliasArray,
462
+ rawValue: raw
470
463
  });
471
- // 将 JSON 字符串转义为安全的 HTML 属性值
472
464
  var escapedJson = escapeHtmlAttribute(JSON.stringify(itemWithAlias));
473
- return "<div class='item' data-series-item=\"".concat(escapedJson, "\" key='").concat(item.seriesName, "'>\n <div class='l'>\n <span style=\"display:inline-block;width: 14px;vertical-align: middle;height: 14px;background-color:").concat(currentColor, ";border-radius: 4px;margin-bottom: 2px;margin-right:6px\"></span>\n <span>").concat(tooltipItemName ? res[0].format || res[0].name : tipName, "\n </span>\n </div>\n <div class='r' style=\"padding-left:6px;\">\n <span class='num'>\n ").concat(showProportion ? computeFloat(item.value) : changeDataTypeEn(item.value), "\n </span>\n </div>\n </div>");
474
- }).join(''), "\n </div>\n <div class='triangle-down' style='width:").concat(triangleWidth, "px'></div>\n </div>");
465
+ return "<div class='item' data-series-item=\"".concat(escapedJson, "\" key='").concat(item.seriesName, "'>\n <div class='l'>\n <span style=\"display:inline-block;width: 14px;vertical-align: middle;height: 14px;background-color:").concat(currentColor, ";border-radius: 4px;margin-bottom: 2px;margin-right:6px\"></span>\n <span>").concat(tooltipItemName ? res[0].format || res[0].name : tipName, "</span>\n </div>\n <div class='r' style=\"padding-left:6px;\">\n <span class='num'>").concat(showProportion ? computeFloat(raw) : changeDataTypeEn(raw), "</span>\n </div>\n </div>");
466
+ }).join(''), "\n </div>\n <div class='triangle-down' style='width:").concat(triangleWidth, "px'></div>\n </div>");
475
467
  }
476
468
  },
477
469
  animation: true,
@@ -482,16 +474,15 @@ function CommonBar(props) {
482
474
  },
483
475
  grid: {
484
476
  top: 0,
485
- // bottom: 30,
486
477
  bottom: 0,
487
478
  left: 12,
488
- right: hasNegative ? 30 : 0,
479
+ right: 0,
489
480
  containLabel: true
490
481
  },
491
482
  xAxis: {
492
483
  type: 'value',
493
- max: bgValue,
494
- min: hasNegative ? minBgValue : undefined,
484
+ min: xAxisMin,
485
+ max: xAxisMax,
495
486
  show: false,
496
487
  axisLine: {
497
488
  show: false
@@ -508,7 +499,7 @@ function CommonBar(props) {
508
499
  type: 'category',
509
500
  inverse: true,
510
501
  axisLabel: {
511
- margin: hasNegative ? 40 : 10,
502
+ margin: rawMin < 0 ? 40 : 10,
512
503
  color: '#273333',
513
504
  fontSize: 14,
514
505
  fontWeight: 500,
@@ -516,35 +507,15 @@ function CommonBar(props) {
516
507
  show: true,
517
508
  interval: 0,
518
509
  rotate: 0,
519
- // width: 188,
520
510
  overflow: 'truncate',
521
511
  ellipsis: '...',
522
- // formatter: function (value, index) {
523
- // // 检查当前项是否有 platformIcon
524
- // if (yIconFlag) {
525
- // return `{icon${index}|} {label|${value}}`;
526
- // } else {
527
- // return value;
528
- // }
529
- // },
530
512
  formatter: function formatter(value, index) {
531
- var _currentData$index;
532
- // 这一行有没有图标?
533
- var rowHasIcon = !!(yIconFlag && (_currentData$index = currentData[index]) !== null && _currentData$index !== void 0 && _currentData$index.platformIcon);
534
-
535
- // 这一行文本可用的最大宽度(扣除图标)
513
+ var _currentData$index2;
514
+ var rowHasIcon = !!(yIconFlag && (_currentData$index2 = currentData[index]) !== null && _currentData$index2 !== void 0 && _currentData$index2.platformIcon);
536
515
  var maxPx = getMaxTextWidthForRow(rowHasIcon);
537
-
538
- // 得到“中间省略版”文本
539
- var finalText = middleEllipsis(value, maxPx, '14px sans-serif' // 跟 axisLabel 字体保持一致
540
- );
541
-
542
- // 按是否有 icon,返回富文本还是普通文本
543
- if (yIconFlag) {
544
- return "{icon".concat(index, "|} {label|").concat(finalText, "}");
545
- } else {
546
- return finalText;
547
- }
516
+ var finalText = middleEllipsis(value, maxPx, FONT);
517
+ if (yIconFlag) return "{icon".concat(index, "|} {label|").concat(finalText, "}");
518
+ return finalText;
548
519
  }
549
520
  },
550
521
  axisTick: {
@@ -559,52 +530,42 @@ function CommonBar(props) {
559
530
  data: axisData
560
531
  },
561
532
  series: [{
562
- // === 背景柱系列 ===
563
- // 需要背景柱的原因是让柱状条加上后面的数字标签的和不超过悬浮上去的阴影的长度
564
533
  name: '背景条',
565
534
  type: 'bar',
566
- // 让它在最底层
567
535
  z: 1,
568
- // 不需要点击/hover 交互
569
536
  silent: true,
570
- // 让柱子和后面的柱子重叠在同一个类目位置
571
537
  barGap: '-100%',
572
538
  emphasis: {
573
539
  disabled: true
574
540
  },
575
- // 柱子的样式
576
541
  itemStyle: {
577
- color: 'rgba(0, 0, 0, 0)' // 背景色可自定义
542
+ color: 'rgba(0, 0, 0, 0)'
578
543
  },
579
- // 这里的 data 根据正负数使用不同的背景值
580
544
  data: currentData.map(function (item) {
581
- var value = valueAccessor(item);
582
- return value < 0 ? minBgValue : bgValue;
545
+ var v = valueAccessor(item);
546
+ return v < 0 ? xAxisMin : xAxisMax;
583
547
  }),
584
- // 根据你需要的柱宽
585
- // barMaxWidth: 42,
586
- // barMinWidth: 16,
587
548
  barWidth: calculateWidth(seriesData.length),
588
549
  barMinHeight: 4,
550
+ barMinWidth: 4,
589
551
  cursor: 'pointer',
590
552
  animation: false,
591
- showBackground: false // 这层本身不再需要 showBackground
553
+ showBackground: false,
554
+ clip: true
592
555
  }, {
593
556
  type: 'bar',
594
- // showBackground: true,
557
+ clip: false,
558
+ // ✅ 关键:label 即使贴边也不要被裁剪
595
559
  label: {
596
560
  show: true,
597
- // position: 'right',
598
561
  fontWeight: 400,
599
562
  fontSize: 14,
600
563
  color: '#515E5F',
601
- distance: 5,
564
+ distance: LABEL_DISTANCE,
602
565
  formatter: function formatter(params) {
603
- if (showProportion) {
604
- return computeFloat(params.value);
605
- } else {
606
- return numberFormatNull(params.value);
607
- }
566
+ var _params$data$rawValue, _params$data;
567
+ var raw = (_params$data$rawValue = params === null || params === void 0 || (_params$data = params.data) === null || _params$data === void 0 ? void 0 : _params$data.rawValue) !== null && _params$data$rawValue !== void 0 ? _params$data$rawValue : params.value;
568
+ return showProportion ? computeFloat(raw) : numberFormatNull(raw);
608
569
  }
609
570
  },
610
571
  emphasis: {
@@ -615,10 +576,9 @@ function CommonBar(props) {
615
576
  borderWidth: 0,
616
577
  borderType: 'solid'
617
578
  },
618
- // barMaxWidth: 42,
619
- // barMinWidth: 16,
620
579
  barWidth: calculateWidth(seriesData.length),
621
580
  barMinHeight: 4,
581
+ barMinWidth: 4,
622
582
  cursor: 'pointer',
623
583
  animation: false,
624
584
  data: seriesData
@@ -661,9 +621,7 @@ function CommonBar(props) {
661
621
  });
662
622
  myChart.on('showTip', function (_ref) {
663
623
  var dataIndex = _ref.dataIndex;
664
- // 鼠标微移时不重复更新
665
624
  if (dataIndex === lastIndex) return;
666
- // 生成淡化后的数组(只改非当前柱)
667
625
  fadedData = originalData.map(function (d, i) {
668
626
  return _objectSpread(_objectSpread({}, d), {}, {
669
627
  itemStyle: _objectSpread(_objectSpread({}, d.itemStyle || {}), {}, {
@@ -677,12 +635,10 @@ function CommonBar(props) {
677
635
  });
678
636
  myChart.on('hideTip', function () {
679
637
  if (lastIndex === null) return;
680
- // 恢复全部不透明
681
638
  setBarData(myChart, originalData);
682
639
  toggleAxisPointer(myChart, false);
683
640
  lastIndex = null;
684
641
  });
685
- myChart.off('finished');
686
642
  myChart.on('finished', function () {
687
643
  dealBarPath(myDom, true);
688
644
  });
@@ -692,7 +648,6 @@ function CommonBar(props) {
692
648
  element.addEventListener('mouseleave', function (event) {
693
649
  if (event && element.offsetHeight && event.offsetY < element.offsetHeight - 2) {
694
650
  if (lastIndex === null) return;
695
- // 恢复全部不透明
696
651
  setBarData(myChart, originalData);
697
652
  myChart.dispatchAction({
698
653
  type: 'hideTip'