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 @@ +
+
+ 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..5c7540989c --- /dev/null +++ b/__tests__/integration/snapshots/api/chart-emit-enable-disable-tooltip/step3.html @@ -0,0 +1,46 @@ +
+
+ 2007-04-23 +
+ +
\ 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: + + `; + 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: + + `; + 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';