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..25592e63b5
--- /dev/null
+++ b/__tests__/integration/api-chart-on-brush-highlight-tooltip.spec.ts
@@ -0,0 +1,38 @@
+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();
+ chart.on('brush:start', resolveStart);
+ brush(plot, 100, 100, 300, 300);
+ await start;
+ await sleep(20);
+
+ const [update, resolveUpdate] = createPromise();
+ chart.on('brush:end', resolveUpdate);
+ dragMask(plot, 30, 30, 60, 60);
+ await update;
+ await sleep(20);
+ });
+
+ afterAll(() => {
+ canvas?.destroy();
+ });
+});
diff --git a/__tests__/integration/api-chart-render-brush-end.spec.ts b/__tests__/integration/api-chart-render-brush-end.spec.ts
index c3f15ad711..9633f3bb77 100644
--- a/__tests__/integration/api-chart-render-brush-end.spec.ts
+++ b/__tests__/integration/api-chart-render-brush-end.spec.ts
@@ -5,7 +5,7 @@ import { sleep } from './utils/sleep';
describe('chart.render', () => {
const canvas = createNodeGCanvas(800, 500);
- it('chart.render() should not emit brush:end', async () => {
+ it('chart.render() should not emit brush:remove', async () => {
const { rerendered, finished, button, chart } = render({
canvas,
container: document.createElement('div'),
@@ -17,7 +17,7 @@ describe('chart.render', () => {
chart.on('brush:highlight', () => {
start();
});
- chart.on('brush:end', () => {
+ chart.on('brush:remove', () => {
end();
});
await finished;
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 @@
+
\ 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 @@
+
\ 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..5c7540989c
--- /dev/null
+++ b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step3.html
@@ -0,0 +1,46 @@
+
\ No newline at end of file
diff --git a/__tests__/integration/snapshots/api/chart-on-focus-context/step2-context.png b/__tests__/integration/snapshots/api/chart-on-focus-context/step2-context.png
index a478bbaf04..e8d81376d1 100644
Binary files a/__tests__/integration/snapshots/api/chart-on-focus-context/step2-context.png and b/__tests__/integration/snapshots/api/chart-on-focus-context/step2-context.png differ
diff --git a/__tests__/integration/snapshots/api/chart-on-focus-context/step2-focus.png b/__tests__/integration/snapshots/api/chart-on-focus-context/step2-focus.png
index 31ae201ad3..4bdda3439b 100644
Binary files a/__tests__/integration/snapshots/api/chart-on-focus-context/step2-focus.png and b/__tests__/integration/snapshots/api/chart-on-focus-context/step2-focus.png differ
diff --git a/__tests__/integration/snapshots/api/chart-on-focus-context/step5-context.png b/__tests__/integration/snapshots/api/chart-on-focus-context/step5-context.png
index c5c8d7833b..01f65947ff 100644
Binary files a/__tests__/integration/snapshots/api/chart-on-focus-context/step5-context.png and b/__tests__/integration/snapshots/api/chart-on-focus-context/step5-context.png differ
diff --git a/__tests__/integration/snapshots/api/chart-on-focus-context/step5-focus.png b/__tests__/integration/snapshots/api/chart-on-focus-context/step5-focus.png
index 758959cab2..0ee0d3676d 100644
Binary files a/__tests__/integration/snapshots/api/chart-on-focus-context/step5-focus.png and b/__tests__/integration/snapshots/api/chart-on-focus-context/step5-focus.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step10.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step10.png
index da027345e8..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step10.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step10.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step11.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step11.png
index c80c1bc0c1..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step11.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step11.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step2.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step2.png
index f4bdbf24bd..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step2.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step2.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step3.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step3.png
index be3dbf7c96..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step3.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step3.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step4.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step4.png
index 2b3a33ea95..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step4.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step4.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step5.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step5.png
index d10878a171..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step5.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step5.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step6.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step6.png
index 9f3129215b..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step6.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step6.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step7.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step7.png
index dea179b212..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step7.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step7.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step8.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step8.png
index 142cf507e6..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step8.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step8.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step9.png b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step9.png
index aa3f8b7f2b..45694f2562 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step9.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush-handle-custom/step9.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step10.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step10.png
index cabc892eb1..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step10.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step10.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step11.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step11.png
index c2abffe0e1..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step11.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step11.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step2.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step2.png
index 9e1cd8b94c..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step2.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step2.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step3.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step3.png
index 6fe2880ad6..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step3.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step3.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step4.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step4.png
index a5c219f055..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step4.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step4.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step5.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step5.png
index 38858125e1..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step5.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step5.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step6.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step6.png
index 3a5c5059c1..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step6.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step6.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step7.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step7.png
index 0c96fa5cab..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step7.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step7.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step8.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step8.png
index 103ade9208..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step8.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step8.png differ
diff --git a/__tests__/integration/snapshots/interaction/penguins-point-brush/step9.png b/__tests__/integration/snapshots/interaction/penguins-point-brush/step9.png
index c2ad2e8868..831f87149b 100644
Binary files a/__tests__/integration/snapshots/interaction/penguins-point-brush/step9.png and b/__tests__/integration/snapshots/interaction/penguins-point-brush/step9.png differ
diff --git a/__tests__/integration/snapshots/tooltip/alphabet-interval-tooltip-render-update/step0.html b/__tests__/integration/snapshots/tooltip/alphabet-interval-tooltip-render-update/step0.html
index e593ff8aca..829ff3ffe4 100644
--- a/__tests__/integration/snapshots/tooltip/alphabet-interval-tooltip-render-update/step0.html
+++ b/__tests__/integration/snapshots/tooltip/alphabet-interval-tooltip-render-update/step0.html
@@ -4,7 +4,7 @@
style="pointer-events: none; position: absolute; visibility: visible; z-index: 8; transition: visibility 0.2s cubic-bezier(0.23, 1, 0.32, 1), left 0.4s cubic-bezier(0.23, 1, 0.32, 1), top 0.4s cubic-bezier(0.23, 1, 0.32, 1); background-color: rgba(255, 255, 255, 0.96); box-shadow: 0 6px 12px 0 rgba(0, 0, 0, 0.12); border-radius: 4px; color: rgba(0, 0, 0, 0.65); font-size: 12px; line-height: 20px; padding: 12px; min-width: 120px; max-width: 360px; font-family: Roboto-Regular; left: 10px; top: 10px;"
>
-
A
- frequency: 0.08167
+ B
+ frequency: 0.01492
\ 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..2d32816ac1
--- /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:
+ ${data.map((d) => `- ${d.date}
`).join('')}
+ `;
+ 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:end', onUpdate);
+ chart.on('brush:remove', onRemove);
+
+ const finished = chart.render();
+
+ function onStart() {
+ chart.emit('tooltip:disable');
+ remove();
+ }
+
+ 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/chart-on-focus-context.ts b/__tests__/plots/api/chart-on-focus-context.ts
index d538a1feb9..e8953f1b9e 100644
--- a/__tests__/plots/api/chart-on-focus-context.ts
+++ b/__tests__/plots/api/chart-on-focus-context.ts
@@ -55,7 +55,7 @@ export function chartOnFocusContext(context) {
const [[x1, x2]] = selection;
const domainX = scaleX.getOptions().domain;
if (x1 === domainX[0] && x2 === domainX[1]) {
- contextView.emit('brush:remove');
+ contextView.emit('brush:remove', {});
} else {
contextView.emit('brush:highlight', { data: { selection } });
}
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/__tests__/plots/tooltip/alphabet-interval-tooltip-render-update.ts b/__tests__/plots/tooltip/alphabet-interval-tooltip-render-update.ts
index ae0f0783f3..f92f3df452 100644
--- a/__tests__/plots/tooltip/alphabet-interval-tooltip-render-update.ts
+++ b/__tests__/plots/tooltip/alphabet-interval-tooltip-render-update.ts
@@ -1,6 +1,8 @@
import { CustomEvent } from '@antv/g';
import { G2Spec, ELEMENT_CLASS_NAME } from '../../../src';
import { LEGEND_ITEMS_CLASS_NAME } from '../../../src/interaction/legendFilter';
+import { sleep } from '../../integration/utils/sleep';
+import { Slice } from '../../../src/data';
export function alphabetIntervalTooltipRenderUpdate(): G2Spec {
return {
@@ -36,6 +38,7 @@ alphabetIntervalTooltipRenderUpdate.steps = ({ canvas }) => {
const [i0] = items;
i0.dispatchEvent(new CustomEvent('click'));
+ await sleep(100);
const elements = document.getElementsByClassName(ELEMENT_CLASS_NAME);
const [e0] = elements;
e0.dispatchEvent(new CustomEvent('pointerover'));
diff --git a/site/docs/spec/interaction/brushHighlight.zh.md b/site/docs/spec/interaction/brushHighlight.zh.md
index 2defa497dc..eeb97923c3 100644
--- a/site/docs/spec/interaction/brushHighlight.zh.md
+++ b/site/docs/spec/interaction/brushHighlight.zh.md
@@ -206,3 +206,30 @@ chart.options({
},
});
```
+
+### 监听事件
+
+支持以下的事件:
+
+- `brush:start` - 开始创建 brush 的时候触发
+- `brush:end` - brush 更新大小和位置完成时候触发
+- `brush:remove` - brush 移除的时候触发
+- `brush:highlight` - 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..ac766992a2
--- /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:end', onUpdate);
+chart.on('brush:remove', onRemove);
+
+chart.render();
+
+function onStart() {
+ chart.emit('tooltip:disable');
+ remove();
+}
+
+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:
+ ${data.map((d) => `- ${d.date}
`).join('')}
+ `;
+ 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..1ca71a9ca9 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:end', {
+ ...event,
+ nativeEvent: true,
+ data: { selection },
+ });
+ },
+ brushupdated: (x, y, x1, y1, event) => {
+ const selection = selectionOf(x, y, x1, y1, scale, coordinate);
+ emitter.emit('brush:end', {
+ ...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..07be1f8223 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,15 @@ 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;
+ if (!parent) return;
+ const { tooltipElement } = parent;
if (tooltipElement) {
+ console.log('destroyTooltip');
tooltipElement.destroy();
- root.tooltipElement = undefined;
+ parent.tooltipElement = undefined;
}
}
@@ -627,7 +631,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 +655,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 +736,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 +755,7 @@ export function tooltip(
}
if (isEmptyTooltipData(data)) {
- hideTooltip({ root, single, emitter, mount });
+ hideTooltip({ root, single, emitter });
return;
}
@@ -762,7 +791,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 +826,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';