fix(filter): optimize the data range expand logic when creating filters (#6264)

This commit is contained in:
wpxp123456
2025-12-08 17:46:50 +08:00
committed by GitHub
parent e67908fc29
commit 8ffeac5419
2 changed files with 161 additions and 11 deletions
@@ -142,9 +142,15 @@ export const SmartToggleSheetsFilterCommand: ICommand = {
if (!lastSelection) return false;
const startRange = lastSelection.range;
const targetFilterRange = isSingleCellSelection(lastSelection)
? expandToContinuousRange(startRange, { left: true, right: true, up: true, down: true }, currentWorksheet)
: startRange;
const targetFilterRange =
// If the selection is a single cell, we should expand it to a continuous range in all directions.
isSingleCellSelection(lastSelection)
? expandToContinuousRange(startRange, { left: true, right: true, up: true, down: true }, currentWorksheet)
// If the selection is only a single row, we should expand it downwards.
: startRange.startRow === startRange.endRow
? expandToContinuousRange(startRange, { down: true }, currentWorksheet)
// Otherwise, we just use the selected range.
: startRange;
return commandService.executeCommand(SetSheetFilterRangeCommand.id, {
unitId,
+152 -8
View File
@@ -193,12 +193,22 @@ function getExpandedRangeLeft(range: IRange, allMatrixWithSpan: ObjectMatrix<IMa
range,
};
}
if (spanAnchor) {
return {
spanAnchor: Rectangle.simpleRangesIntersect(range, spanAnchor) ? spanAnchor : null,
hasValue: false,
range,
};
}
return {
spanAnchor: null,
hasValue: false,
range,
};
}
function getExpandedRangeRight(range: IRange, allMatrixWithSpan: ObjectMatrix<IMatrixWithSpanInfo>, rightOffset: number, isWorksheetHasSpan: boolean): IExpandedRangeResult {
const { startRow, endColumn, endRow } = range;
let spanAnchor: IRange | null = null;
@@ -238,6 +248,14 @@ function getExpandedRangeRight(range: IRange, allMatrixWithSpan: ObjectMatrix<IM
};
}
if (spanAnchor) {
return {
spanAnchor: Rectangle.simpleRangesIntersect(range, spanAnchor) ? spanAnchor : null,
hasValue: false,
range,
};
}
return {
spanAnchor: null,
hasValue: false,
@@ -282,6 +300,15 @@ function getExpandedRangeUp(range: IRange, allMatrixWithSpan: ObjectMatrix<IMatr
range,
};
}
if (spanAnchor) {
return {
spanAnchor: Rectangle.simpleRangesIntersect(range, spanAnchor) ? spanAnchor : null,
hasValue: false,
range,
};
}
return {
spanAnchor: null,
hasValue: false,
@@ -326,22 +353,128 @@ function getExpandedRangeDown(range: IRange, allMatrixWithSpan: ObjectMatrix<IMa
range,
};
}
if (spanAnchor) {
return {
spanAnchor: Rectangle.simpleRangesIntersect(range, spanAnchor) ? spanAnchor : null,
hasValue: false,
range,
};
}
return {
spanAnchor: null,
hasValue: false,
range,
};
}
// the demo unit=YSvbxFMCTxugbku-IWNyxQ&type=2&subunit=U_wr1DEF84N_mbesFNmxR in pro
// The excel behavior rules:
// 1. If the range has a span, the range should expand to whole span range.
// 2. If range left, right, up, down has value, the range should expand to the cell which has value.
// 3. If the range has no value, the range should not expand.
// 4. If the merge has span, the every cell value in span should be the anchor of the span range.
// 5. The span range should be not part in the result range.
/**
* Expand the range to a continuous range, it uses when Ctrl + A , or only one cell selected to add a pivot table adn so on.
* A fast path to expand range by checking the four corner cells.
*/
// eslint-disable-next-line max-lines-per-function,complexity
function getExpandedRangeByFastPath({
range,
allMatrixWithSpan,
directions,
isWorksheetHasSpan,
maxRow,
maxColumn,
}: {
range: IRange;
allMatrixWithSpan: ObjectMatrix<IMatrixWithSpanInfo>;
directions: IExpandParams;
isWorksheetHasSpan: boolean;
maxRow: number;
maxColumn: number;
}): {
hasValue: boolean;
range: IRange;
} {
const { left, right, up, down } = directions;
const { startRow, startColumn, endRow, endColumn } = range;
let hasValue = false;
// top-left
if (left && up && startRow > 0 && startColumn > 0) {
const cell = allMatrixWithSpan.getValue(startRow - 1, startColumn - 1)!;
if (hasValueFromMatrixWithSpanInfo(cell, allMatrixWithSpan)) {
if (isWorksheetHasSpan && cell.spanAnchor) {
range.startRow = cell.spanAnchor.startRow;
range.startColumn = cell.spanAnchor.startColumn;
} else {
range.startRow = startRow - 1;
range.startColumn = startColumn - 1;
}
hasValue = true;
}
}
// top-right
if (right && up && startRow > 0 && endColumn < maxColumn - 1) {
const cell = allMatrixWithSpan.getValue(startRow - 1, endColumn + 1)!;
if (hasValueFromMatrixWithSpanInfo(cell, allMatrixWithSpan)) {
if (isWorksheetHasSpan && cell.spanAnchor) {
range.startRow = cell.spanAnchor.startRow;
range.endColumn = cell.spanAnchor.endColumn;
} else {
range.startRow = startRow - 1;
range.endColumn = endColumn + 1;
}
hasValue = true;
}
}
// bottom-left
if (left && down && endRow < maxRow - 1 && startColumn > 0) {
const cell = allMatrixWithSpan.getValue(endRow + 1, startColumn - 1)!;
if (hasValueFromMatrixWithSpanInfo(cell, allMatrixWithSpan)) {
if (isWorksheetHasSpan && cell.spanAnchor) {
range.endRow = cell.spanAnchor.endRow;
range.startColumn = cell.spanAnchor.startColumn;
} else {
range.endRow = endRow + 1;
range.startColumn = startColumn - 1;
}
hasValue = true;
}
}
// bottom-right
if (right && down && endRow < maxRow - 1 && endColumn < maxColumn - 1) {
const cell = allMatrixWithSpan.getValue(endRow + 1, endColumn + 1)!;
if (hasValueFromMatrixWithSpanInfo(cell, allMatrixWithSpan)) {
if (isWorksheetHasSpan && cell.spanAnchor) {
range.endRow = cell.spanAnchor.endRow;
range.endColumn = cell.spanAnchor.endColumn;
} else {
range.endRow = endRow + 1;
range.endColumn = endColumn + 1;
}
hasValue = true;
}
}
return {
hasValue,
range,
};
}
/**
* Expand the range to a continuous range, it uses when Ctrl + A , or only one cell selected to add a pivot table adn so on.
* The demo unit=YSvbxFMCTxugbku-IWNyxQ&type=2&subunit=U_wr1DEF84N_mbesFNmxR in pro.
* The excel behavior rules:
* 1. If the range has a span, the range should expand to whole span range.
* 2. If range left, right, up, down has value, the range should expand to the cell which has value.
* 3. If the range has no value, the range should not expand.
* 4. If the merge has span, the every cell value in span should be the anchor of the span range.
* 5. The span range should be not part in the result range.
* @param {IRange} startRange The start range.
* @param {IExpandParams} directions The directions to expand.
* @param {Worksheet} worksheet The worksheet working on.
@@ -360,6 +493,16 @@ export function expandToContinuousRange(startRange: IRange, directions: IExpandP
while (changed) {
changed = false;
// try fast path first
const fastPathResult = getExpandedRangeByFastPath({ range: destRange, allMatrixWithSpan, directions, isWorksheetHasSpan: worksheetHasSpan, maxRow, maxColumn });
if (fastPathResult.hasValue) {
destRange = fastPathResult.range;
changed = true;
continue;
}
// then try normal path
if (up && destRange.startRow !== 0) {
const { hasValue, range, spanAnchor } = getExpandedRangeUp(destRange, allMatrixWithSpan, 1, worksheetHasSpan);
if (spanAnchor) {
@@ -406,6 +549,7 @@ export function expandToContinuousRange(startRange: IRange, directions: IExpandP
}
}
}
if (spanAnchors.length > 0) {
destRange = Rectangle.union(destRange, ...spanAnchors);
}