From 5f84026f5de206d5ae666fdbd6339fe60e56e57c Mon Sep 17 00:00:00 2001 From: MiniPear Date: Mon, 10 Jul 2023 14:51:44 +0800 Subject: [PATCH] fix(event): emit events for extended shape --- .../api-chart-on-text-click.spec.ts | 32 +++++++++++++++++++ __tests__/plots/api/chart-on-text-click.ts | 24 ++++++++++++++ __tests__/plots/api/index.ts | 1 + src/interaction/event.ts | 19 ++++++++--- 4 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 __tests__/integration/api-chart-on-text-click.spec.ts create mode 100644 __tests__/plots/api/chart-on-text-click.ts diff --git a/__tests__/integration/api-chart-on-text-click.spec.ts b/__tests__/integration/api-chart-on-text-click.spec.ts new file mode 100644 index 0000000000..13235a4ac9 --- /dev/null +++ b/__tests__/integration/api-chart-on-text-click.spec.ts @@ -0,0 +1,32 @@ +import { chartOnTextClick as render } from '../plots/api/chart-on-text-click'; +import { createDOMGCanvas } from './utils/createDOMGCanvas'; +import { dispatchFirstElementEvent, createPromise } from './utils/event'; +import './utils/useSnapshotMatchers'; +import { ChartEvent } from '../../src'; + +describe('chart.on', () => { + const canvas = createDOMGCanvas(640, 480); + const { finished, chart } = render({ canvas }); + + chart.off(); + + it('chart.on("text:click", callback) should provide datum for item element', async () => { + await finished; + const [fired, resolve] = createPromise(); + chart.on(`text:${ChartEvent.CLICK}`, resolve); + dispatchFirstElementEvent(canvas, 'click', { detail: 1 }); + await fired; + }); + + it('chart.on("element:click", callback) should provide datum for item element', async () => { + await finished; + const [fired, resolve] = createPromise(); + chart.on(`element:${ChartEvent.CLICK}`, resolve); + dispatchFirstElementEvent(canvas, 'click', { detail: 1 }); + await fired; + }); + + afterAll(() => { + canvas?.destroy(); + }); +}); diff --git a/__tests__/plots/api/chart-on-text-click.ts b/__tests__/plots/api/chart-on-text-click.ts new file mode 100644 index 0000000000..e999ffb8d8 --- /dev/null +++ b/__tests__/plots/api/chart-on-text-click.ts @@ -0,0 +1,24 @@ +import { Chart } from '../../../src'; + +export function chartOnTextClick(context) { + const { container, canvas } = context; + + const chart = new Chart({ theme: 'classic', container, canvas }); + + chart.text().style({ + x: 290, // 像素坐标 + y: 200, // 像素坐标 + text: 'hello', + textAlign: 'center', + fontSize: 60, + textBaseline: 'middle', + }); + + chart.on('element:click', () => console.log('click element')); + + chart.on('text:click', () => console.log('click text')); + + const finished = chart.render(); + + return { chart, finished }; +} diff --git a/__tests__/plots/api/index.ts b/__tests__/plots/api/index.ts index c73caaaab9..91fbb08365 100644 --- a/__tests__/plots/api/index.ts +++ b/__tests__/plots/api/index.ts @@ -39,3 +39,4 @@ export { chartEmitItemTooltipHideContent } from './chart-emit-item-tooltip-hide- export { chartEmitClickTooltip } from './chart-emit-click-tooltip'; export { chartChangeDataLegend } from './chart-change-data-legend'; export { chartTooltipMultiChart } from './chart-tooltip-multi-chart'; +export { chartOnTextClick } from './chart-on-text-click'; diff --git a/src/interaction/event.ts b/src/interaction/event.ts index 5df1cb5c40..ade757f11d 100644 --- a/src/interaction/event.ts +++ b/src/interaction/event.ts @@ -14,6 +14,14 @@ export function dataOf(element, view) { return selectedMark.data[index]; } +// For extended shape. +function maybeElementRoot(node) { + if (node.className === 'element') return node; + let root = node.parent; + while (root && root.className !== 'element') root = root.parent; + return root; +} + function bubblesEvent(eventType, view, emitter, predicate = (event) => true) { return (e) => { if (!predicate(e)) return; @@ -26,17 +34,20 @@ function bubblesEvent(eventType, view, emitter, predicate = (event) => true) { // There is no target for pointerupoutside event if out of canvas. if (!target) return; - const { className: elementType, markType } = target; + const { className } = target; // If target area is plot area, do not emit extra events. - if (elementType === 'plot') return; + if (className === 'plot') return; - // Emit wrapped events. + // If target is element or child of element. + const elementRoot = maybeElementRoot(target); + if (!elementRoot) return; + const { className: elementType, markType } = elementRoot; if (elementType === 'element') { const e1 = { ...e, nativeEvent: true, - data: { data: dataOf(target, view) }, + data: { data: dataOf(elementRoot, view) }, }; emitter.emit(`element:${eventType}`, e1); emitter.emit(`${markType}:${eventType}`, e1);