in src/aop/controller/tooltip.tsx [35:208]
public showTooltip(point: Point) {
const cfg = this.getTooltipCfg();
const items = this.getTooltipItems(point);
if (!items?.length) {
return;
}
// 自定义tooltip
if (cfg?.customTooltip) {
// 创建容器
if (!this.tooltipContainer) {
const container = document.createElement('div');
container.className = `${FullCrossName} widgets-tooltip`;
container.style.cssText = `position: fixed;z-index: 1001; pointer-events: none; top: 0; left: 0;`;
document.body.append(container);
this.tooltipContainer = container;
}
this.tooltipContainer.style.visibility = 'visible';
// 图表离开视窗时隐藏tooltip
this.observer = new IntersectionObserver((entries: any[]) => {
for (const entry of entries) {
// 元素离开视口
if (!entry.isIntersecting) {
this.unlockTooltip();
this.hideTooltip();
}
}
});
this.observer.observe(this.parentDom);
// 通过事件手动隐藏tooltip
window.addEventListener(HideTooltipEventName, () => {
this.unlockTooltip();
this.hideTooltip();
});
// 绘制
let title = '';
if (cfg?.showTitle) {
try {
// @ts-ignore
title = this.getTitle(items);
} catch (e) {}
}
// 配置项处理
const config = (this?.view as any)?.widgetsCtx?.mergeConfig ?? {};
// 进位相关配置项
let formatConfig: any;
// 当tooltip中配置了单位相关信息时,直接使用tooltip的配置项,否则使用y轴配置项
if (
typeof config?.tooltip === 'object' &&
(config?.tooltip?.valueType ||
config?.tooltip?.unit ||
config?.tooltip?.needUnitTransform ||
config?.tooltip?.unitTransformTo)
) {
formatConfig = config.tooltip;
} else if (Array.isArray(config.yAxis) && config.yAxis.length >= 2) {
// 双轴
formatConfig = config.yAxis;
} else if (Array.isArray(config.yAxis)) {
formatConfig = config?.yAxis?.[0] ?? {};
} else {
formatConfig = config?.yAxis ?? {};
}
// const customValueFormatter = customFormatter(formatConfig);
items.forEach((item: any, index: number) => {
// @ts-ignore
const raw = getRawData(config, this?.view?.widgetsCtx?.rawData, item);
if (config?.tooltip?.valueFormatter) {
item.value = config?.tooltip?.valueFormatter(item.value, raw, index, items);
} else {
let customValueFormatter = null;
if (Array.isArray(formatConfig)) {
// 双轴
customValueFormatter =
'y1' in item?.data
? customFormatter(formatConfig[1])
: customFormatter(formatConfig[0]);
} else {
// 单轴
customValueFormatter = customFormatter(formatConfig);
}
if (customValueFormatter) {
item.value = customValueFormatter(item.value);
}
}
if (item.name.startsWith('undefined-name-')) {
item.name = '';
} else if (config?.tooltip?.nameFormatter) {
item.name = config?.tooltip?.nameFormatter(item.name, raw, index, items);
}
});
const element =
cfg.customTooltip === true ? (
<FreeTooltip title={title} data={items} />
) : (
cfg.customTooltip(title, items)
);
ReactDOM.render(element, this.tooltipContainer);
// 计算位置
const padding = 10;
const position = {
x: point.x + padding,
y: point.y,
};
const parentRect = this.parentDom.getBoundingClientRect();
position.x += parentRect.left;
position.y += parentRect.top;
const tooltipRect = this.tooltipContainer.getBoundingClientRect();
const bodyWidth = document.body.clientWidth;
const bodyHeight = document.body.clientHeight;
if (
position.x + tooltipRect.width > bodyWidth &&
position.x - tooltipRect.width - padding * 2 >= 0
) {
// 超过屏幕时移至左边
position.x = position.x - tooltipRect.width - padding * 2;
}
if (
position.y + tooltipRect.height > bodyHeight &&
position.y - tooltipRect.height - padding >= 0
) {
// 超过屏幕时移至上方
position.y = position.y - tooltipRect.height - padding;
}
// 定位
// @ts-ignore
this.tooltipContainer.style.transform = `translate3d(${position.x}px, ${position.y}px, 0px)`;
// this.tooltipContainer.style.top = `${position.y}px`;
// @ts-ignore
// this.tooltipContainer.style.left = `${position.x}px`;
if (cfg?.showMarkers) {
// @ts-ignore
this.renderTooltipMarkers(items, cfg.marker);
}
// 显示辅助线
if (cfg?.showCrosshairs && items?.length) {
const dataPoint = {
x: items[0]?.x,
y: items[0]?.y,
}; // 数据点位置
const isCrosshairsFollowCursor = cfg?.crosshairs?.follow || false;
// @ts-ignore
super.renderCrosshairs(isCrosshairsFollowCursor ? point : dataPoint, cfg);
}
} else {
super.showTooltip(point);
}
// 开启锁定时绘制锁定icon
if (cfg?.lockable) {
this.drawLockElement(false);
}
}