@kylincloud/flamegraph 0.35.20 → 0.35.21
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 +7 -0
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/index.cjs.js +2 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/index.node.cjs.js +4 -4
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/index.node.esm.js +3 -3
- package/dist/index.node.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/Tooltip/Tooltip.module.scss +1 -1
- package/src/Tooltip/Tooltip.tsx +78 -9
package/package.json
CHANGED
package/src/Tooltip/Tooltip.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import React, {
|
|
|
7
7
|
useState,
|
|
8
8
|
useRef,
|
|
9
9
|
useCallback,
|
|
10
|
+
useLayoutEffect,
|
|
10
11
|
Dispatch,
|
|
11
12
|
SetStateAction,
|
|
12
13
|
} from 'react';
|
|
@@ -210,6 +211,52 @@ function getDiffColorByText(
|
|
|
210
211
|
return undefined;
|
|
211
212
|
}
|
|
212
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Tooltip 位置计算:默认右下;若越界则翻到左/上;最终 clamp 到视口内。
|
|
216
|
+
* 注意:Tooltip 使用 position: fixed,因此用 innerWidth/innerHeight 做视口碰撞检测最直接。
|
|
217
|
+
*/
|
|
218
|
+
const TOOLTIP_GAP_X = 12;
|
|
219
|
+
const TOOLTIP_GAP_Y = 20;
|
|
220
|
+
const TOOLTIP_PAD = 8;
|
|
221
|
+
|
|
222
|
+
function clamp(v: number, min: number, max: number) {
|
|
223
|
+
if (max < min) return min;
|
|
224
|
+
return Math.max(min, Math.min(max, v));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function computeSafeTooltipPos(
|
|
228
|
+
x: number,
|
|
229
|
+
y: number,
|
|
230
|
+
tipW: number,
|
|
231
|
+
tipH: number
|
|
232
|
+
) {
|
|
233
|
+
const vw = window.innerWidth;
|
|
234
|
+
const vh = window.innerHeight;
|
|
235
|
+
|
|
236
|
+
const w = Math.max(0, tipW || 0);
|
|
237
|
+
const h = Math.max(0, tipH || 0);
|
|
238
|
+
|
|
239
|
+
// 默认:右下
|
|
240
|
+
let left = x + TOOLTIP_GAP_X;
|
|
241
|
+
let top = y + TOOLTIP_GAP_Y;
|
|
242
|
+
|
|
243
|
+
// 右侧溢出:翻到左边
|
|
244
|
+
if (left + w + TOOLTIP_PAD > vw) {
|
|
245
|
+
left = x - w - TOOLTIP_GAP_X;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// 底部溢出:翻到上边
|
|
249
|
+
if (top + h + TOOLTIP_PAD > vh) {
|
|
250
|
+
top = y - h - TOOLTIP_GAP_Y;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 最终夹取到视口内
|
|
254
|
+
left = clamp(left, TOOLTIP_PAD, vw - w - TOOLTIP_PAD);
|
|
255
|
+
top = clamp(top, TOOLTIP_PAD, vh - h - TOOLTIP_PAD);
|
|
256
|
+
|
|
257
|
+
return { left, top };
|
|
258
|
+
}
|
|
259
|
+
|
|
213
260
|
export function Tooltip({
|
|
214
261
|
shouldShowFooter = true,
|
|
215
262
|
shouldShowTitle = true,
|
|
@@ -219,6 +266,8 @@ export function Tooltip({
|
|
|
219
266
|
palette,
|
|
220
267
|
}: TooltipProps) {
|
|
221
268
|
const tooltipRef = useRef<HTMLDivElement>(null);
|
|
269
|
+
const lastPosRef = useRef<{ x: number; y: number } | null>(null);
|
|
270
|
+
|
|
222
271
|
const [content, setContent] = React.useState({
|
|
223
272
|
title: {
|
|
224
273
|
text: '',
|
|
@@ -245,13 +294,17 @@ export function Tooltip({
|
|
|
245
294
|
throw new Error('Missing tooltipElement');
|
|
246
295
|
}
|
|
247
296
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
window.innerWidth - tooltipRef.current.clientWidth - 20
|
|
251
|
-
);
|
|
252
|
-
const top = e.clientY + 20;
|
|
297
|
+
// 记录最后鼠标位置(给 useLayoutEffect 二次校正用)
|
|
298
|
+
lastPosRef.current = { x: e.clientX, y: e.clientY };
|
|
253
299
|
|
|
300
|
+
// 先更新内容(tooltip 高度可能因此变化)
|
|
254
301
|
setTooltipContent(setContent, onMouseOut, e);
|
|
302
|
+
|
|
303
|
+
// 用当前已渲染的尺寸先算一次位置(内容变化后的真实尺寸会在 useLayoutEffect 再校正)
|
|
304
|
+
const w = tooltipRef.current.clientWidth || 0;
|
|
305
|
+
const h = tooltipRef.current.clientHeight || 0;
|
|
306
|
+
|
|
307
|
+
const { left, top } = computeSafeTooltipPos(e.clientX, e.clientY, w, h);
|
|
255
308
|
setStyle({ top, left, visibility: 'visible' });
|
|
256
309
|
},
|
|
257
310
|
[setTooltipContent]
|
|
@@ -278,6 +331,24 @@ export function Tooltip({
|
|
|
278
331
|
};
|
|
279
332
|
}, [dataSourceRef.current, memoizedOnMouseMove]);
|
|
280
333
|
|
|
334
|
+
// 内容变化后用真实 DOM 尺寸做二次校正,避免“首次显示尺寸尚未更新导致仍越界”
|
|
335
|
+
useLayoutEffect(() => {
|
|
336
|
+
if (!tooltipRef.current) return;
|
|
337
|
+
if (!lastPosRef.current) return;
|
|
338
|
+
if (content.tooltipData.length === 0) return;
|
|
339
|
+
|
|
340
|
+
const { x, y } = lastPosRef.current;
|
|
341
|
+
const rect = tooltipRef.current.getBoundingClientRect();
|
|
342
|
+
const { left, top } = computeSafeTooltipPos(x, y, rect.width, rect.height);
|
|
343
|
+
|
|
344
|
+
setStyle((prev) => {
|
|
345
|
+
if (prev && prev.left === left && prev.top === top && prev.visibility === 'visible') {
|
|
346
|
+
return prev;
|
|
347
|
+
}
|
|
348
|
+
return { ...(prev || {}), left, top, visibility: 'visible' };
|
|
349
|
+
});
|
|
350
|
+
}, [content.tooltipData.length, content.title.text]);
|
|
351
|
+
|
|
281
352
|
return (
|
|
282
353
|
<div
|
|
283
354
|
data-testid="tooltip"
|
|
@@ -460,12 +531,10 @@ function TooltipTable({
|
|
|
460
531
|
<tr>
|
|
461
532
|
<td />
|
|
462
533
|
<td>
|
|
463
|
-
{i18n.self} (
|
|
464
|
-
{i18n.tooltipUnitTitles[baselineData.units].total})
|
|
534
|
+
{i18n.self} ({i18n.tooltipUnitTitles[baselineData.units].total})
|
|
465
535
|
</td>
|
|
466
536
|
<td>
|
|
467
|
-
{i18n.total} (
|
|
468
|
-
{i18n.tooltipUnitTitles[baselineData.units].total})
|
|
537
|
+
{i18n.total} ({i18n.tooltipUnitTitles[baselineData.units].total})
|
|
469
538
|
</td>
|
|
470
539
|
</tr>
|
|
471
540
|
</thead>
|