Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: float dom after freeze #4587

Merged
merged 8 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,4 @@ export { isNodeEnv } from './shared/tools';
export { Skeleton } from './skeleton.ts';
export type { IGetRowColByPosOptions } from './sheets/sheet-skeleton';
export type { IPosition } from './sheets/typedef.ts';
export * from './sheets/sheet-skeleton';
7 changes: 4 additions & 3 deletions packages/core/src/sheets/typedef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@

import type { IResources } from '../services/resource-manager/type';
import type { IObjectArrayPrimitiveType, IObjectMatrixPrimitiveType, Nullable } from '../shared';
import type { BooleanNumber } from '../types/enum';
import type { LocaleType } from '../types/enum/locale-type';
import type { IDocumentData } from '../types/interfaces';
import type { ICellCustomRender } from '../types/interfaces/i-cell-custom-render';
import type { IStyleData } from '../types/interfaces/i-style-data';
import { type BooleanNumber, CellValueType } from '../types/enum';
import { CellValueType } from '../types/enum';

/**
* Snapshot of a workbook.
Expand Down Expand Up @@ -378,12 +379,12 @@ export interface IFreeze {
*/
ySplit: number;
/**
* scrollable start row
* scrollable start row(viewMain start row)
*/
startRow: number;

/**
* scrollable start column
* scrollable start column(viewMain start column)
*/
startColumn: number;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import type {
} from '@univerjs/core';
import type { IDocumentSkeletonColumn } from '../../basics/i-document-skeleton-cached';
import type { ITransformChangeState } from '../../basics/interfaces';
import type { IBoundRectNoAngle, IViewportInfo } from '../../basics/vector2';
import type { IBoundRectNoAngle, IPoint, IViewportInfo } from '../../basics/vector2';
import type { Scene } from '../../scene';
import type { BorderCache, IFontCacheItem, IStylesCache } from './interfaces';
import {
Expand Down Expand Up @@ -1437,6 +1437,27 @@ export class SpreadsheetSkeleton extends SheetSkeleton {
};
}

getDistanceFromTopLeft(row: number, col: number): IPoint {
return {
x: this.colStartX(col),
y: this.rowStartY(row),
};
}

colStartX(col: number): number {
const arr = this.columnWidthAccumulation;
const i = col - 1;
if (i === -1) return 0;
return arr[i];
}

rowStartY(row: number): number {
const arr = this.rowHeightAccumulation;
const i = row - 1;
if (i === -1) return 0;
return arr[i];
}

getHiddenRowsInRange(range: IRowRange) {
const hiddenRows = [];
for (let i = range.startRow; i <= range.endRow; i++) {
Expand Down
11 changes: 4 additions & 7 deletions packages/engine-render/src/viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export class Viewport {
/**
* bound of visible area
*/
private _viewBound: IBoundRectNoAngle;
private _viewBound: IBoundRectNoAngle = { top: 0, left: 0, bottom: 0, right: 0 };
private _preViewBound: IBoundRectNoAngle;

/**
Expand Down Expand Up @@ -354,8 +354,6 @@ export class Viewport {

set viewportScrollY(val: number) {
this._viewportScrollY = val;
// const { y } = this.transViewportScroll2ScrollValue(this._viewportScrollX, this._viewportScrollY);
// this.scrollY = y;
}

get viewportScrollY() {
Expand All @@ -364,14 +362,10 @@ export class Viewport {

set scrollX(val: number) {
this._scrollX = val;
// const { x } = this.transScroll2ViewportScrollValue(this._scrollX, this._scrollY);
// this._viewportScrollX = x;
}

set scrollY(val: number) {
this._scrollY = val;
// const { y } = this.transScroll2ViewportScrollValue(this._scrollX, this._scrollY);
// this._viewportScrollY = y;
}

get scrollX() {
Expand Down Expand Up @@ -449,6 +443,9 @@ export class Viewport {
this._active = false;
}

/**
* canvas resize & freeze change would invoke this method
*/
resetCanvasSizeAndUpdateScroll() {
this._resizeCacheCanvas();
this._updateScrollByViewportScrollValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ export interface IDOMAnchor {
}

export interface ILimitBound extends IBoundRectNoAngle {
/**
* Actually, it means fixed.
* When left is true, dom is fixed to left of dom pos when dom width is shrinking. or dom is fixed to right of dom pos when dom width is shrinking.
* When top is true, dom is fixed to top of dom pos when dom height is shrinking. or dom is fixed to bottom of dom pos when dom height is shrinking.
*/
absolute: {
left: boolean;
top: boolean;
Expand All @@ -102,17 +107,24 @@ export interface ILimitBound extends IBoundRectNoAngle {

/**
* Adjust dom bound size when scrolling (dom bound would shrink when scrolling if over the edge of viewMain)
* @param posOfFloatObject
* @param posOfFloatObject The position of float object, relative to sheet content, scale & scrolling does not affect it.
* @param scene
* @param skeleton
* @param worksheet
* @returns ILimitBound
*/
// eslint-disable-next-line max-lines-per-function
export function transformBound2DOMBound(posOfFloatObject: IBoundRectNoAngle, scene: Scene, skeleton: SpreadsheetSkeleton, worksheet: Worksheet, floatDomInfo?: ICanvasFloatDomInfo): ILimitBound {
const { scaleX, scaleY } = scene.getAncestorScale();
const viewMain = scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN);

const freeze = worksheet.getFreeze();
const { startColumn: viewMainStartColumn, startRow: viewMainStartRow, xSplit: freezedCol, ySplit: freezedRow } = freeze;
/**
* Actually, it means fixed.
*/
const absolute = {
left: true,
left: true, // left means the left of pic is in a viewMainLeft
top: true,
};

Expand All @@ -123,16 +135,20 @@ export function transformBound2DOMBound(posOfFloatObject: IBoundRectNoAngle, sce
};
}
const { left, right, top, bottom } = posOfFloatObject;
let { top: topBoundOfViewArea, left: leftBoundViewArea, viewportScrollX, viewportScrollY } = viewMain;

let { top: viewBoundsTop, left: viewBoundsLeft, viewportScrollX, viewportScrollY } = viewMain;
// specify edge of viewbound. if not specify, use viewMain.
const { boundsOfViewArea, scrollDirectionResponse } = floatDomInfo || {};
if (boundsOfViewArea) {
const { boundsOfViewArea: specBoundsOfViewArea, scrollDirectionResponse } = floatDomInfo || {};
const { rowHeaderWidth, columnHeaderHeight } = skeleton;
const boundsOfViewArea = {
top: columnHeaderHeight,
left: rowHeaderWidth,
};
if (specBoundsOfViewArea) {
if (Tools.isDefine(boundsOfViewArea.top)) {
topBoundOfViewArea = boundsOfViewArea.top;
boundsOfViewArea.top = specBoundsOfViewArea.top;
}
if (Tools.isDefine(boundsOfViewArea.left)) {
leftBoundViewArea = boundsOfViewArea.left;
boundsOfViewArea.left = specBoundsOfViewArea.left;
}
}
if (scrollDirectionResponse === ScrollDirectionResponse.HORIZONTAL) {
Expand All @@ -142,51 +158,75 @@ export function transformBound2DOMBound(posOfFloatObject: IBoundRectNoAngle, sce
viewportScrollX = 0;
}

let offsetLeft: number;
let offsetRight: number;

// viewMain or viewTop
if (left < leftBoundViewArea) {
absolute.left = true;
offsetLeft = ((leftBoundViewArea) + (left - leftBoundViewArea)) * scaleX;
offsetRight = Math.max(
Math.min(
((leftBoundViewArea) + (right - leftBoundViewArea)) * scaleX,
(leftBoundViewArea) * scaleX
),
(right - viewportScrollX) * scaleX);
} else {
let offsetLeft: number = 0;
let offsetRight: number = 0;

/**
* freezed viewport start & end position
*/
const freezeStartY = skeleton.rowStartY(viewMainStartRow - freezedRow) + columnHeaderHeight;
const freezeStartX = skeleton.colStartX(viewMainStartColumn - freezedCol) + rowHeaderWidth;
const freezeEndY = skeleton.rowStartY(viewMainStartRow) + columnHeaderHeight;
const freezeEndX = skeleton.colStartX(viewMainStartColumn) + rowHeaderWidth;

if (freezedCol === 0) {
absolute.left = false;
offsetLeft = Math.max((left - viewportScrollX) * scaleX, (leftBoundViewArea) * scaleX);
offsetRight = Math.max((right - viewportScrollX) * scaleX, (leftBoundViewArea) * scaleX);
offsetLeft = (left - viewportScrollX) * scaleX;
offsetRight = (right - viewportScrollX) * scaleX;
} else {
// freeze
// viewMainLeft may not start at col = 0
// DO NOT use viewMainLeft?.viewBound.right. It's not accurate. there is a delay to set viewBound!
const leftToCanvas = left - (freezeStartX - rowHeaderWidth);
const rightToCanvas = right - (freezeStartX - rowHeaderWidth);
if (right < freezeEndX) {
offsetLeft = leftToCanvas * scaleX;
offsetRight = rightToCanvas * scaleX;
} else if (left <= freezeEndX && right >= freezeEndX) {
offsetLeft = leftToCanvas * scaleX;
offsetRight = Math.max(viewBoundsLeft, (right - viewportScrollX) * scaleX);
} else if (left > freezeEndX) {
absolute.left = false;
offsetLeft = Math.max((left - viewportScrollX) * scaleX, viewBoundsLeft);
offsetRight = Math.max((right - viewportScrollX) * scaleX, viewBoundsLeft);
}
}

let offsetTop: number;
let offsetBottom: number;
// viewMain or viewTop
if (top < topBoundOfViewArea) {
absolute.top = true;
offsetTop = ((topBoundOfViewArea) + (top - topBoundOfViewArea)) * scaleY;
offsetBottom = Math.max(
Math.min(
((topBoundOfViewArea) + (right - topBoundOfViewArea)) * scaleY,
(topBoundOfViewArea) * scaleY
),
(bottom - viewportScrollY) * scaleY
);
} else {
let offsetTop: number = 0;
let offsetBottom: number = 0;
if (freezedRow === 0) {
absolute.top = false;
offsetTop = Math.max((top - viewportScrollY) * scaleY, (topBoundOfViewArea) * scaleY);
offsetBottom = Math.max((bottom - viewportScrollY) * scaleY, (topBoundOfViewArea) * scaleY);
offsetTop = (top - viewportScrollY) * scaleY;
offsetBottom = (bottom - viewportScrollY) * scaleY;
} else {
const topToCanvas = top - (freezeStartY - columnHeaderHeight);
const bottomToCanvas = bottom - (freezeStartY - columnHeaderHeight);
if (bottom < freezeEndY) {
offsetTop = topToCanvas * scaleY;
offsetBottom = bottomToCanvas * scaleY;
} else if (top <= freezeEndY && bottom >= freezeEndY) {
offsetTop = topToCanvas * scaleY;
offsetBottom = Math.max(viewBoundsTop, (bottom - viewportScrollY) * scaleY);
} else if (top > freezeEndY) {
absolute.top = false;
offsetTop = Math.max((top - viewportScrollY) * scaleY, viewBoundsTop);
offsetBottom = Math.max((bottom - viewportScrollY) * scaleY, viewBoundsTop);
}
}

return {
offsetLeft = Math.max(offsetLeft, boundsOfViewArea.left);
offsetTop = Math.max(offsetTop, boundsOfViewArea.top);
offsetRight = Math.max(offsetRight, boundsOfViewArea.left);
offsetBottom = Math.max(offsetBottom, boundsOfViewArea.top);

const rs = {
left: offsetLeft,
right: offsetRight,
top: offsetTop,
bottom: offsetBottom,
absolute,
};
return rs;
}

/**
Expand Down Expand Up @@ -728,6 +768,7 @@ export class SheetCanvasFloatDomManagerService extends Disposable {
};
}

// eslint-disable-next-line max-lines-per-function, complexity
addFloatDomToRange(range: IRange, config: ICanvasFloatDom, domAnchor: Partial<IDOMAnchor>, propId?: string) {
const target = getSheetCommandTarget(this._univerInstanceService, {
unitId: config.unitId,
Expand Down Expand Up @@ -796,8 +837,8 @@ export class SheetCanvasFloatDomManagerService extends Disposable {
if (!skMangerService) {
return;
}
const skeleton = skMangerService.getWorksheetSkeleton(subUnitId);
if (!skeleton) {
const skeletonParam = skMangerService.getWorksheetSkeleton(subUnitId);
if (!skeletonParam) {
return;
}

Expand Down Expand Up @@ -870,9 +911,11 @@ export class SheetCanvasFloatDomManagerService extends Disposable {
const disposableCollection = new DisposableCollection();

const viewMain = scene.getMainViewport();
const { rowHeaderWidth, columnHeaderHeight } = skeletonParam.skeleton;

const boundsOfViewArea: IBoundRectNoAngle = {
top: viewMain.top,
left: viewMain.left,
top: columnHeaderHeight,
left: rowHeaderWidth,
bottom: viewMain.bottom,
right: viewMain.right,
};
Expand All @@ -886,7 +929,7 @@ export class SheetCanvasFloatDomManagerService extends Disposable {
subUnitId,
} as unknown as ICanvasFloatDomInfo;

const initedPosition = calcPosition(domRect, renderObject.renderUnit, skeleton.skeleton, target.worksheet, floatDomInfo);
const initedPosition = calcPosition(domRect, renderObject.renderUnit, skeletonParam.skeleton, target.worksheet, floatDomInfo);
const position$ = new BehaviorSubject<IFloatDomLayout>(initedPosition);
floatDomInfo.position$ = position$;

Expand Down Expand Up @@ -943,7 +986,7 @@ export class SheetCanvasFloatDomManagerService extends Disposable {
height: domAnchor.height ?? newRangePos.height,
zIndex: this._drawingManagerService.getDrawingOrder(unitId, subUnitId).length - 1,
});
const newPos = calcPosition(newRect, renderObject.renderUnit, skeleton.skeleton, target.worksheet, floatDomInfo);
const newPos = calcPosition(newRect, renderObject.renderUnit, skeletonParam.skeleton, target.worksheet, floatDomInfo);
position$.next(newPos);
}));
const skm = this._renderManagerService.getRenderById(unitId)?.with(SheetSkeletonManagerService);
Expand All @@ -956,7 +999,7 @@ export class SheetCanvasFloatDomManagerService extends Disposable {
});

const listener = domRect.onTransformChange$.subscribeEvent(() => {
const newPosition = calcPosition(domRect, renderObject.renderUnit, skeleton.skeleton, target.worksheet, floatDomInfo);
const newPosition = calcPosition(domRect, renderObject.renderUnit, skeletonParam.skeleton, target.worksheet, floatDomInfo);
position$.next(
newPosition
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ export class FormatPainterController extends Disposable {
}

private _commandExecutedListener() {
const selectionRenderService = this._renderManagerService.getCurrentTypeOfRenderer(UniverInstanceType.UNIVER_SHEET)!.with(ISheetSelectionRenderService);
const unitId = this._univerInstanceService.getFocusedUnit()?.getUnitId() || '';
const renderUnit = this._renderManagerService.getRenderById(unitId);
if (!renderUnit) return;
const selectionRenderService = renderUnit.with(ISheetSelectionRenderService);

this.disposeWithMe(
selectionRenderService.selectionMoveEnd$.subscribe((selections) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,36 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM
right: 0,
});
viewMain.resetPadding();
viewMainLeft.resizeWhenFreezeChange({
left: rowHeaderWidthAndMarginLeft,
top: columnHeaderHeightAndMarginTop,
bottom: 0,
width: 0,
});
viewMainTop.resizeWhenFreezeChange({
left: rowHeaderWidthAndMarginLeft,
top: columnHeaderHeightAndMarginTop,
height: 0,
right: 0,
});
viewMainLeftTop.resizeWhenFreezeChange({
left: rowHeaderWidthAndMarginLeft,
top: columnHeaderHeightAndMarginTop,
width: 0,
height: 0,
});
viewRowTop.resizeWhenFreezeChange({
left: 0,
top: columnHeaderHeightAndMarginTop,
width: rowHeaderWidthAndMarginLeft,
height: 0,
});
viewColumnLeft.resizeWhenFreezeChange({
left: 0,
top: 0,
height: columnHeaderHeightAndMarginTop,
width: 0,
});
} else if (isTopView === true && isLeftView === false) {
// freeze row
const topGap = endSheetView.startY - startSheetView.startY;
Expand Down
Loading