diff --git a/__tests__/integration/api-chart-render-clear-interaction.spec.ts b/__tests__/integration/api-chart-render-clear-interaction.spec.ts new file mode 100644 index 0000000000..4196c9672c --- /dev/null +++ b/__tests__/integration/api-chart-render-clear-interaction.spec.ts @@ -0,0 +1,35 @@ +import { CustomEvent as GCustomEvent } from '@antv/g'; +import { chartRenderClearInteraction as render } from '../plots/api/chart-render-clear-interaction'; +import { PLOT_CLASS_NAME } from '../../src'; +import { createDOMGCanvas } from './utils/createDOMGCanvas'; +import './utils/useSnapshotMatchers'; +import './utils/useCustomFetch'; + +describe('chart.render', () => { + const dir = `${__dirname}/snapshots/api`; + const canvas = createDOMGCanvas(640, 480); + + it('chart.interaction(name, false) should clear interaction.', async () => { + const { finished } = render({ + canvas, + container: document.createElement('div'), + }); + await finished; + + // Trigger tooltip + const plot = canvas.document.getElementsByClassName(PLOT_CLASS_NAME)[0]; + plot.dispatchEvent( + new GCustomEvent('pointermove', { + offsetX: 200, + offsetY: 300, + }), + ); + await expect(canvas).toMatchDOMSnapshot(dir, render.name, { + selector: '.g2-tooltip', + }); + }); + + afterAll(() => { + canvas?.destroy(); + }); +}); diff --git a/__tests__/integration/snapshots/api/chartRenderClearInteraction.html b/__tests__/integration/snapshots/api/chartRenderClearInteraction.html new file mode 100644 index 0000000000..ec747fa47d --- /dev/null +++ b/__tests__/integration/snapshots/api/chartRenderClearInteraction.html @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/__tests__/plots/api/chart-render-clear-interaction.ts b/__tests__/plots/api/chart-render-clear-interaction.ts new file mode 100644 index 0000000000..10552fcafc --- /dev/null +++ b/__tests__/plots/api/chart-render-clear-interaction.ts @@ -0,0 +1,31 @@ +import { Chart } from '../../../src'; + +export function chartRenderClearInteraction(context) { + const { container, canvas } = context; + + const chart = new Chart({ + container, + canvas, + }); + + chart.options({ + theme: 'classic', + type: 'line', + clip: true, + data: { + type: 'fetch', + value: 'data/aapl.csv', + }, + encode: { + x: 'date', + y: 'close', + }, + }); + + const finished = chart.render().then(() => { + chart.options({ interaction: { tooltip: false } }); + return chart.render(); + }); + + return { chart, finished }; +} diff --git a/src/runtime/plot.ts b/src/runtime/plot.ts index bbf145a649..91069cd93c 100644 --- a/src/runtime/plot.ts +++ b/src/runtime/plot.ts @@ -230,10 +230,17 @@ export async function plot( target.container['nameInteraction'] = nameInteraction; // Apply interactions. - for (const option of inferInteraction(options)) { - const interaction = useInteraction(option); - const destroy = interaction(target, enterViewInstances, context.emitter); - nameInteraction.set(option.type, { destroy }); + for (const typeOption of inferInteraction(options)) { + const [type, option] = typeOption; + if (option) { + const interaction = useInteraction({ type, ...(option as any) }); + const destroy = interaction( + target, + enterViewInstances, + context.emitter, + ); + nameInteraction.set(type, { destroy }); + } } } @@ -242,15 +249,23 @@ export async function plot( for (const target of updateViewInstances) { const { options, container } = target; const nameInteraction = container['nameInteraction']; - for (const option of inferInteraction(options)) { + for (const typeOption of inferInteraction(options)) { + const [type, option] = typeOption; + // Remove interaction for existed views. - const prevInteraction = nameInteraction.get(option.type); + const prevInteraction = nameInteraction.get(type); if (prevInteraction) prevInteraction.destroy?.(); // Apply new interaction. - const interaction = useInteraction(option); - const destroy = interaction(target, updateViewInstances, context.emitter); - nameInteraction.set(option.type, { destroy }); + if (option) { + const interaction = useInteraction({ type, ...(option as any) }); + const destroy = interaction( + target, + updateViewInstances, + context.emitter, + ); + nameInteraction.set(type, { destroy }); + } } } @@ -314,7 +329,13 @@ function createUpdateView( }; } -function updateTooltip(selection, options, view, library, context) { +function updateTooltip( + selection: Selection, + options: G2ViewTree, + view: G2ViewDescriptor, + library: G2Library, + context: G2Context, +) { const [useInteraction] = useLibrary< G2InteractionOptions, InteractionComponent, @@ -325,7 +346,7 @@ function updateTooltip(selection, options, view, library, context) { const container = selection.node(); const nameInteraction = container['nameInteraction']; const tooltipOptions = inferInteraction(options).find( - (d) => d.type === 'tooltip', + ([d]) => d === 'tooltip', ); // Destroy older tooltip. @@ -333,8 +354,13 @@ function updateTooltip(selection, options, view, library, context) { if (!tooltip) return; tooltip.destroy?.(); + if (!tooltipOptions[1]) return; + // Apply new tooltip interaction. - const applyTooltip = useInteraction(tooltipOptions); + const applyTooltip = useInteraction({ + type: 'tooltip', + ...(tooltipOptions[1] as any), + }); const target = { options, view, @@ -1351,7 +1377,9 @@ function inferTheme(theme: G2ThemeOptions = {}): G2ThemeOptions { /** * @todo Infer builtin tooltips. */ -function inferInteraction(view: G2View): G2InteractionOptions[] { +function inferInteraction( + view: G2View, +): [string, boolean | Omit][] { const defaults = { event: true, tooltip: true, @@ -1360,12 +1388,7 @@ function inferInteraction(view: G2View): G2InteractionOptions[] { legendFilter: true, }; const { interaction = {} } = view; - return Object.entries(deepMix(defaults, interaction)) - .filter((d) => !!d[1]) - .map(([key, value]) => ({ - type: key, - ...(value as Record), - })); + return Object.entries(deepMix(defaults, interaction)); } async function applyTransform(