Skip to content

Commit

Permalink
fix: 修复父容器存在 transform 缩放时单元格刷选偏移 close #2553
Browse files Browse the repository at this point in the history
  • Loading branch information
lijinke666 committed Feb 27, 2024
1 parent 48b7073 commit 232b7d0
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1004,20 +1004,51 @@ describe('Interaction Event Controller Tests', () => {
spreadsheet.on(S2Event.GLOBAL_RESET, reset);

const pointInCanvas = getClientPointOnCanvas(spreadsheet.container, 10, 10);
const evt = new window.CustomEvent('click');
const event = new window.CustomEvent('click');

Object.defineProperties(evt, {
Object.defineProperties(event, {
clientX: {
value: pointInCanvas.clientX,
},
clientY: {
value: pointInCanvas.clientY,
},
});
spreadsheet.getCanvasElement().dispatchEvent(evt);
spreadsheet.getCanvasElement().dispatchEvent(event);

expect(eventController.isCanvasEffect).toBe(true);
expect(reset).not.toHaveBeenCalled();
expect(spreadsheet.interaction.reset).not.toHaveBeenCalled();
});

// https://github.com/antvis/S2/issues/2553
test('should use offset point if enable supportsCSSTransform', () => {
jest.spyOn(spreadsheet, 'getCanvasConfig').mockImplementationOnce(() => {
return {
supportsCSSTransform: true,
};
});

const event = new MouseEvent('click');

Object.defineProperties(event, {
offsetX: {
value: 100,
},
offsetY: {
value: 200,
},
clientX: {
value: 300,
},
clientY: {
value: 400,
},
});

expect(eventController.getViewportPoint(event)).toStrictEqual({
x: 100,
y: 200,
});
});
});
1 change: 1 addition & 0 deletions packages/s2-core/__tests__/util/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ export const createFakeSpreadSheet = (config?: {
s2.facet.getCells = jest.fn().mockReturnValue([]);
s2.getCanvasElement = () =>
s2.container.getContextService().getDomElement() as HTMLCanvasElement;
s2.getCanvasConfig = () => s2.container.getConfig();
s2.isCustomHeaderFields = jest.fn(() => false);
s2.isCustomRowFields = jest.fn(() => false);
s2.isCustomColumnFields = jest.fn(() => false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,8 @@ export class ColCellBrushSelection extends BaseBrushSelection {

this.setBrushSelectionStage(InteractionBrushSelectionStage.DRAGGED);

const pointInCanvas = this.spreadsheet.container.client2Viewport({
x: event.clientX,
y: event.clientY,
});
const pointInCanvas =
this.spreadsheet.interaction.eventController.getViewportPoint(event);

if (!this.isPointInCanvas(pointInCanvas)) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,8 @@ export class DataCellBrushSelection extends BaseBrushSelection {
}

this.setBrushSelectionStage(InteractionBrushSelectionStage.DRAGGED);
const pointInCanvas = this.spreadsheet.container.client2Viewport({
x: event.clientX,
y: event.clientY,
});
const pointInCanvas =
this.spreadsheet.interaction.eventController.getViewportPoint(event);

if (this.autoBrushScroll(pointInCanvas)) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,8 @@ export class RowCellBrushSelection extends BaseBrushSelection {

this.setBrushSelectionStage(InteractionBrushSelectionStage.DRAGGED);

const pointInCanvas = this.spreadsheet.container.client2Viewport({
x: event.clientX,
y: event.clientY,
});
const pointInCanvas =
this.spreadsheet.interaction.eventController.getViewportPoint(event);

if (this.autoBrushScroll(pointInCanvas, true)) {
return;
Expand Down
24 changes: 24 additions & 0 deletions packages/s2-core/src/interaction/event-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
DisplayObject,
type FederatedPointerEvent as CanvasEvent,
type Group,
type PointLike,
} from '@antv/g';
import { each, get, hasIn, isEmpty, isNil } from 'lodash';
import { GuiIcon } from '../common';
Expand Down Expand Up @@ -701,4 +702,27 @@ export class EventController {
this.s2EventHandlers = [];
this.domEventListeners = [];
}

public getViewportPoint(
event: MouseEvent | PointerEvent | CanvasEvent,
): PointLike {
const config = this.spreadsheet.getCanvasConfig();

// https://github.com/antvis/G/blob/a43c19a662684945d0bf9dc1876af43ac26b1243/packages/g-lite/src/plugins/EventPlugin.ts#L216
if (
config.supportsCSSTransform &&
!isNil(event.offsetX) &&
!isNil(event.offsetY)
) {
return {
x: event.offsetX,
y: event.offsetY,
};
}

return this.spreadsheet.container.client2Viewport({
x: event.clientX,
y: event.clientY,
});
}
}
9 changes: 9 additions & 0 deletions packages/s2-core/src/sheet-type/spread-sheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -599,11 +599,20 @@ export abstract class SpreadSheet extends EE {

/**
* 获取 G Canvas 实例
* @see https://g.antv.antgroup.com/api/renderer/canvas
*/
public getCanvas(): Canvas {
return this.container;
}

/**
* 获取 G Canvas 配置
* @see https://g.antv.antgroup.com/api/canvas/options
*/
public getCanvasConfig(): Partial<CanvasConfig> {
return this.getCanvas().getConfig();
}

/**
* 获取 <canvas/> HTML 元素
*/
Expand Down
5 changes: 5 additions & 0 deletions packages/s2-react/playground/components/CustomTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export const CustomTreeOptions: SheetComponentOptions = {
width: 600,
height: 480,
hierarchyType: 'tree',
transformCanvasConfig() {
return {
supportsCSSTransform: true,
};
},
showDefaultHeaderActionIcon: false,
interaction: {
copy: {
Expand Down
92 changes: 90 additions & 2 deletions s2-site/docs/api/basic-class/interaction.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ s2.interaction.reset()
| --- |--------------------------------------------------| --- |
| spreadsheet | 表格实例 | [SpreadSheet](/docs/api/basic-class/spreadsheet) |
| interactions | 当前已注册的交互 | `Map<string, BaseEvent>` |
| intercept | 当前拦截的交互,防止不同交互之间冲突 | `Set<Intercept>` |
| intercepts | 当前拦截的交互,防止不同交互之间冲突 ([查看示例](/examples/interaction/advanced/#intercepts)) | `Set<Intercept>` |
| eventController | 事件控制器 | [EventController](#eventcontroller) |
| destroy | 卸载所有交互实例,并重置为初始状态 | `() => void` |
| reset | 重置所有交互 | `() => void` |
| setState | 设置状态 | (data: [InteractionStateInfo](#interactionstateinfo)) => void |
Expand All @@ -25,7 +26,7 @@ s2.interaction.reset()
| setInteractedCells | 设置当前发生改变的单元格 | (cell: [S2CellType](#s2celltype)) => void |
| getInteractedCells | 获取当前发生改变的单元格 | () => [S2CellType](#s2celltype)[] |
| getCurrentStateName | 获取当前状态名 | `() => void` |
| isEqualStateName | 是否是相同的状态名 | `(name: InteractionStateName) => void` |
| isEqualStateName | 是否是相同的状态名 | (name: [InteractionStateName](#interactionstatename)) => void |
| isSelectedState | 是否是选中状态 | `() => void` |
| isHoverState | 是否是悬停状态 | `() => void` |
| isHoverFocusState | 是否是悬停聚焦状态 (悬停在单元格 `focusTime`: 默认 800ms 后) | `() => void` |
Expand Down Expand Up @@ -121,6 +122,48 @@ interface MergedCellInfo {
}
```

### CellType

```ts
enum CellType {
DATA_CELL = 'dataCell',
ROW_CELL = 'rowCell',
COL_CELL = 'colCell',
SERIES_NUMBER_CELL = 'seriesNumberCell',
CORNER_CELL = 'cornerCell',
MERGED_CELL = 'mergedCell',
}
```

### CellMeta

```ts
interface CellMeta {
id: string;
colIndex: number;
rowIndex: number;
type: CellType;
rowQuery?: Record<string, any>;
[key: string]: unknown;
}
```

### InteractionStateName

```ts
enum InteractionStateName {
ALL_SELECTED = 'allSelected',
SELECTED = 'selected',
BRUSH_SELECTED = 'brushSelected',
UNSELECTED = 'unselected',
HOVER = 'hover',
HOVER_FOCUS = 'hoverFocus',
HIGHLIGHT = 'highlight',
SEARCH_RESULT = 'searchResult',
PREPARE_SELECT = 'prepareSelect',
}
```

### InteractionStateInfo

```ts
Expand All @@ -133,4 +176,49 @@ interface InteractionStateInfo {
}
```

### EventController

| 参数 | 说明 | 类型 |
| --- |--------| --- |
| spreadsheet | 表格实例 | [SpreadSheet](/docs/api/basic-class/spreadsheet) |
| canvasEventHandlers | 当前已注册的交互 | [EventHandler](#eventhandler)[] |
| s2EventHandlers | 当前已注册的交互 | [S2EventHandler](#s2eventhandler)[] |
| domEventListeners | 当前已注册的交互 | [EventHandler](#eventhandler)[] |
| isCanvasEffect | 是否是图表内部引起的事件 | boolean |
| canvasMousemoveEvent | 表格鼠标移动事件 | CanvasEvent |
| isMatchElement | 是否是表格内部的元素 | (event: MouseEvent) => void |
| isMatchPoint | 是否是表格内部的坐标 | (event: MouseEvent) => void |
| bindEvents | 绑定交互事件 | `() => void`) |
| clear | 清空交互事件 | `() => void`) |
| getViewportPoint | 获取表格内的鼠标坐标 (兼容 `supportsCSSTransform`) | `(event: MouseEvent \| PointerEvent \| WheelEvent) => PointLike` |

### EventListener

```ts
interface EventListener {
target: EventTarget;
type: string;
handler: EventListenerOrEventListenerObject;
options?: AddEventListenerOptions | boolean;
}
```

### S2EventHandler

```ts
interface S2EventHandler {
type: keyof EmitterType;
handler: EmitterType[keyof EmitterType];
}
```

### EventHandler

```ts
interface EventHandler {
type: string;
handler: (event: CanvasEvent) => void;
}
```

<embed src="@/docs/common/view-meta.zh.md"></embed>
1 change: 1 addition & 0 deletions s2-site/docs/api/basic-class/spreadsheet.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ s2.isPivotMode()
| getInitColLeafNodes | 获取初次渲染的列头叶子节点 (比如:隐藏列头前) | () => [Node[]](/docs/api/basic-class/node/) | |
| getCanvasElement | 获取表格对应的 `<canvas/>` HTML 元素 | () => [HTMLCanvasElement](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement) | |
| getCanvas | 获取 G Canvas 实例 | () => [Canvas](https://g.antv.antgroup.com/api/renderer/canvas) | |
| getCanvasConfig | 获取 G Canvas 配置 | () => Partial<[CanvasConfig](https://g.antv.antgroup.com/api/canvas/options)> | |
| clearInitColLeafNodes | 清空存储在 store 中的初始叶子节点 | () => void | |
| updateSortMethodMap | 更新存储在 store 中的节点排序方式 map, replace 为是否覆盖上一次的值 | (nodeId: string, sortMethod: string, replace?: boolean) => void | |
| getMenuDefaultSelectedKeys | 获取 tooltip 中选中的菜单项 key 值 | `(nodeId: string) => string[]` | |
Expand Down

0 comments on commit 232b7d0

Please sign in to comment.