From 01d40be6607ee4924f192391ec0d43ac9a2739ad Mon Sep 17 00:00:00 2001 From: MiniPear Date: Tue, 5 Sep 2023 19:51:58 +0800 Subject: [PATCH] feat(interaction): emit more brush and tooltip events --- ...-chart-emit-enable-disable-tooltip.spec.ts | 103 ++++++++++++++++ ...i-chart-on-brush-highlight-tooltip.spec.ts | 41 +++++++ .../step0.html | 1 + .../step1.html | 46 +++++++ .../step2.html | 46 +++++++ .../step3.html | 1 + .../api/chart-on-brush-highlight-tooltip.ts | 99 ++++++++++++++++ __tests__/plots/api/index.ts | 1 + .../plots/interaction/penguins-point-brush.ts | 2 +- .../spec/interaction/brushHighlight.zh.md | 27 +++++ site/docs/spec/interaction/tooltip.zh.md | 7 ++ .../interaction/brush/demo/brush-emit.ts | 91 ++++++++++++++ site/examples/interaction/brush/demo/brush.ts | 19 ++- .../examples/interaction/brush/demo/meta.json | 8 ++ src/index.ts | 1 + src/interaction/brushHighlight.ts | 29 ++++- src/interaction/tooltip.ts | 112 ++++++++++++------ src/runtime/constant.ts | 1 + 18 files changed, 593 insertions(+), 42 deletions(-) create mode 100644 __tests__/integration/api-chart-emit-enable-disable-tooltip.spec.ts create mode 100644 __tests__/integration/api-chart-on-brush-highlight-tooltip.spec.ts create mode 100644 __tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step0.html create mode 100644 __tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step1.html create mode 100644 __tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step2.html create mode 100644 __tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step3.html create mode 100644 __tests__/plots/api/chart-on-brush-highlight-tooltip.ts create mode 100644 site/examples/interaction/brush/demo/brush-emit.ts diff --git a/__tests__/integration/api-chart-emit-enable-disable-tooltip.spec.ts b/__tests__/integration/api-chart-emit-enable-disable-tooltip.spec.ts new file mode 100644 index 0000000000..e28301f22d --- /dev/null +++ b/__tests__/integration/api-chart-emit-enable-disable-tooltip.spec.ts @@ -0,0 +1,103 @@ +import './utils/useSnapshotMatchers'; +import { Chart } from '../../src'; +import { createDOMGCanvas } from './utils/createDOMGCanvas'; +import { sleep } from './utils/sleep'; +import { dispatchFirstElementEvent, dispatchPlotEvent } from './utils/event'; +import { kebabCase } from './utils/kebabCase'; + +const data = [ + { date: '2007-04-23', close: 93.24 }, + { date: '2007-04-24', close: 95.35 }, + { date: '2007-04-25', close: 98.84 }, + { date: '2007-04-26', close: 99.92 }, + { date: '2007-04-29', close: 99.8 }, + { date: '2007-05-01', close: 99.47 }, + { date: '2007-05-02', close: 100.39 }, + { date: '2007-05-03', close: 100.4 }, + { date: '2007-05-04', close: 100.81 }, + { date: '2007-05-07', close: 103.92 }, +]; + +function renderBar({ canvas, container }) { + const chart = new Chart({ canvas, container }); + chart.options({ + type: 'interval', + data, + encode: { x: 'date', y: 'close' }, + }); + const finished = chart.render(); + return { chart, finished }; +} + +function renderLine({ canvas, container }) { + const chart = new Chart({ canvas, container }); + chart.options({ + type: 'line', + data, + encode: { x: 'date', y: 'close' }, + }); + const finished = chart.render(); + return { chart, finished }; +} + +describe('chart.emit', () => { + const dir = `${__dirname}/snapshots/api/${kebabCase( + 'chartEmitEnableDisableTooltip', + )}`; + const barCanvas = createDOMGCanvas(640, 480); + const lineCanvas = createDOMGCanvas(640, 480); + + it('chart.emit enable item tooltip.', async () => { + const { finished, chart } = renderBar({ + canvas: barCanvas, + container: document.createElement('div'), + }); + await finished; + + chart.emit('tooltip:disable'); + await sleep(20); + + dispatchFirstElementEvent(barCanvas, 'pointerover'); + await expect(barCanvas).toMatchDOMSnapshot(dir, 'step0', { + selector: '.g2-tooltip', + }); + + chart.emit('tooltip:enable'); + + dispatchFirstElementEvent(barCanvas, 'pointerover'); + await expect(barCanvas).toMatchDOMSnapshot(dir, 'step1', { + selector: '.g2-tooltip', + }); + }); + + it('chart.emit enable series tooltip.', async () => { + const { finished, chart } = renderLine({ + canvas: lineCanvas, + container: document.createElement('div'), + }); + await finished; + + chart.emit('tooltip:disable'); + dispatchPlotEvent(lineCanvas, 'pointermove', { + offsetX: 100, + offsetY: 100, + }); + await expect(lineCanvas).toMatchDOMSnapshot(dir, 'step2', { + selector: '.g2-tooltip', + }); + + chart.emit('tooltip:enable'); + dispatchPlotEvent(lineCanvas, 'pointermove', { + offsetX: 100, + offsetY: 100, + }); + await expect(lineCanvas).toMatchDOMSnapshot(dir, 'step3', { + selector: '.g2-tooltip', + }); + }); + + afterAll(() => { + barCanvas?.destroy(); + lineCanvas?.destroy(); + }); +}); diff --git a/__tests__/integration/api-chart-on-brush-highlight-tooltip.spec.ts b/__tests__/integration/api-chart-on-brush-highlight-tooltip.spec.ts new file mode 100644 index 0000000000..49656f09bd --- /dev/null +++ b/__tests__/integration/api-chart-on-brush-highlight-tooltip.spec.ts @@ -0,0 +1,41 @@ +import { chartOnBrushHighlightTooltip as render } from '../plots/api/chart-on-brush-highlight-tooltip'; +import { brush, dragMask } from '../plots/interaction/penguins-point-brush'; +import './utils/useSnapshotMatchers'; +import { PLOT_CLASS_NAME } from '../../src'; +import { createPromise } from './utils/event'; +import { createDOMGCanvas } from './utils/createDOMGCanvas'; +import { sleep } from './utils/sleep'; + +describe('chart.on', () => { + const canvas = createDOMGCanvas(640, 480); + + it('chart.on should on brush events.', async () => { + const { finished, chart } = render({ + canvas, + container: document.createElement('div'), + }); + await finished; + + const { document: gDocument } = canvas; + const plot = gDocument.getElementsByClassName(PLOT_CLASS_NAME)[0]; + + const [start, resolveStart] = createPromise(); + const [create, resolveCreate] = createPromise(); + chart.on('brush:start', resolveStart); + chart.on('brush:create', resolveCreate); + brush(plot, 100, 100, 300, 300); + await start; + await create; + await sleep(20); + + const [update, resolveUpdate] = createPromise(); + chart.on('brush:update', resolveUpdate); + dragMask(plot, 30, 30, 60, 60); + await update; + await sleep(20); + }); + + afterAll(() => { + canvas?.destroy(); + }); +}); diff --git a/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step0.html b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step0.html new file mode 100644 index 0000000000..ec747fa47d --- /dev/null +++ b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step0.html @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step1.html b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step1.html new file mode 100644 index 0000000000..5c7540989c --- /dev/null +++ b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step1.html @@ -0,0 +1,46 @@ +
+
+ 2007-04-23 +
+ +
\ No newline at end of file diff --git a/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step2.html b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step2.html new file mode 100644 index 0000000000..5c7540989c --- /dev/null +++ b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step2.html @@ -0,0 +1,46 @@ +
+
+ 2007-04-23 +
+ +
\ No newline at end of file diff --git a/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step3.html b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step3.html new file mode 100644 index 0000000000..ec747fa47d --- /dev/null +++ b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step3.html @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/__tests__/plots/api/chart-on-brush-highlight-tooltip.ts b/__tests__/plots/api/chart-on-brush-highlight-tooltip.ts new file mode 100644 index 0000000000..5abb334eb2 --- /dev/null +++ b/__tests__/plots/api/chart-on-brush-highlight-tooltip.ts @@ -0,0 +1,99 @@ +import { Chart, MASK_CLASS_NAME } from '../../../src'; + +function useTip({ container, onRemove = () => {}, offsetX = 20, offsetY = 0 }) { + let div; + + const render = (data, [x, y]) => { + if (div) remove(); + div = document.createElement('div'); + div.innerHTML = ` + Select a node: + + `; + div.style.position = 'absolute'; + div.style.background = '#eee'; + div.style.padding = '0.5em'; + div.style.left = x + offsetX + 'px'; + div.style.top = y + offsetY + 'px'; + div.onclick = () => { + remove(); + onRemove(); + }; + container.append(div); + }; + + const remove = () => { + if (div) div.remove(); + div = null; + }; + + return [render, remove] as const; +} + +export function chartOnBrushHighlightTooltip(context) { + const { container, canvas } = context; + + const chart = new Chart({ + container, + canvas, + }); + + const data = [ + { date: '2007-04-23', close: 93.24 }, + { date: '2007-04-24', close: 95.35 }, + { date: '2007-04-25', close: 98.84 }, + { date: '2007-04-26', close: 99.92 }, + { date: '2007-04-29', close: 99.8 }, + { date: '2007-05-01', close: 99.47 }, + { date: '2007-05-02', close: 100.39 }, + { date: '2007-05-03', close: 100.4 }, + { date: '2007-05-04', close: 100.81 }, + { date: '2007-05-07', close: 103.92 }, + ]; + + chart + .line() + .data(data) + .encode('x', (d) => new Date(d.date)) + .encode('y', 'close') + .scale('y', { nice: true }) + .interaction('brushXHighlight', true); + + const [render, remove] = useTip({ + container, + onRemove: () => chart.emit('brush:remove', {}), + }); + + chart.on('brush:start', onStart); + chart.on('brush:create', onUpdate); + chart.on('brush:update', onUpdate); + chart.on('brush:remove', onRemove); + + const finished = chart.render(); + + function onStart() { + chart.emit('tooltip:disable'); + } + + function onUpdate(e) { + const { canvas } = chart.getContext(); + // @ts-ignore + const [mask] = canvas.document.getElementsByClassName(MASK_CLASS_NAME); + const bounds = mask.getBounds(); + const x = bounds.max[0]; + const y = bounds.center[1]; + const [X] = e.data.selection; + const filtered = data.filter( + ({ date }) => new Date(date) >= X[0] && new Date(date) <= X[1], + ); + render(filtered, [x, y]); + } + + function onRemove(e) { + const { nativeEvent } = e; + if (nativeEvent) remove(); + chart.emit('tooltip:enable'); + } + + return { chart, finished }; +} diff --git a/__tests__/plots/api/index.ts b/__tests__/plots/api/index.ts index b34773393f..db8cc1baa5 100644 --- a/__tests__/plots/api/index.ts +++ b/__tests__/plots/api/index.ts @@ -47,3 +47,4 @@ export { chartRender3dScatterPlotPerspective } from './chart-render-3d-scatter-p export { chartRender3dScatterPlotLegend } from './chart-render-3d-scatter-plot-legend'; export { chartRender3dLinePlot } from './chart-render-3d-line-plot'; export { chartRender3dLinePlotPerspective } from './chart-render-3d-line-plot-perspective'; +export { chartOnBrushHighlightTooltip } from './chart-on-brush-highlight-tooltip'; diff --git a/__tests__/plots/interaction/penguins-point-brush.ts b/__tests__/plots/interaction/penguins-point-brush.ts index fe111d057f..026a08c1eb 100644 --- a/__tests__/plots/interaction/penguins-point-brush.ts +++ b/__tests__/plots/interaction/penguins-point-brush.ts @@ -72,7 +72,7 @@ export function drag(shape, x, y, x1, y1) { }), ); shape.dispatchEvent( - new CustomEvent('drag', { + new CustomEvent('dragend', { // @ts-ignore offsetX: x1, offsetY: y1, diff --git a/site/docs/spec/interaction/brushHighlight.zh.md b/site/docs/spec/interaction/brushHighlight.zh.md index 2defa497dc..bec8dfc708 100644 --- a/site/docs/spec/interaction/brushHighlight.zh.md +++ b/site/docs/spec/interaction/brushHighlight.zh.md @@ -206,3 +206,30 @@ chart.options({ }, }); ``` + +### 监听事件 + +支持以下的事件: + +- `brush:create` - 创建 brush 完成的时候触发 +- `brush:update` - brush 更新大小和位置完成时候触发 +- `brush:highlight` - brush 改变大小和位置时出发 +- `brush:remove` - brush 移除的时候触发 + +```js +chart.on('brush:highlight', (e) => { + console.log(e.data.selection); + console.log(e.nativeEvent); +}); +``` + +### 触发交互 + +支持以下的事件: + +- `brush:highlight` - 高亮数据 +- `brush:remove` - 移除 brush + +```js +chart.emit('brush:remove'); +``` diff --git a/site/docs/spec/interaction/tooltip.zh.md b/site/docs/spec/interaction/tooltip.zh.md index 6bb2239d0f..1a05611cf5 100644 --- a/site/docs/spec/interaction/tooltip.zh.md +++ b/site/docs/spec/interaction/tooltip.zh.md @@ -166,3 +166,10 @@ chart.render((chart) => ```js chart.emit('tooltip:hide'); ``` + +### 开始/禁止交互 + +```js +chart.emit('tooltip:disable'); // 禁用 tooltip +chart.emit('tooltip:enable'); // 启用交互 +``` diff --git a/site/examples/interaction/brush/demo/brush-emit.ts b/site/examples/interaction/brush/demo/brush-emit.ts new file mode 100644 index 0000000000..9efa399c96 --- /dev/null +++ b/site/examples/interaction/brush/demo/brush-emit.ts @@ -0,0 +1,91 @@ +import { Chart, MASK_CLASS_NAME } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', +}); + +const [render, remove] = useTip({ + container: document.getElementById('container'), + onRemove: () => chart.emit('brush:remove', {}), +}); + +const data = [ + { date: '2007-04-23', close: 93.24 }, + { date: '2007-04-24', close: 95.35 }, + { date: '2007-04-25', close: 98.84 }, + { date: '2007-04-26', close: 99.92 }, + { date: '2007-04-29', close: 99.8 }, + { date: '2007-05-01', close: 99.47 }, + { date: '2007-05-02', close: 100.39 }, + { date: '2007-05-03', close: 100.4 }, + { date: '2007-05-04', close: 100.81 }, + { date: '2007-05-07', close: 103.92 }, +]; + +chart + .line() + .data(data) + .encode('x', (d) => new Date(d.date)) + .encode('y', 'close') + .scale('y', { nice: true }) + .interaction('brushXHighlight', true); + +chart.on('brush:start', onStart); +chart.on('brush:create', onUpdate); +chart.on('brush:update', onUpdate); +chart.on('brush:remove', onRemove); + +chart.render(); + +function onStart() { + chart.emit('tooltip:disable'); +} + +function onUpdate(e) { + const { canvas } = chart.getContext(); + const [mask] = canvas.document.getElementsByClassName(MASK_CLASS_NAME); + const bounds = mask.getBounds(); + const x = bounds.max[0]; + const y = bounds.center[1]; + const [X] = e.data.selection; + const filtered = data.filter( + ({ date }) => new Date(date) >= X[0] && new Date(date) <= X[1], + ); + render(filtered, [x, y]); +} + +function onRemove(e) { + const { nativeEvent } = e; + if (nativeEvent) remove(); + chart.emit('tooltip:enable'); +} + +function useTip({ container, onRemove = () => {}, offsetX = 20, offsetY = 0 }) { + let div; + + const render = (data, [x, y]) => { + if (div) remove(); + div = document.createElement('div'); + div.innerHTML = ` + Select a node: + + `; + div.style.position = 'absolute'; + div.style.background = '#eee'; + div.style.padding = '0.5em'; + div.style.left = x + offsetX + 'px'; + div.style.top = y + offsetY + 'px'; + div.onclick = () => { + remove(); + onRemove(); + }; + container.append(div); + }; + + const remove = () => { + if (div) div.remove(); + div = null; + }; + + return [render, remove]; +} diff --git a/site/examples/interaction/brush/demo/brush.ts b/site/examples/interaction/brush/demo/brush.ts index 6702b32c17..e4465c164b 100644 --- a/site/examples/interaction/brush/demo/brush.ts +++ b/site/examples/interaction/brush/demo/brush.ts @@ -9,13 +9,22 @@ chart .point() .data({ type: 'fetch', - value: - 'https://gw.alipayobjects.com/os/basement_prod/6b4aa721-b039-49b9-99d8-540b3f87d339.json', + value: 'https://gw.alipayobjects.com/os/antvdemo/assets/data/scatter.json', }) - .encode('x', 'height') - .encode('y', 'weight') + .encode('x', 'weight') + .encode('y', 'height') .encode('color', 'gender') - .state({ inactive: { stroke: 'gray', opacity: 0.5 } }) + .encode('shape', 'point') + .style({ + fillOpacity: 0.7, + transform: 'scale(1, 1)', + transformOrigin: 'center center', + }) + .state('inactive', { + fill: 'black', + fillOpacity: 0.5, + transform: 'scale(0.5, 0.5)', + }) .interaction('brushHighlight', true); chart.render(); diff --git a/site/examples/interaction/brush/demo/meta.json b/site/examples/interaction/brush/demo/meta.json index 8ab3d48d55..abf597f7c7 100644 --- a/site/examples/interaction/brush/demo/meta.json +++ b/site/examples/interaction/brush/demo/meta.json @@ -11,6 +11,14 @@ "en": "Brush" }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*XbQtTrYgA88AAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "brush-emit.ts", + "title": { + "zh": "刷选事件", + "en": "Brush" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*CpEHQ52tUfkAAAAAAAAAAAAADmJ7AQ/original" } ] } diff --git a/src/index.ts b/src/index.ts index 597e3d85e8..180cd251ba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,7 @@ export { COMPONENT_CLASS_NAME, LABEL_CLASS_NAME, AREA_CLASS_NAME, + MASK_CLASS_NAME, } from './runtime'; export { diff --git a/src/interaction/brushHighlight.ts b/src/interaction/brushHighlight.ts index 22d233a70f..b901d541b3 100644 --- a/src/interaction/brushHighlight.ts +++ b/src/interaction/brushHighlight.ts @@ -217,6 +217,8 @@ export function brush( brushed = () => {}, brushended = () => {}, brushcreated = () => {}, + brushstarted = () => {}, + brushupdated = () => {}, extent = bboxOf(root), brushRegion = (x, y, x1, y1, extent) => [x, y, x1, y1], reverse = false, @@ -249,7 +251,8 @@ export function brush( root.style.draggable = true; // Make it response to drag event. // Remove old mask and init new mask. - const initMask = (x, y) => { + const initMask = (x, y, event) => { + brushstarted(event); if (mask) mask.remove(); if (background) background.remove(); start = [x, y]; @@ -395,7 +398,7 @@ export function brush( const { target } = event; const [offsetX, offsetY] = brushMousePosition(root, event); if (!mask || !isMask(target)) { - initMask(offsetX, offsetY); + initMask(offsetX, offsetY, event); creating = true; return; } @@ -435,6 +438,7 @@ export function brush( const { x, y, width, height } = mask.style; start = [x, y]; end = [x + width, y + height]; + brushupdated(x, y, x + width, y + height, event); return; } end = brushMousePosition(root, event); @@ -471,7 +475,7 @@ export function brush( return { mask, move(x, y, x1, y1, emit = true) { - if (!mask) initMask(x, y); + if (!mask) initMask(x, y, {}); start = [x, y]; end = [x1, y1]; updateMask([x, y], [x1, y1], emit); @@ -645,6 +649,25 @@ export function brushHighlight( const handler = series ? seriesBrushed : brushed; handler(x, y, x1, y1); }, + brushcreated: (x, y, x1, y1, event) => { + const selection = selectionOf(x, y, x1, y1, scale, coordinate); + emitter.emit('brush:create', { + ...event, + nativeEvent: true, + data: { selection }, + }); + }, + brushupdated: (x, y, x1, y1, event) => { + const selection = selectionOf(x, y, x1, y1, scale, coordinate); + emitter.emit('brush:update', { + ...event, + nativeEvent: true, + data: { selection }, + }); + }, + brushstarted: (e) => { + emitter.emit('brush:start', e); + }, }); // Move brush and highlight data. diff --git a/src/interaction/tooltip.ts b/src/interaction/tooltip.ts index 5717caec1d..8266f23887 100644 --- a/src/interaction/tooltip.ts +++ b/src/interaction/tooltip.ts @@ -140,7 +140,7 @@ function showTooltip({ parent.tooltipElement = tooltipElement; } -function hideTooltip({ root, single, emitter, nativeEvent = true, mount }) { +function hideTooltip({ root, single, emitter, nativeEvent = true }) { if (nativeEvent) { emitter.emit('tooltip:hide', { nativeEvent }); } @@ -152,11 +152,13 @@ function hideTooltip({ root, single, emitter, nativeEvent = true, mount }) { } } -function destroyTooltip(root) { - const { tooltipElement } = root; +function destroyTooltip({ root, single }) { + const canvasContainer = root.getRootNode().defaultView.getConfig().container; + const parent = single ? canvasContainer : root; + const { tooltipElement } = parent; if (tooltipElement) { tooltipElement.destroy(); - root.tooltipElement = undefined; + parent.tooltipElement = undefined; } } @@ -627,7 +629,13 @@ export function seriesTooltip( ) as (...args: any[]) => void; const hide = () => { - hideTooltip({ root, single, emitter, mount }); + hideTooltip({ root, single, emitter }); + if (crosshairs) hideRuleY(root); + if (marker) hideMarker(root); + }; + + const destroy = () => { + destroyTooltip({ root, single }); if (crosshairs) hideRuleY(root); if (marker) hideMarker(root); }; @@ -645,29 +653,48 @@ export function seriesTooltip( }; const onTooltipHide = () => { - hideTooltip({ root, single, emitter, nativeEvent: false, mount }); + hideTooltip({ root, single, emitter, nativeEvent: false }); }; - emitter.on('tooltip:show', onTooltipShow); - emitter.on('tooltip:hide', onTooltipHide); + const onTooltipDisable = () => { + removeEventListeners(); + destroy(); + }; - if (!disableNative) { - root.addEventListener('pointerenter', update); - root.addEventListener('pointermove', update); - root.addEventListener('pointerleave', hide); - } + const onTooltipEnable = () => { + addEventListeners(); + }; - return () => { + const addEventListeners = () => { + if (!disableNative) { + root.addEventListener('pointerenter', update); + root.addEventListener('pointermove', update); + root.addEventListener('pointerleave', hide); + } + }; + + const removeEventListeners = () => { if (!disableNative) { root.removeEventListener('pointerenter', update); root.removeEventListener('pointermove', update); root.removeEventListener('pointerleave', hide); } + }; + + addEventListeners(); + + emitter.on('tooltip:show', onTooltipShow); + emitter.on('tooltip:hide', onTooltipHide); + emitter.on('tooltip:disable', onTooltipDisable); + emitter.on('tooltip:enable', onTooltipEnable); + + return () => { + removeEventListeners(); emitter.off('tooltip:show', onTooltipShow); emitter.off('tooltip:hide', onTooltipHide); - destroyTooltip(root); - if (crosshairs) hideRuleY(root); - if (marker) hideMarker(root); + emitter.off('tooltip:disable', onTooltipDisable); + emitter.off('tooltip:enable', onTooltipEnable); + destroy(); }; } @@ -707,7 +734,7 @@ export function tooltip( (event) => { const { target: element } = event; if (!elementSet.has(element)) { - hideTooltip({ root, single, emitter, mount }); + hideTooltip({ root, single, emitter }); return; } const k = groupKey(element); @@ -726,7 +753,7 @@ export function tooltip( } if (isEmptyTooltipData(data)) { - hideTooltip({ root, single, emitter, mount }); + hideTooltip({ root, single, emitter }); return; } @@ -762,7 +789,24 @@ export function tooltip( const pointerout = (event) => { const { target: element } = event; if (!elementSet.has(element)) return; - hideTooltip({ root, single, emitter, mount }); + hideTooltip({ root, single, emitter }); + }; + + const addEventListeners = () => { + if (!disableNative) { + root.addEventListener('pointerover', pointerover); + root.addEventListener('pointermove', pointerover); + root.addEventListener('pointerout', pointerout); + } + }; + + const removeEventListeners = () => { + if (!disableNative) { + root.removeEventListener('pointerover', pointerover); + root.removeEventListener('pointermove', pointerover); + root.removeEventListener('pointerout', pointerout); + } + destroyTooltip({ root, single }); }; const onTooltipShow = ({ nativeEvent, data }) => { @@ -780,28 +824,30 @@ export function tooltip( const onTooltipHide = ({ nativeEvent }: any = {}) => { if (nativeEvent) return; - hideTooltip({ root, single, emitter, nativeEvent: false, mount }); + hideTooltip({ root, single, emitter, nativeEvent: false }); + }; + + const onTooltipDisable = () => { + removeEventListeners(); + destroyTooltip({ root, single }); + }; + + const onTooltipEnable = () => { + addEventListeners(); }; emitter.on('tooltip:show', onTooltipShow); emitter.on('tooltip:hide', onTooltipHide); + emitter.on('tooltip:enable', onTooltipEnable); + emitter.on('tooltip:disable', onTooltipDisable); - if (!disableNative) { - root.addEventListener('pointerover', pointerover); - root.addEventListener('pointermove', pointerover); - root.addEventListener('pointerout', pointerout); - } + addEventListeners(); return () => { - if (!disableNative) { - root.removeEventListener('pointerover', pointerover); - root.removeEventListener('pointermove', pointerover); - root.removeEventListener('pointerout', pointerout); - } - + removeEventListeners(); emitter.off('tooltip:show', onTooltipShow); emitter.off('tooltip:hide', onTooltipHide); - destroyTooltip(root); + destroyTooltip({ root, single }); }; } diff --git a/src/runtime/constant.ts b/src/runtime/constant.ts index 34ee9e1b42..174adeef29 100644 --- a/src/runtime/constant.ts +++ b/src/runtime/constant.ts @@ -6,3 +6,4 @@ export const PLOT_CLASS_NAME = 'plot'; export const COMPONENT_CLASS_NAME = 'component'; export const LABEL_CLASS_NAME = 'label'; export const AREA_CLASS_NAME = 'area'; +export const MASK_CLASS_NAME = 'mask';