Skip to content

Commit

Permalink
fix: tooltip.enterable bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
hustcc committed Oct 9, 2023
1 parent b7a71d4 commit fd0f01a
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 44 deletions.
2 changes: 1 addition & 1 deletion __tests__/integration/components/tooltip/tooltip-1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const Tooltip1 = () => {

document.getElementsByTagName('body')[0].appendChild(tooltip.HTMLTooltipElement);
group.addEventListener('mousemove', (e: any) => {
tooltip.position = [e.offsetX, e.offsetY];
tooltip.show(e.offsetX, e.offsetY);
});
group.addEventListener('mouseenter', (e: any) => {
tooltip.show(e.offsetX, e.offsetY);
Expand Down
7 changes: 4 additions & 3 deletions __tests__/integration/components/tooltip/tooltip-10.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,20 @@ export const Tooltip10 = () => {
{ value: 1.2312323, name: '第四项', index: 1, color: 'green' },
{ value: 1.2312323, name: '第五项', index: 1, color: 'blue' },
],
enterable: true,
},
})
);

document.getElementsByTagName('body')[0].appendChild(tooltip.HTMLTooltipElement);
group.addEventListener('mousemove', (e: any) => {
tooltip.position = [e.offsetX, e.offsetY];
tooltip.show(e.offsetX, e.offsetY);
});
group.addEventListener('mouseenter', (e: any) => {
tooltip.show(e.offsetX, e.offsetY);
});
group.addEventListener('mouseleave', () => {
tooltip.hide();
group.addEventListener('mouseleave', (e) => {
tooltip.hide(e.offsetX, e.offsetY);
});

return group;
Expand Down
17 changes: 3 additions & 14 deletions __tests__/integration/components/tooltip/tooltip-2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,26 +56,15 @@ export const Tooltip2 = () => {
);

document.getElementsByTagName('body')[0].appendChild(tooltip.HTMLTooltipElement);
let isPointerInTooltip = false;
group.addEventListener('mousemove', (e: any) => {
tooltip.position = [e.offsetX, e.offsetY];
});
tooltip.getContainer().addEventListener('mouseenter', () => {
isPointerInTooltip = true;
});
tooltip.getContainer().addEventListener('mouseleave', () => {
isPointerInTooltip = false;
tooltip.show(e.offsetX, e.offsetY);
});

group.addEventListener('mouseenter', () => {
tooltip.show();
});
group.addEventListener('mouseleave', () => {
timeout(() => {
if (!isPointerInTooltip) {
tooltip.hide();
}
});
group.addEventListener('mouseleave', (e) => {
tooltip.hide(e.offsetX, e.offsetY);
});
return group;
};
Expand Down
2 changes: 1 addition & 1 deletion __tests__/integration/components/tooltip/tooltip-3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const Tooltip3 = () => {

document.getElementsByTagName('body')[0].appendChild(tooltip.HTMLTooltipElement);
group.addEventListener('mousemove', (e: any) => {
tooltip.position = [e.offsetX, e.offsetY];
tooltip.show(e.offsetX, e.offsetY);
});
group.addEventListener('mouseenter', () => {
tooltip.show();
Expand Down
6 changes: 3 additions & 3 deletions __tests__/integration/components/tooltip/tooltip-4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ export const Tooltip4 = () => {

document.getElementsByTagName('body')[0].appendChild(tooltip.HTMLTooltipElement);
group.addEventListener('mousemove', (e: any) => {
tooltip.position = [e.offsetX, e.offsetY];
tooltip.show(e.offsetX, e.offsetY);
});
group.addEventListener('mouseenter', () => {
tooltip.show();
});
group.addEventListener('mouseleave', () => {
tooltip.hide();
group.addEventListener('mouseleave', (e) => {
tooltip.hide(e.offsetX, e.offsetY);
});
return group;
};
Expand Down
2 changes: 1 addition & 1 deletion __tests__/integration/components/tooltip/tooltip-5.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const Tooltip5 = () => {

document.getElementsByTagName('body')[0].appendChild(tooltip.HTMLTooltipElement);
group.addEventListener('mousemove', (e: any) => {
tooltip.position = [e.offsetX, e.offsetY];
tooltip.show(e.offsetX, e.offsetY);
});
group.addEventListener('mouseenter', () => {
tooltip.show();
Expand Down
2 changes: 1 addition & 1 deletion __tests__/integration/components/tooltip/tooltip-6.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const Tooltip6 = () => {

document.getElementsByTagName('body')[0].appendChild(tooltip.HTMLTooltipElement);
group.addEventListener('mousemove', (e: any) => {
tooltip.position = [e.offsetX, e.offsetY];
tooltip.show(e.offsetX, e.offsetY);
/** 1: 通过 React 渲染Tooltip节点 */
// ReactDOM.render(
// <div>
Expand Down
2 changes: 1 addition & 1 deletion __tests__/integration/components/tooltip/tooltip-7.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const Tooltip7 = () => {
document.getElementsByTagName('body')[0].appendChild(tooltip.HTMLTooltipElement);
}

tooltip.position = [e.offsetX, e.offsetY];
tooltip.show(e.offsetX, e.offsetY);
});
group.addEventListener('mouseenter', (e: any) => {
tooltip?.show(e.offsetX, e.offsetY);
Expand Down
75 changes: 56 additions & 19 deletions src/ui/tooltip/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { substitute, createDOM } from '@antv/util';
import { Component } from '../../core';
import { Group } from '../../shapes';
import { applyStyleSheet, throttle } from '../../util';
import { BBox, applyStyleSheet, throttle } from '../../util';
import { getClassNames, getDefaultTooltipStyle } from './constant';
import type { TooltipOptions, TooltipPosition, TooltipStyleProps } from './types';

Expand All @@ -10,6 +10,8 @@ export type { TooltipStyleProps, TooltipOptions };
export class Tooltip extends Component<TooltipStyleProps> {
public static tag = 'tooltip';

private timestamp = Date.now();

public get HTMLTooltipElement() {
return this.element;
}
Expand All @@ -18,12 +20,6 @@ export class Tooltip extends Component<TooltipStyleProps> {
return this.element;
}

public set position([x, y]: [number, number]) {
this.attributes.x = x;
this.attributes.y = y;
this.updatePosition();
}

private get elementSize() {
const width = this.element.offsetWidth;
const height = this.element.offsetHeight;
Expand Down Expand Up @@ -89,19 +85,32 @@ export class Tooltip extends Component<TooltipStyleProps> {
* 如果设置了坐标值,显示过程中会立即更新位置并关闭过渡动画
*/
public show(x?: number, y?: number) {
const disableTransition = x !== undefined && y !== undefined;
if (disableTransition) {
const transition = this.element.style.transition;
this.element.style.transition = 'none';
this.position = [x ?? +this.attributes.x, y ?? +this.attributes.y];
setTimeout(() => {
this.element.style.transition = transition;
}, 10);
if (x !== undefined && y !== undefined) {
const isToggle = this.element.style.visibility === 'hidden';
const setPosition = () => {
this.attributes.x = x ?? this.attributes.x;
this.attributes.y = y ?? this.attributes.y;
this.updatePosition();
};
// 只有从 hidden 状态变为 visible 状态时才需要关闭过渡动画
isToggle ? this.closeTransition(setPosition) : setPosition();
}
this.element.style.visibility = 'visible';
}

public hide() {
/**
* 如果 hide 时传入了坐标值,那么只有当鼠标不在 tooltip 上时才会隐藏
* 对于 enterable = true 的时候,需要传入 x y,为了避免问题,建议上层在使用的时候,都传入 x y
* @param x
* @param y
* @returns
*/
public hide(x = 0, y = 0) {
const { enterable } = this.attributes;

// 如果当前鼠标在 tooltip 上,则不隐藏
if (enterable && this.isCursorEntered(x, y)) return;

this.element.style.visibility = 'hidden';
}

Expand Down Expand Up @@ -186,10 +195,15 @@ export class Tooltip extends Component<TooltipStyleProps> {
/**
* 更新tooltip的位置
*/
@throttle(100, true)
private updatePosition() {
// 尝试当前的位置使用默认position能否放下
// 如果不能,则改变取溢出边的反向position
const { showDelay = 60 } = this.attributes;

const currentTimestamp = Date.now();
if (currentTimestamp - this.timestamp < showDelay) return;

this.timestamp = currentTimestamp;
// 尝试当前的位置使用默认 position 能否放下
// 如果不能,则改变取溢出边的反向 position
/**
* 默认位置
* ⬇️
Expand Down Expand Up @@ -241,4 +255,27 @@ export class Tooltip extends Component<TooltipStyleProps> {
const correctedPositionString = correctivePosition.join('-');
return this.getRelativeOffsetFromCursor(correctedPositionString as TooltipPosition);
}

private isCursorEntered(cursorX: number, cursorY: number) {
// 是可捕获的,并且点在 tooltip dom 上
if (this.element) {
const { x, y, width, height } = this.element.getBoundingClientRect();
const { container } = this.attributes;
const { x: cx, y: cy } = container;

return new BBox(x - cx, y - cy, width, height).isPointIn(cursorX, cursorY);
}
return false;
}

private closeTransition(callback: () => void) {
const transition = this.element.style.transition;
this.element.style.transition = 'none';

callback();

setTimeout(() => {
this.element.style.transition = transition;
}, 10);
}
}
2 changes: 2 additions & 0 deletions src/ui/tooltip/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export type TooltipStyleProps = GroupStyleProps & {
offset?: [number, number];
/** 指针是否可进入 */
enterable?: boolean;
/** 配合 enterable = true 使用,指定延迟显示的毫秒数,默认为 60ms */
showDelay?: number;
/** 画布的左上角坐标 */
container: {
x: number;
Expand Down
8 changes: 8 additions & 0 deletions src/util/bbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ export class BBox {
left: this.left,
};
}

/**
* 点是否在 bbox 中
* @param p
*/
public isPointIn(x: number, y: number) {
return x >= this.left && x <= this.right && y >= this.top && y <= this.bottom;
}
}

export function getRenderBBox(element: DisplayObject) {
Expand Down

0 comments on commit fd0f01a

Please sign in to comment.