diff --git a/examples/gallery/dynamic/demo/dynamic-bar.ts b/examples/gallery/dynamic/demo/dynamic-bar.ts index 9ea751376f..eae350af18 100644 --- a/examples/gallery/dynamic/demo/dynamic-bar.ts +++ b/examples/gallery/dynamic/demo/dynamic-bar.ts @@ -98,6 +98,7 @@ fetch('../data/china-gdp.json') fill: '#ddd', textAlign: 'end' }, + animate: false, }); chart .interval() @@ -145,6 +146,7 @@ fetch('../data/china-gdp.json') fill: '#ddd', textAlign: 'end' }, + animate: false, }); // @ts-ignore chart.changeData(handleData(Object.values(data)[count])); diff --git a/examples/gallery/dynamic/demo/dynamic-bubble.ts b/examples/gallery/dynamic/demo/dynamic-bubble.ts index 4f8f28b88c..11bdf3c728 100644 --- a/examples/gallery/dynamic/demo/dynamic-bubble.ts +++ b/examples/gallery/dynamic/demo/dynamic-bubble.ts @@ -110,7 +110,7 @@ fetch('../data/life.json') .shape('circle') .animate({ update: { - duration: 300, + duration: 200, easing: 'easeLinear' } }) @@ -159,5 +159,5 @@ fetch('../data/life.json') } countUp(); - interval = setInterval(countUp, 300); + interval = setInterval(countUp, 200); }); diff --git a/src/chart/controller/tooltip.ts b/src/chart/controller/tooltip.ts index 76e10023a8..dee3421fc6 100644 --- a/src/chart/controller/tooltip.ts +++ b/src/chart/controller/tooltip.ts @@ -1,4 +1,6 @@ -import { deepMix, each, find, flatten, get, isArray, isEqual, isFunction, mix } from '@antv/util'; +import { CONTAINER_CLASS } from '@antv/component/lib/tooltip/css-const'; + +import { deepMix, each, find, flatten, get, isArray, isEqual, isFunction, mix, isUndefined } from '@antv/util'; import { Crosshair, HtmlTooltip, IGroup } from '../../dependents'; import Geometry from '../../geometry/base'; import { MappingDatum, Point, TooltipOption } from '../../interface'; @@ -35,6 +37,7 @@ export default class Tooltip extends Controller { private yCrosshair; private guideGroup: IGroup; + private isLocked: boolean = false; private isVisible: boolean = true; private items; private title: string; @@ -46,8 +49,8 @@ export default class Tooltip extends Controller { public init() { } public render() { - this.option = this.view.getOptions().tooltip; - this.isVisible = this.option !== false; + const option = this.view.getOptions().tooltip; + this.isVisible = option !== false; } /** @@ -155,6 +158,36 @@ export default class Tooltip extends Controller { this.view.emit('tooltip:hide', {}); } + /** + * lockTooltip + */ + public lockTooltip() { + this.isLocked = true; + if (this.tooltip) { + // tooltip contianer 可捕获事件 + this.tooltip.setCapture(true); + } + } + + /** + * unlockTooltip + */ + public unlockTooltip() { + this.isLocked = false; + const cfg = this.getTooltipCfg(); + if (this.tooltip) { + // 重置 capture 属性 + this.tooltip.setCapture(cfg.capture); + } + } + + /** + * isTooltipLocked + */ + public isTooltipLocked() { + return this.isLocked; + } + public clear() { const { tooltip, xCrosshair, yCrosshair, tooltipMarkersGroup } = this; if (tooltip) { @@ -198,6 +231,7 @@ export default class Tooltip extends Controller { this.yCrosshair = null; this.tooltip = null; this.guideGroup = null; + this.isLocked = false; } public changeVisible(visible: boolean) { @@ -272,17 +306,18 @@ export default class Tooltip extends Controller { public layout() { } public update() { this.clear(); - // 更新 tooltip 配置 - this.option = this.view.getOptions().tooltip; } // 获取 tooltip 配置,因为用户可能会通过 view.tooltip() 重新配置 tooltip,所以就不做缓存,每次直接读取 private getTooltipCfg() { const view = this.view; - const option = this.option; + const option = view.getOptions().tooltip; const theme = view.getTheme(); const defaultCfg = get(theme, ['components', 'tooltip'], {}); - return deepMix({}, defaultCfg, option); + const enterable = isUndefined(get(option, 'enterable')) ? defaultCfg.enterable : get(option, 'enterable'); + return deepMix({}, defaultCfg, option, { + capture: enterable || this.isLocked ? true : false, + }); } private getTitle(items) { @@ -309,26 +344,6 @@ export default class Tooltip extends Controller { }); tooltip.init(); - - const tooltipContainer = tooltip.get('container'); - if (cfg.enterable === false) { - // 优化体验,在 tooltip dom 上加绑事件 - // 如果 tooltip 不允许进入 - tooltipContainer.onmousemove = event => { - // 避免 tooltip 频繁闪烁 - const point = this.view.getCanvas().getPointByClient(event.clientX, event.clientY); - this.view.emit('plot:mousemove', point); - }; - } - - // 优化:鼠标移入 tooltipContainer 然后再移出时,需要隐藏 tooltip - tooltipContainer.onmouseleave = () => { - if (!this.view.isTooltipLocked()) { - this.hideTooltip(); - } - }; - - this.tooltip = tooltip; } diff --git a/src/chart/view.ts b/src/chart/view.ts index 3959f19b16..9593bd7239 100644 --- a/src/chart/view.ts +++ b/src/chart/view.ts @@ -134,8 +134,6 @@ export class View extends Base { /** 当前鼠标是否在 plot 内(CoordinateBBox) */ private isPreMouseInPlot: boolean = false; - /** tooltip 是否被锁定 */ - private tooltipLocked: boolean; /** 默认标识位,用于判定数据是否更新 */ private isDataChanged: boolean = false; @@ -1012,7 +1010,10 @@ export class View extends Base { * @returns View */ public lockTooltip(): View { - this.tooltipLocked = true; + const tooltip = this.getController('tooltip') as TooltipComponent; + if (tooltip) { + tooltip.lockTooltip(); + } return this; } @@ -1021,7 +1022,10 @@ export class View extends Base { * @returns View */ public unlockTooltip(): View { - this.tooltipLocked = false; + const tooltip = this.getController('tooltip') as TooltipComponent; + if (tooltip) { + tooltip.unlockTooltip(); + } return this; } @@ -1030,7 +1034,8 @@ export class View extends Base { * @returns 是否锁定 */ public isTooltipLocked() { - return this.tooltipLocked; + const tooltip = this.getController('tooltip') as TooltipComponent; + return tooltip && tooltip.isTooltipLocked(); } /** diff --git a/tests/bugs/tooltip-spec.ts b/tests/bugs/tooltip-spec.ts index 88af177d5c..73cf975af7 100644 --- a/tests/bugs/tooltip-spec.ts +++ b/tests/bugs/tooltip-spec.ts @@ -90,45 +90,6 @@ describe('tooltip', () => { expect(tooltipItems.length).toBe(1); }); - it('tooltip avoid', () => { - const data = [ - { year: '1991', value: 15468 }, - { year: '1992', value: 16100 }, - { year: '1993', value: 15900 }, - { year: '1994', value: 17409 }, - { year: '1995', value: 17000 }, - { year: '1996', value: 31056 }, - { year: '1997', value: 31982 }, - { year: '1998', value: 32040 }, - { year: '1999', value: 33233 }, - ]; - const chart = new Chart({ - container: createDiv(), - width: 400, - height: 250, - }); - - chart.data(data); - chart.area().position('year*value'); - - const moveEvent = jest.fn(); - chart.on('plot:mousemove', moveEvent); - - chart.render(); - - const point = chart.getXY({ year: '1995', value: 17000 }); - chart.showTooltip(point); - - const tooltip = chart.ele.getElementsByClassName('g2-tooltip')[0]; - const mousemoveEvent = new MouseEvent('mousemove', { - clientX: 100, - clientY: 100, - }); - tooltip.dispatchEvent(mousemoveEvent); - - expect(moveEvent).toBeCalled(); - }); - it('heatmap tooltip', () => { const chart = new Chart({ container: createDiv(), @@ -157,7 +118,7 @@ describe('tooltip', () => { expect(tooltip).toBeDefined(); }); - it('tooltip hide when mouseleave tooltipContainer', () => { + it('tooltip avoid', () => { const data = [ { year: '1991', value: 15468 }, { year: '1992', value: 16100 }, @@ -177,28 +138,34 @@ describe('tooltip', () => { chart.data(data); chart.area().position('year*value'); - - const moveEvent = jest.fn(); - chart.on('plot:mousemove', moveEvent); - chart.render(); const point = chart.getXY({ year: '1995', value: 17000 }); chart.showTooltip(point); - const tooltip = chart.ele.getElementsByClassName('g2-tooltip')[0]; - const mousemoveEvent = new MouseEvent('mouseleave', { - clientX: 100, - clientY: 100, + // @ts-ignore + expect(chart.ele.getElementsByClassName('g2-tooltip')[0].style['pointer-events']).toBe('none'); + + chart.tooltip({ + enterable: true, }); - tooltip.dispatchEvent(mousemoveEvent); + chart.hideTooltip(); + chart.showTooltip(chart.getXY({ year: '1992', value: 16100 })); // @ts-ignore - expect(tooltip.style.visibility).toBe('hidden'); + expect(chart.ele.getElementsByClassName('g2-tooltip')[0].style['pointer-events']).toBe('auto'); + chart.hideTooltip(); + chart.tooltip({ + enterable: false, + }); chart.lockTooltip(); chart.showTooltip(point); - tooltip.dispatchEvent(mousemoveEvent); // @ts-ignore - expect(tooltip.style.visibility).toBe('visible'); + expect(chart.ele.getElementsByClassName('g2-tooltip')[0].style['pointer-events']).toBe('auto'); + + chart.unlockTooltip(); + chart.showTooltip(chart.getXY({ year: '1992', value: 16100 })); + // @ts-ignore + expect(chart.ele.getElementsByClassName('g2-tooltip')[0].style['pointer-events']).toBe('none'); }); }); diff --git a/tests/unit/chart/view/index-spec.ts b/tests/unit/chart/view/index-spec.ts index 91234eba3f..673c2b0f49 100644 --- a/tests/unit/chart/view/index-spec.ts +++ b/tests/unit/chart/view/index-spec.ts @@ -315,11 +315,15 @@ describe('View', () => { it('lockTooltip', () => { view.lockTooltip(); expect(view.isTooltipLocked()).toBeTrue(); + // @ts-ignore + expect(div.getElementsByClassName('g2-tooltip')[0].style['pointer-events']).toBe('auto'); }); it('unlockTooltip', () => { view.unlockTooltip(); expect(view.isTooltipLocked()).toBeFalse(); + // @ts-ignore + expect(div.getElementsByClassName('g2-tooltip')[0].style['pointer-events']).toBe('none'); }); it('filtered group scale values', () => {