Skip to content

Commit

Permalink
feat: add auto col for dv render
Browse files Browse the repository at this point in the history
  • Loading branch information
lumixraku committed Oct 26, 2024
1 parent b090094 commit 9b3f0cb
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 50 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"Duplicatable",
"Dushusir",
"endindex",
"endregion",
"esbuild",
"Ethi",
"evented",
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/sheets/column-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ export class ColumnManager {
/**
* get given column data
* @param columnPos column index
* @returns
*/
getColumn(columnPos: number): Nullable<Partial<IColumnData>> {
const column = this._columnData[columnPos];
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/sheets/sheet-snapshot-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
* limitations under the License.
*/

import { BooleanNumber } from '../types/enum/text-style';
import type { IWorksheetData } from './typedef';
import { BooleanNumber } from '../types/enum/text-style';

// TODO@wzhudev: default value should not be exposed, but the keys.

Expand Down
1 change: 1 addition & 0 deletions packages/data-validation/src/validators/base-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ import type { ICellCustomRender, ICellRenderContext } from '@univerjs/core';

export interface IBaseDataValidationWidget extends ICellCustomRender {
calcCellAutoHeight(info: ICellRenderContext): number | undefined;
calcCellAutoWidth(info: ICellRenderContext): number | undefined;
}
23 changes: 12 additions & 11 deletions packages/engine-render/src/components/sheets/extensions/font.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,12 @@ export class Font extends SheetExtension {
const { ctx, viewRanges, diffRanges, spreadsheetSkeleton, cellInfo } = renderFontCtx;

//#region merged cell
let { startY, endY, startX, endX } = cellInfo;
const { startY, endY, startX, endX } = cellInfo;
const { isMerged, isMergedMainCell, mergeInfo } = cellInfo;
renderFontCtx.startX = startX;
renderFontCtx.startY = startY;
renderFontCtx.endX = endX;
renderFontCtx.endY = endY;

// merged, but not primary cell, then skip. DO NOT RENDER AGAIN, or that would cause font blurry.
if (isMerged && !isMergedMainCell) {
Expand All @@ -164,11 +168,12 @@ export class Font extends SheetExtension {

// merged and primary cell
if (isMergedMainCell) {
startY = mergeInfo.startY;
endY = mergeInfo.endY;
startX = mergeInfo.startX;
endX = mergeInfo.endX;
renderFontCtx.startX = mergeInfo.startX;
renderFontCtx.startY = mergeInfo.startY;
renderFontCtx.endX = mergeInfo.endX;
renderFontCtx.endY = mergeInfo.endY;
}

//#endregion

const fontsConfig = fontMatrix.getValue(row, col);
Expand Down Expand Up @@ -205,14 +210,10 @@ export class Font extends SheetExtension {
//#region text overflow
renderFontCtx.overflowRectangle = overflowRange;
renderFontCtx.cellData = cellData;
renderFontCtx.startX = startX;
renderFontCtx.startY = startY;
renderFontCtx.endX = endX;
renderFontCtx.endY = endY;
this._setFontRenderBounds(renderFontCtx, row, col, fontMatrix);
//#endregion

ctx.translate(startX + FIX_ONE_PIXEL_BLUR_OFFSET, startY + FIX_ONE_PIXEL_BLUR_OFFSET);
ctx.translate(renderFontCtx.startX + FIX_ONE_PIXEL_BLUR_OFFSET, renderFontCtx.startY + FIX_ONE_PIXEL_BLUR_OFFSET);
this._renderDocuments(ctx, fontsConfig, renderFontCtx.startX, renderFontCtx.startY, renderFontCtx.endX, renderFontCtx.endY, row, col, spreadsheetSkeleton.overflowCache);

ctx.closePath();
Expand Down Expand Up @@ -309,7 +310,7 @@ export class Font extends SheetExtension {
}
} else {
ctx.rectByPrecision(startX + 1 / scale, startY + 1 / scale, cellWidth - 2 / scale, cellHeight - 2 / scale);
// for normal cell, forbid text overflow cellarea
// for normal cell, forbid text overflow cell area
ctx.clip();
}
renderFontContext.startX = startX;
Expand Down
49 changes: 30 additions & 19 deletions packages/engine-render/src/components/sheets/sheet-skeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -708,14 +708,13 @@ export class SpreadsheetSkeleton extends Skeleton {
const { startColumn, endColumn } = range;

for (let colIndex = startColumn; colIndex <= endColumn; colIndex++) {
if (!this.worksheet.getColVisible(colIndex)) continue;
// If the row has already been calculated, it does not need to be recalculated
if (calculatedCols.has(colIndex)) {
continue;
}
if (calculatedCols.has(colIndex)) continue;

// const mergedRanges = this.worksheet.getMergedCellRange(startRow, startColumn, endRow, endColumn);

const autoWidth = this._calculateColMaxWidth(colIndex);
const autoWidth = this._calculateColWidth(colIndex);
calculatedCols.add(colIndex);
results.push({
col: colIndex,
Expand All @@ -733,8 +732,7 @@ export class SpreadsheetSkeleton extends Skeleton {
* @param colIndex
* @returns {number} width
*/

private _calculateColMaxWidth(colIndex: number): number {
private _calculateColWidth(colIndex: number): number {
const MEASURE_EXTENT = 10000;
const MEASURE_EXTENT_FOR_PARAGRAPH = MEASURE_EXTENT / 10;
const worksheet = this.worksheet;
Expand Down Expand Up @@ -779,7 +777,8 @@ export class SpreadsheetSkeleton extends Skeleton {
};

const rowIdxArr = createRowSequence(checkStart, checkEnd, otherRowIndex);

const preColIndex = Math.max(0, colIndex - 1);
const currColWidth = this._columnWidthAccumulation[colIndex] - this._columnWidthAccumulation[preColIndex];
for (let i = 0; i < rowIdxArr.length; i++) {
const row = rowIdxArr[i];

Expand All @@ -797,7 +796,8 @@ export class SpreadsheetSkeleton extends Skeleton {
continue;
}
}
let measuredWidth = this.getMeasuredWidthByCell(cell);

let measuredWidth = this._getMeasuredWidthByCell(cell, currColWidth);

if (cell.fontRenderExtension) {
measuredWidth += ((cell.fontRenderExtension?.leftOffset || 0) + (cell.fontRenderExtension?.rightOffset || 0));
Expand All @@ -813,18 +813,24 @@ export class SpreadsheetSkeleton extends Skeleton {

// if there are no content in this column( measure result is 0), return current column width.
if (colWidth === 0) {
const preColIndex = Math.max(0, colIndex - 1);
return this._columnWidthAccumulation[colIndex] - this._columnWidthAccumulation[preColIndex];
return currColWidth;
}
return colWidth;
}

getMeasuredWidthByCell(cell: ICellDataForSheetInterceptor) {
/**
* For _calculateColMaxWidth
* @param cell
* @returns {number} width
*/
_getMeasuredWidthByCell(cell: ICellDataForSheetInterceptor, currColWidth: number) {
let measuredWidth = 0;
if (cell?.interceptorAutoWidth) {
const cellWidth = cell.interceptorAutoWidth();

// isSkip means the text in this cell would not rendering.
if (cell.fontRenderExtension?.isSkip && cell?.interceptorAutoWidth) {
const cellWidth = cell.interceptorAutoWidth?.();
if (cellWidth) {
return measuredWidth;
return cellWidth;
}
}

Expand All @@ -840,8 +846,13 @@ export class SpreadsheetSkeleton extends Skeleton {

const documentViewModel = new DocumentViewModel(documentModel);
const { vertexAngle: angle } = convertTextRotation(textRotation);
const cellStyle = this._styles.getStyleByCell(cell);

documentModel.updateDocumentDataPageSize(Infinity, Infinity);
if (cellStyle?.tb === WrapStrategy.WRAP) {
documentModel.updateDocumentDataPageSize(currColWidth, Infinity);
} else {
documentModel.updateDocumentDataPageSize(Infinity, Infinity);
}

const documentSkeleton = DocumentSkeleton.create(documentViewModel, this._localService);

Expand All @@ -862,10 +873,10 @@ export class SpreadsheetSkeleton extends Skeleton {
const absAngleInRad = Math.abs(degToRad(angle));

measuredWidth +=
t * Math.cos(absAngleInRad) +
r * Math.sin(absAngleInRad) +
b * Math.cos(absAngleInRad) +
l * Math.sin(absAngleInRad);
t * Math.sin(absAngleInRad) +
r * Math.cos(absAngleInRad) +
b * Math.sin(absAngleInRad) +
l * Math.cos(absAngleInRad);
}
return measuredWidth;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,37 @@ export class SheetsDataValidationRenderController extends RxDisposable {
};
return validator?.canvasRender?.calcCellAutoHeight?.(info);
},
interceptorAutoWidth: () => {
const skeleton = this._renderManagerService.getRenderById(unitId)
?.with(SheetSkeletonManagerService)
.getWorksheetSkeleton(subUnitId)
?.skeleton;
if (!skeleton) {
return undefined;
}
const mergeCell = skeleton.worksheet.getMergedCell(row, col);

const info: ICellRenderContext = {
data: {
...cell,
dataValidation: {
ruleId,
validStatus,
rule,
validator,
},
},
style: skeleton.getsStyles().getStyleByCell(cell),
primaryWithCoord: skeleton.getCellByIndex(mergeCell?.startRow ?? row, mergeCell?.startColumn ?? col),
unitId,
subUnitId,
row,
col,
workbook,
worksheet,
};
return validator?.canvasRender?.calcCellAutoWidth?.(info);
},
coverable: (cell?.coverable ?? true) && !(rule.type === DataValidationType.LIST || rule.type === DataValidationType.LIST_MULTIPLE),
});
},
Expand Down Expand Up @@ -390,4 +421,3 @@ export class SheetsDataValidationMobileRenderController extends RxDisposable {
});
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ export class CheckboxRender implements IBaseDataValidationWidget {
return (style?.fs ?? 10) * 1.6;
}

calcCellAutoWidth(info: ICellRenderContext): number | undefined {
const { style } = info;
return (style?.fs ?? 10) * 1.6;
}

private async _parseFormula(rule: IDataValidationRule, unitId: string, subUnitId: string): Promise<IFormulaResult> {
const { formula1 = CHECKBOX_FORMULA_1, formula2 = CHECKBOX_FORMULA_2 } = rule;
const results = await this._formulaService.getRuleFormulaResult(unitId, subUnitId, rule.uid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,32 @@ export class DropdownMultipleWidget implements IBaseDataValidationWidget {
return layout.cellAutoHeight;
}

calcCellAutoWidth(info: ICellRenderContext): number | undefined {
const { primaryWithCoord, style, data } = info;
const fontRenderExtension = data.fontRenderExtension;
const { leftOffset = 0, rightOffset = 0, topOffset = 0, downOffset = 0 } = fontRenderExtension || {};
const _cellBounding = primaryWithCoord.isMergedMainCell ? primaryWithCoord.mergeInfo : primaryWithCoord;
const cellBounding = {
startX: _cellBounding.startX + leftOffset,
endX: _cellBounding.endX - rightOffset,
startY: _cellBounding.startY + topOffset,
endY: _cellBounding.endY - downOffset,
};
const validation = data.dataValidation;
if (!validation) {
return undefined;
}
const cellWidth = cellBounding.endX - cellBounding.startX;
const cellHeight = cellBounding.endY - cellBounding.startY;
const cellValue = getCellValueOrigin(data) ?? '';
const { validator: _validator } = validation;
const validator = _validator as ListMultipleValidator;
const items = validator.parseCellValue(cellValue);
const fontStyle = getFontStyleString(style ?? undefined);
const layout = layoutDropdowns(items, fontStyle, cellWidth, cellHeight);
return layout.calcAutoWidth;
}

isHit(position: { x: number; y: number }, info: ICellRenderContext) {
const { primaryWithCoord } = info;
const cellBounding = primaryWithCoord.isMergedMainCell ? primaryWithCoord.mergeInfo : primaryWithCoord;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,19 @@ import { getCellValueOrigin } from '@univerjs/sheets-data-validation';
import { ShowDataValidationDropdown } from '../../commands/operations/data-validation.operation';
import { DROP_DOWN_DEFAULT_COLOR } from '../../const';

/**
* padding in Capsule
*/
const PADDING_H = 4;
const ICON_SIZE = 4;
const ICON_PLACE = 14;

/**
* margin for Capsule, that means distance between capsule and cell border
*/
const MARGIN_H = 6;
const MARGIN_V = 4;
const RADIUS_BG = 8;
const DROP_DOWN_ICON_COLOR = '#565656';

const downPath = new Path2D('M3.32201 4.84556C3.14417 5.05148 2.85583 5.05148 2.67799 4.84556L0.134292 1.90016C-0.152586 1.56798 0.0505937 1 0.456301 1L5.5437 1C5.94941 1 6.15259 1.56798 5.86571 1.90016L3.32201 4.84556Z');
Expand Down Expand Up @@ -319,7 +327,7 @@ export class DropdownWidget implements IBaseDataValidationWidget {
width: rectWidth,
height: rectHeight,
fill: activeItem?.color || DROP_DOWN_DEFAULT_COLOR,
radius: 8,
radius: RADIUS_BG,
});
ctx.save();
ctx.translateWithPrecision(PADDING_H, 0);
Expand Down Expand Up @@ -410,6 +418,56 @@ export class DropdownWidget implements IBaseDataValidationWidget {
}
}

calcCellAutoWidth(info: ICellRenderContext): number | undefined {
const { primaryWithCoord, style, data } = info;
const cellRange = primaryWithCoord.isMergedMainCell ? primaryWithCoord.mergeInfo : primaryWithCoord;

const fontRenderExtension = data.fontRenderExtension;
const { leftOffset = 0, rightOffset = 0, topOffset = 0, downOffset = 0 } = fontRenderExtension || {};

const rule = data.dataValidation?.rule;
if (!rule) return;
if (rule.renderMode === DataValidationRenderMode.TEXT) return;

const cellBounding = {
startX: cellRange.startX + leftOffset,
endX: cellRange.endX - rightOffset,
startY: cellRange.startY + topOffset,
endY: cellRange.endY - downOffset,
};
const cellWidth = cellBounding.endX - cellBounding.startX;
const value = getCellValueOrigin(data);
const valueStr = `${value ?? ''}`;

let { tb, pd } = style || {};
const { l = DEFAULT_STYLES.pd.l, r = DEFAULT_STYLES.pd.r } = (pd ?? {});
tb = tb ?? WrapStrategy.WRAP;

let paddingAll = MARGIN_H * 2 + ICON_PLACE;
switch (rule.renderMode) {
case DataValidationRenderMode.ARROW:
paddingAll = ICON_PLACE + MARGIN_H * 2 + r + l;
break;
case DataValidationRenderMode.CUSTOM:
// + 1 is must, or last character will be cut
paddingAll = ICON_PLACE + MARGIN_H * 2 + PADDING_H * 2 + r + l + RADIUS_BG / 2 + 1;
break;
// default is CUSTOM
default:
paddingAll = ICON_PLACE + MARGIN_H * 2 + PADDING_H * 2 + r + l + RADIUS_BG / 2 + 1;
}
const widthForTextLayout = cellWidth - paddingAll;
const { documentSkeleton, docModel } = createDocuments(valueStr, this._localeService, style);
if (tb === WrapStrategy.WRAP) {
docModel.updateDocumentDataPageSize(Math.max(widthForTextLayout, 1));
}

documentSkeleton.calculate();
documentSkeleton.getActualSize();
const textLayout = getDocsSkeletonPageSize(documentSkeleton)!;
return textLayout.width + paddingAll;
}

isHit(position: { x: number; y: number }, info: ICellRenderContext) {
const { data, subUnitId, row, col } = info;
const map = this._ensureMap(subUnitId);
Expand Down
Loading

0 comments on commit 9b3f0cb

Please sign in to comment.