diff --git a/packages/s2-core/__tests__/bugs/issue-2340-spec.ts b/packages/s2-core/__tests__/bugs/issue-2340-spec.ts new file mode 100644 index 0000000000..1f6bc1e71e --- /dev/null +++ b/packages/s2-core/__tests__/bugs/issue-2340-spec.ts @@ -0,0 +1,78 @@ +/** + * @description spec for issue #2340 + * https://github.com/antvis/S2/issues/2340 + */ +import { map } from 'lodash'; +import { + CellTypes, + InteractionStateName, + getCellMeta, + type S2Options, + HeaderCell, +} from '../../src'; +import { createPivotSheet, sleep } from '../util/helpers'; + +const s2Options: S2Options = { + width: 800, + height: 600, + style: { + cellCfg: { + width: 200, + height: 200, + }, + }, +}; + +describe('Header Brush Selection Tests', () => { + test.each([CellTypes.COL_CELL, CellTypes.ROW_CELL])( + 'should not trigger data cell selected when header selected and scroll out of viewport', + async (cellType) => { + const s2 = createPivotSheet(s2Options, { useSimpleData: false }); + s2.render(); + + const isRow = cellType === CellTypes.ROW_CELL; + const targetCells = isRow + ? s2.interaction.getAllRowHeaderCells() + : s2.interaction.getAllColHeaderCells(); + + const cells = [ + (targetCells as HeaderCell[]).find((cell) => { + const meta = cell.getMeta(); + return meta.isLeaf; + }), + ]; + + s2.interaction.changeState({ + cells: map(cells, getCellMeta), + stateName: InteractionStateName.BRUSH_SELECTED, + }); + + await sleep(500); + + const offsetKey = isRow ? 'offsetY' : 'offsetX'; + // 将圈选的单元格滑出可视范围 + s2.facet.updateScrollOffset({ + [offsetKey]: { value: 300 }, + }); + + await sleep(500); + + // 还原 + s2.facet.updateScrollOffset({ + [offsetKey]: { value: 0 }, + }); + + expect(s2.interaction.getActiveCells()).toHaveLength(1); + expect(s2.interaction.getCurrentStateName()).toEqual( + InteractionStateName.BRUSH_SELECTED, + ); + + // 交互过的不应该有 dataCell (未触发过列头多选) + s2.interaction.getInteractedCells().forEach((cell) => { + expect(cell.cellType).toEqual( + isRow ? CellTypes.ROW_CELL : CellTypes.COL_CELL, + ); + }); + }, + ); +}); diff --git a/packages/s2-core/src/cell/data-cell.ts b/packages/s2-core/src/cell/data-cell.ts index 0703ee72c6..189785e151 100644 --- a/packages/s2-core/src/cell/data-cell.ts +++ b/packages/s2-core/src/cell/data-cell.ts @@ -393,7 +393,7 @@ export class DataCell extends BaseCell { ); } - // dataCell根据state 改变当前样式, + // dataCell 根据 state 改变当前样式, protected changeRowColSelectState(indexType: ViewMetaIndexType) { const { interaction } = this.spreadsheet; const currentIndex = get(this.meta, indexType); diff --git a/packages/s2-core/src/cell/header-cell.ts b/packages/s2-core/src/cell/header-cell.ts index 0bfebe0b5f..a2dfd1eb3f 100644 --- a/packages/s2-core/src/cell/header-cell.ts +++ b/packages/s2-core/src/cell/header-cell.ts @@ -415,6 +415,7 @@ export abstract class HeaderCell extends BaseCell { switch (stateInfo?.stateName) { case InteractionStateName.SELECTED: + case InteractionStateName.BRUSH_SELECTED: this.handleSelect(cells, stateInfo?.nodes); break; case InteractionStateName.HOVER_FOCUS: diff --git a/packages/s2-core/src/common/constant/interaction.ts b/packages/s2-core/src/common/constant/interaction.ts index 75a9650318..b63e1c6f11 100644 --- a/packages/s2-core/src/common/constant/interaction.ts +++ b/packages/s2-core/src/common/constant/interaction.ts @@ -18,6 +18,7 @@ export enum InteractionName { export enum InteractionStateName { ALL_SELECTED = 'allSelected', SELECTED = 'selected', + BRUSH_SELECTED = 'brushSelected', UNSELECTED = 'unselected', HOVER = 'hover', HOVER_FOCUS = 'hoverFocus', diff --git a/packages/s2-core/src/facet/header/col.ts b/packages/s2-core/src/facet/header/col.ts index 7bd98f46ba..60c2df7002 100644 --- a/packages/s2-core/src/facet/header/col.ts +++ b/packages/s2-core/src/facet/header/col.ts @@ -77,14 +77,14 @@ export class ColHeader extends BaseHeader { return this.scrollGroup; } - protected isColCellInRect(item: Node): boolean { + protected isColCellInRect(node: Node): boolean { const { spreadsheet, cornerWidth, width, scrollX } = this.headerConfig; return ( // don't care about scrollY, because there is only freeze col-header exist - width + scrollX > item.x && + width + scrollX > node.x && scrollX - (spreadsheet.isFrozenRowHeader() ? 0 : cornerWidth) < - item.x + item.width + node.x + node.width ); } diff --git a/packages/s2-core/src/interaction/brush-selection/col-brush-selection.ts b/packages/s2-core/src/interaction/brush-selection/col-brush-selection.ts index 38881a5676..5903b4024c 100644 --- a/packages/s2-core/src/interaction/brush-selection/col-brush-selection.ts +++ b/packages/s2-core/src/interaction/brush-selection/col-brush-selection.ts @@ -96,16 +96,14 @@ export class ColBrushSelection extends BaseBrushSelection { ); } - // 最终刷选的cell + // 最终刷选的 cell protected updateSelectedCells() { const { interaction } = this.spreadsheet; interaction.changeState({ cells: map(this.brushRangeCells, getCellMeta), stateName: InteractionStateName.SELECTED, - onUpdateCells: (root) => { - root.updateCells(root.getAllColHeaderCells()); - }, + onUpdateCells: this.onUpdateCells, }); this.spreadsheet.emit( diff --git a/packages/s2-core/src/interaction/brush-selection/data-cell-brush-selection.ts b/packages/s2-core/src/interaction/brush-selection/data-cell-brush-selection.ts index ea3faf6704..dabfa25ae2 100644 --- a/packages/s2-core/src/interaction/brush-selection/data-cell-brush-selection.ts +++ b/packages/s2-core/src/interaction/brush-selection/data-cell-brush-selection.ts @@ -94,13 +94,14 @@ export class DataCellBrushSelection extends BaseBrushSelection { return metas; }; - // 最终刷选的cell + // 最终刷选的 cell protected updateSelectedCells() { const brushRange = this.getBrushRange(); const selectedCellMetas = this.getSelectedCellMetas(brushRange); this.spreadsheet.interaction.changeState({ cells: selectedCellMetas, + // TODO: 怕上层有直接消费 stateName, 暂时保留, 2.0 版本改成 InteractionStateName.BRUSH_SELECTED stateName: InteractionStateName.SELECTED, onUpdateCells: afterSelectDataCells, }); diff --git a/packages/s2-core/src/interaction/brush-selection/row-brush-selection.ts b/packages/s2-core/src/interaction/brush-selection/row-brush-selection.ts index 95225bcc90..57e842c95d 100644 --- a/packages/s2-core/src/interaction/brush-selection/row-brush-selection.ts +++ b/packages/s2-core/src/interaction/brush-selection/row-brush-selection.ts @@ -96,7 +96,7 @@ export class RowBrushSelection extends BaseBrushSelection { this.spreadsheet.interaction.changeState({ cells: selectedCellMetas, - stateName: InteractionStateName.SELECTED, + stateName: InteractionStateName.BRUSH_SELECTED, onUpdateCells: this.onUpdateCells, }); diff --git a/packages/s2-core/src/interaction/root.ts b/packages/s2-core/src/interaction/root.ts index 2e87577dab..03c4c66c56 100644 --- a/packages/s2-core/src/interaction/root.ts +++ b/packages/s2-core/src/interaction/root.ts @@ -144,7 +144,10 @@ export class RootInteraction { } public isSelectedState() { - return this.isStateOf(InteractionStateName.SELECTED); + return ( + this.isStateOf(InteractionStateName.SELECTED) || + this.isStateOf(InteractionStateName.BRUSH_SELECTED) + ); } public isAllSelectedState() {