diff --git a/common/changes/@visactor/vtable/fix-animation_position_2026-03-18-07-54.json b/common/changes/@visactor/vtable/fix-animation_position_2026-03-18-07-54.json new file mode 100644 index 000000000..02510b6e4 --- /dev/null +++ b/common/changes/@visactor/vtable/fix-animation_position_2026-03-18-07-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vtable", + "comment": "fix(scrolling): ensure target row/col is reached after animation", + "type": "none" + } + ], + "packageName": "@visactor/vtable" +} \ No newline at end of file diff --git a/packages/vtable/src/core/BaseTable.ts b/packages/vtable/src/core/BaseTable.ts index ab99553bb..167cbeb53 100644 --- a/packages/vtable/src/core/BaseTable.ts +++ b/packages/vtable/src/core/BaseTable.ts @@ -5126,10 +5126,10 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { getTargetScrollTop(row: number) { const drawRange = this.getDrawRange(); const frozenHeight = this.getFrozenRowsHeight(); - return Math.max( - 0, - Math.min(this.getRowsHeight(0, row - 1) - frozenHeight, this.getAllRowsHeight() - drawRange.height) - ); + // const rowsHeight = this.getRowsHeight(0, row - 1); + const rowsHeight = Math.ceil(this.rowHeightsMap.getSumInRange(0, row - 1)); // same as this.scrollTop + const allRowsHeight = this.getAllRowsHeight(); + return Math.max(0, Math.min(rowsHeight - frozenHeight, allRowsHeight - drawRange.height)); } private _scheduleScrollToRowCorrect(row: number, delay: number = 0) { @@ -5192,7 +5192,10 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { // This ensures dynamically-computed row heights (e.g. autoWrapText) are reflected // in the scroll position calculation. const top = this.rowHeightsMap.getSumInRange(0, cellAddr.row - 1); - this.scrollTop = Math.min(top - frozenHeight, this.rowHeightsMap.getSumInRange(0, this.rowCount - 1) - drawRange.height); + this.scrollTop = Math.min( + top - frozenHeight, + this.rowHeightsMap.getSumInRange(0, this.rowCount - 1) - drawRange.height + ); } this.render(); } diff --git a/packages/vtable/src/core/animation.ts b/packages/vtable/src/core/animation.ts index 32fd437f3..ded1384fa 100644 --- a/packages/vtable/src/core/animation.ts +++ b/packages/vtable/src/core/animation.ts @@ -12,10 +12,18 @@ class Animateaaa extends ACustomAnimate { if (this.from.x !== this.to.x) { const x = end ? this.to.x : this.from.x + Math.floor((this.to.x - this.from.x) * ratio); this.params.table.scrollLeft = x; + if (ratio === 1 && this.to.targetCol !== -1) { + // ensure scrollToCol is called at the end of animation to avoid not reaching the target col + this.params.table.scrollToCol(this.to.targetCol, false); + } } if (this.from.y !== this.to.y) { const y = end ? this.to.y : this.from.y + Math.floor((this.to.y - this.from.y) * ratio); this.params.table.scrollTop = y; + if (ratio === 1 && this.to.targetRow !== -1) { + // ensure scrollToRow is called at the end of animation to avoid not reaching the target row + this.params.table.scrollToRow(this.to.targetRow, false); + } } } } @@ -70,7 +78,9 @@ export class TableAnimationManager { const to = { x: isNumber(col) ? left - this.table.getFrozenColsWidth() : this.table.scrollLeft, - y: isNumber(row) ? top - this.table.getFrozenRowsHeight() : this.table.scrollTop + y: isNumber(row) ? top - this.table.getFrozenRowsHeight() : this.table.scrollTop, + targetRow: rowInt ?? -1, + targetCol: colInt ?? -1 }; const duration = !isBoolean(animationOption) ? animationOption?.duration ?? 3000 : animationOption ? 3000 : 0; const easing = !isBoolean(animationOption) ? animationOption?.easing ?? 'linear' : animationOption ? 'linear' : '';