From 70d847fea472e85e2e713b71f75c684f22a2c38d Mon Sep 17 00:00:00 2001 From: MiniPear Date: Tue, 27 Jun 2023 13:25:20 +0800 Subject: [PATCH] feat(tooltip): disableNative (#5236) --- .../api-chart-emit-click-tooltip.spec.ts | 41 +++++++++++++++++ .../api/chart-emit-click-tooltip/step0.html | 1 + .../api/chart-emit-click-tooltip/step1.html | 46 +++++++++++++++++++ .../api/chart-emit-click-tooltip/step2.html | 46 +++++++++++++++++++ .../plots/api/chart-emit-click-tooltip.ts | 40 ++++++++++++++++ __tests__/plots/api/index.ts | 1 + site/docs/spec/interaction/tooltip.zh.md | 37 +++++++-------- .../interaction/interaction/demo/meta.json | 8 ++++ .../interaction/demo/tooltip-click.ts | 25 ++++++++++ src/interaction/tooltip.ts | 35 +++++++++----- 10 files changed, 250 insertions(+), 30 deletions(-) create mode 100644 __tests__/integration/api-chart-emit-click-tooltip.spec.ts create mode 100644 __tests__/integration/snapshots/api/chart-emit-click-tooltip/step0.html create mode 100644 __tests__/integration/snapshots/api/chart-emit-click-tooltip/step1.html create mode 100644 __tests__/integration/snapshots/api/chart-emit-click-tooltip/step2.html create mode 100644 __tests__/plots/api/chart-emit-click-tooltip.ts create mode 100644 site/examples/interaction/interaction/demo/tooltip-click.ts diff --git a/__tests__/integration/api-chart-emit-click-tooltip.spec.ts b/__tests__/integration/api-chart-emit-click-tooltip.spec.ts new file mode 100644 index 0000000000..38828e7482 --- /dev/null +++ b/__tests__/integration/api-chart-emit-click-tooltip.spec.ts @@ -0,0 +1,41 @@ +import { chartEmitClickTooltip as render } from '../plots/api/chart-emit-click-tooltip'; +import { kebabCase } from './utils/kebabCase'; +import { dispatchFirstElementEvent, dispatchPlotEvent } from './utils/event'; +import './utils/useSnapshotMatchers'; +import { createDOMGCanvas } from './utils/createDOMGCanvas'; + +describe('chart.emit', () => { + const dir = `${__dirname}/snapshots/api/${kebabCase(render.name)}`; + const canvas = createDOMGCanvas(640, 480); + + it('chart.tooltip should disable native events.', async () => { + const { finished } = render({ + canvas, + container: document.createElement('div'), + }); + await finished; + + // Disable native events. + dispatchFirstElementEvent(canvas, 'pointerover'); + + await expect(canvas).toMatchDOMSnapshot(dir, 'step0', { + selector: '.g2-tooltip', + }); + + // Click item to show tooltip. + dispatchFirstElementEvent(canvas, 'click', { detail: 1 }); + await expect(canvas).toMatchDOMSnapshot(dir, 'step1', { + selector: '.g2-tooltip', + }); + + // Click plot to hide tooltip. + dispatchPlotEvent(canvas, 'click', { detail: 1 }); + await expect(canvas).toMatchDOMSnapshot(dir, 'step2', { + selector: '.g2-tooltip', + }); + }); + + afterAll(() => { + canvas?.destroy(); + }); +}); diff --git a/__tests__/integration/snapshots/api/chart-emit-click-tooltip/step0.html b/__tests__/integration/snapshots/api/chart-emit-click-tooltip/step0.html new file mode 100644 index 0000000000..ec747fa47d --- /dev/null +++ b/__tests__/integration/snapshots/api/chart-emit-click-tooltip/step0.html @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/__tests__/integration/snapshots/api/chart-emit-click-tooltip/step1.html b/__tests__/integration/snapshots/api/chart-emit-click-tooltip/step1.html new file mode 100644 index 0000000000..4b06720b19 --- /dev/null +++ b/__tests__/integration/snapshots/api/chart-emit-click-tooltip/step1.html @@ -0,0 +1,46 @@ +
+
+ Sports +
+ +
; diff --git a/__tests__/integration/snapshots/api/chart-emit-click-tooltip/step2.html b/__tests__/integration/snapshots/api/chart-emit-click-tooltip/step2.html new file mode 100644 index 0000000000..255353c0f6 --- /dev/null +++ b/__tests__/integration/snapshots/api/chart-emit-click-tooltip/step2.html @@ -0,0 +1,46 @@ +; diff --git a/__tests__/plots/api/chart-emit-click-tooltip.ts b/__tests__/plots/api/chart-emit-click-tooltip.ts new file mode 100644 index 0000000000..21fda88f4f --- /dev/null +++ b/__tests__/plots/api/chart-emit-click-tooltip.ts @@ -0,0 +1,40 @@ +import { Chart } from '../../../src'; + +export function chartEmitClickTooltip(context) { + const { container, canvas } = context; + + const chart = new Chart({ + theme: 'classic', + container: container, + canvas, + }); + + chart + .interval() + .data([ + { genre: 'Sports', sold: 275 }, + { genre: 'Strategy', sold: 115 }, + { genre: 'Action', sold: 120 }, + { genre: 'Shooter', sold: 350 }, + { genre: 'Other', sold: 150 }, + ]) + .encode('x', 'genre') + .encode('y', 'sold') + .encode('color', 'genre') + .interaction('tooltip', { disableNative: true }); + + const finished = chart.render(); + + chart.on('element:click', ({ data }) => { + chart.emit('tooltip:show', { data }); + }); + + chart.on('plot:click', () => { + chart.emit('tooltip:hide'); + }); + + return { + chart, + finished, + }; +} diff --git a/__tests__/plots/api/index.ts b/__tests__/plots/api/index.ts index b89203f4cf..92ca7805f7 100644 --- a/__tests__/plots/api/index.ts +++ b/__tests__/plots/api/index.ts @@ -36,3 +36,4 @@ export { chartEmitBrushHighlightAxisCross } from './chart-emit-brush-highlight-a export { chartEmitScrollbarFilter } from './chart-emit-scrollbar-filter'; export { chartOptionsCompositeMark } from './chart-options-composite-mark'; export { chartEmitItemTooltipHideContent } from './chart-emit-item-tooltip-hide-content'; +export { chartEmitClickTooltip } from './chart-emit-click-tooltip'; diff --git a/site/docs/spec/interaction/tooltip.zh.md b/site/docs/spec/interaction/tooltip.zh.md index 590c0834e5..6319f28d74 100644 --- a/site/docs/spec/interaction/tooltip.zh.md +++ b/site/docs/spec/interaction/tooltip.zh.md @@ -34,23 +34,24 @@ chart.render(); ## 选项 -| 属性 | 描述 | 类型 | 默认值 | -| ------------------------- | ------------------------------------ | ------------------------------------------- | ------ | -| wait | 提示信息更新的时间间隔,单位为毫秒 | `number` | 50 | -| leading | 是否在时间间隔开始的时候更新提示信息 | `boolean` | true | -| trailing | 是否在时间间隔结束的时候更新提示信息 | `boolean` | false | -| shared | 相同 x 的元素是否共享 tooltip | `boolean` | false | -| series | 是否是系列元素的 tooltip | `boolean` | - | -| body | 是否展示 tooltip | `boolean` | true | -| groupName | 是否使用 groupName | `boolean` | true | -| position | tooltip 位置 | `TooltipPosition` | - | -| mount | tooltip 渲染的 dom 节点 | `string` \| `HTMLElement` | 图表容器 | -| bounding | tooltip 渲染的限制区域,超出会自动调整位置 | `BBox` | 图表区域大小 | -| crosshairs | 是否暂时指示线 | `boolean` | - | -| `crosshairs${StyleAttrs}` | 指示线的样式 | `number \| string` | - | -| render | 自定义 tooltip 渲染函数 | `(event, options) => HTMLElement \| string` | - | -| sort | item 排序器 | `(d: TooltipItemValue) => any` | - | -| filter | item 筛选器 | `(d: TooltipItemValue) => any` | - | +| 属性 | 描述 | 类型 | 默认值 | +| ------------------------- | ------------------------------------------- | ------------------------------------------- | ------------ | +| wait | 提示信息更新的时间间隔,单位为毫秒 | `number` | 50 | +| leading | 是否在时间间隔开始的时候更新提示信息 | `boolean` | true | +| trailing | 是否在时间间隔结束的时候更新提示信息 | `boolean` | false | +| shared | 相同 x 的元素是否共享 tooltip | `boolean` | false | +| series | 是否是系列元素的 tooltip | `boolean` | - | +| body | 是否展示 tooltip | `boolean` | true | +| groupName | 是否使用 groupName | `boolean` | true | +| position | tooltip 位置 | `TooltipPosition` | - | +| mount | tooltip 渲染的 dom 节点 | `string` \| `HTMLElement` | 图表容器 | +| bounding | tooltip 渲染的限制区域,超出会自动调整位置 | `BBox` | 图表区域大小 | +| crosshairs | 是否暂时指示线 | `boolean` | - | +| `crosshairs${StyleAttrs}` | 指示线的样式 | `number \| string` | - | +| render | 自定义 tooltip 渲染函数 | `(event, options) => HTMLElement \| string` | - | +| sort | item 排序器 | `(d: TooltipItemValue) => any` | - | +| filter | item 筛选器 | `(d: TooltipItemValue) => any` | - | +| disableNative | 是否响应原生事件(pointerover 和 pointerout) | true | `boolean` | ```ts type TooltipPosition = @@ -63,7 +64,7 @@ type TooltipPosition = | 'bottom-left' | 'bottom-right'; -type BBox = { x: number, y: number, width: number, height: number }; +type BBox = { x: number; y: number; width: number; height: number }; ``` ## 案例 diff --git a/site/examples/interaction/interaction/demo/meta.json b/site/examples/interaction/interaction/demo/meta.json index 62b4c60228..aaa327a819 100644 --- a/site/examples/interaction/interaction/demo/meta.json +++ b/site/examples/interaction/interaction/demo/meta.json @@ -84,6 +84,14 @@ }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*WcxIS4inFuoAAAAAAAAAAAAADmJ7AQ/original" }, + { + "filename": "tooltip-click.ts", + "title": { + "zh": "点击提示", + "en": "Click Tooltip" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*4YDhQZN5FogAAAAAAAAAAAAADmJ7AQ/original" + }, { "filename": "chart-index.ts", "title": { diff --git a/site/examples/interaction/interaction/demo/tooltip-click.ts b/site/examples/interaction/interaction/demo/tooltip-click.ts new file mode 100644 index 0000000000..28154dbd6e --- /dev/null +++ b/site/examples/interaction/interaction/demo/tooltip-click.ts @@ -0,0 +1,25 @@ +import { Chart } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', + theme: 'classic', + autoFit: true, +}); + +chart + .interval() + .data({ + type: 'fetch', + value: + 'https://gw.alipayobjects.com/os/bmw-prod/fb9db6b7-23a5-4c23-bbef-c54a55fee580.csv', + }) + .encode('x', 'letter') + .encode('y', 'frequency') + .axis('y', { labelFormatter: '.0%' }) + .interaction('tooltip', { disableNative: true }); // Disable pointerover and pointerout events. + +chart.on('element:click', ({ data }) => chart.emit('tooltip:show', { data })); + +chart.on('plot:click', () => chart.emit('tooltip:hide')); + +chart.render(); diff --git a/src/interaction/tooltip.ts b/src/interaction/tooltip.ts index 6f526ccde9..5f78f94a4f 100644 --- a/src/interaction/tooltip.ts +++ b/src/interaction/tooltip.ts @@ -379,6 +379,7 @@ export function seriesTooltip( enterable, mount, bounding, + disableNative = false, style: _style = {}, ...rest }: Record, @@ -601,14 +602,18 @@ export function seriesTooltip( emitter.on('tooltip:show', onTooltipShow); emitter.on('tooltip:hide', onTooltipHide); - root.addEventListener('pointerenter', update); - root.addEventListener('pointermove', update); - root.addEventListener('pointerleave', hide); + if (!disableNative) { + root.addEventListener('pointerenter', update); + root.addEventListener('pointermove', update); + root.addEventListener('pointerleave', hide); + } return () => { - root.removeEventListener('pointerenter', update); - root.removeEventListener('pointermove', update); - root.removeEventListener('pointerleave', hide); + if (!disableNative) { + root.removeEventListener('pointerenter', update); + root.removeEventListener('pointermove', update); + root.removeEventListener('pointerleave', hide); + } emitter.off('tooltip:show', onTooltipShow); emitter.off('tooltip:hide', onTooltipHide); destroyTooltip(root); @@ -641,6 +646,7 @@ export function tooltip( mount, bounding, body = true, + disableNative = false, }: Record, ) { const elements = elementsof(root); @@ -730,14 +736,19 @@ export function tooltip( emitter.on('tooltip:show', onTooltipShow); emitter.on('tooltip:hide', onTooltipHide); - root.addEventListener('pointerover', pointerover); - root.addEventListener('pointermove', pointerover); - root.addEventListener('pointerout', pointerout); + if (!disableNative) { + root.addEventListener('pointerover', pointerover); + root.addEventListener('pointermove', pointerover); + root.addEventListener('pointerout', pointerout); + } return () => { - root.removeEventListener('pointerover', pointerover); - root.removeEventListener('pointermove', pointerover); - root.removeEventListener('pointerout', pointerout); + if (!disableNative) { + root.removeEventListener('pointerover', pointerover); + root.removeEventListener('pointermove', pointerover); + root.removeEventListener('pointerout', pointerout); + } + emitter.off('tooltip:show', onTooltipShow); emitter.off('tooltip:hide', onTooltipHide); destroyTooltip(root);