@visactor/vtable
Version:
canvas table width high performance
321 lines (302 loc) • 22.4 kB
JavaScript
import { HierarchyState, IconPosition } from "../../ts-types";
import * as calc from "../../tools/calc";
import { getQuadProps } from "../utils/padding";
import { getProp } from "../utils/get-prop";
import { Factory } from "../../core/factory";
import { isArray, isFunction, isNumber, isObject, isValid } from "@visactor/vutils";
import { decodeReactDom, dealPercentCalc } from "../component/custom";
import { breakString } from "../utils/break-string";
import { emptyCustomLayout } from "../../components/react/react-custom-layout";
import { getOrApply } from "../../tools/helper";
export function computeColsWidth(table, colStart, colEnd, update) {
var _a, _b, _c, _d, _e, _f, _g, _h;
table.internalProps.columnWidthConfig && table._parseColumnWidthConfig(table.internalProps.columnWidthConfig),
table.isPivotTable() && table.internalProps.columnWidthConfigForRowHeader && table._parseColumnWidthConfigForRowHeader(table.internalProps.columnWidthConfigForRowHeader),
colStart = null != colStart ? colStart : 0, colEnd = null != colEnd ? colEnd : table.colCount - 1,
0 === colStart && colEnd === table.colCount - 1 && table._clearColRangeWidthsMap();
const layoutMap = table.internalProps.layoutMap;
table.isPivotTable() && (layoutMap.enableUseGetBodyCache(), layoutMap.enableUseHeaderPathCache());
const oldColWidths = [], newWidths = [];
if (update) for (let col = 0; col < table.colCount; col++) oldColWidths[col] = table.getColWidth(col);
for (let col = colStart; col <= colEnd; col++) {
let maxWidth;
if (table.internalProps.transpose || "only-header" !== (null === (_b = null === (_a = table.internalProps.layoutMap.columnObjects) || void 0 === _a ? void 0 : _a[col]) || void 0 === _b ? void 0 : _b.columnWidthComputeMode) && "only-header" !== table.columnWidthComputeMode || !("showHeader" in table.internalProps.layoutMap)) maxWidth = table.internalProps.transpose || "only-body" !== (null === (_d = null === (_c = table.internalProps.layoutMap.columnObjects) || void 0 === _c ? void 0 : _c[col]) || void 0 === _d ? void 0 : _d.columnWidthComputeMode) && "only-body" !== table.columnWidthComputeMode ? computeColWidth(col, 0, table.rowCount - 1, table) : computeColWidth(col, table.internalProps.layoutMap.getBodyRange().start.row, table.internalProps.layoutMap.getBodyRange().end.row, table); else {
const temp = table.internalProps.layoutMap.showHeader;
table.internalProps.layoutMap.showHeader = !0, maxWidth = computeColWidth(col, 0, table.internalProps.layoutMap.headerLevelCount - 1, table),
table.internalProps.layoutMap.showHeader = temp;
}
table._setColContentWidth(col, maxWidth);
table.getColWidth(col) !== maxWidth && table._clearColRangeWidthsMap(col), update ? newWidths[col] = Math.round(table._adjustColWidth(col, maxWidth)) : table._setColWidth(col, table._adjustColWidth(col, maxWidth), !1, !0);
}
if ("adaptive" === table.widthMode) {
table._clearColRangeWidthsMap();
const canvasWidth = table.tableNoFrameWidth;
let actualHeaderWidth = 0, startCol = 0, endCol = table.colCount;
if ("only-body" === table.widthAdaptiveMode) {
for (let col = 0; col < table.colCount; col++) {
const colWidth = update && null !== (_e = newWidths[col]) && void 0 !== _e ? _e : table.getColWidth(col);
(col < table.rowHeaderLevelCount || table.isPivotChart() && col >= table.colCount - table.rightFrozenColCount) && (actualHeaderWidth += colWidth);
}
startCol = table.rowHeaderLevelCount, endCol = table.isPivotChart() ? table.colCount - table.rightFrozenColCount : table.colCount;
}
getAdaptiveWidth(canvasWidth - actualHeaderWidth, startCol, endCol, update, newWidths, table);
} else if (table.autoFillWidth) {
table._clearColRangeWidthsMap();
const canvasWidth = table.tableNoFrameWidth;
let actualHeaderWidth = 0, actualWidth = 0;
for (let col = 0; col < table.colCount; col++) {
const colWidth = update && null !== (_f = newWidths[col]) && void 0 !== _f ? _f : table.getColWidth(col);
(col < table.rowHeaderLevelCount + table.leftRowSeriesNumberCount || table.isPivotChart() && col >= table.colCount - table.rightFrozenColCount) && (actualHeaderWidth += colWidth),
actualWidth += colWidth;
}
if (actualWidth < canvasWidth && actualWidth > actualHeaderWidth) {
getAdaptiveWidth(canvasWidth - actualHeaderWidth, table.rowHeaderLevelCount + table.leftRowSeriesNumberCount, table.isPivotChart() ? table.colCount - table.rightFrozenColCount : table.colCount, update, newWidths, table);
}
}
if (update) {
for (let col = 0; col < table.colCount; col++) {
const newColWidth = null !== (_h = null !== (_g = newWidths[col]) && void 0 !== _g ? _g : table.getColWidth(col)) && void 0 !== _h ? _h : table.getColWidth(col);
newColWidth !== oldColWidths[col] && table._setColWidth(col, newColWidth, !1, !0);
}
table.stateManager.checkFrozen();
for (let col = 0; col < table.colCount; col++) {
const newColWidth = table.getColWidth(col);
newColWidth !== oldColWidths[col] && table.scenegraph.updateColWidth(col, newColWidth - oldColWidths[col], !0, !0);
}
table.scenegraph.updateContainer(!0);
}
table.isPivotTable() && (layoutMap.disableUseGetBodyCache(), layoutMap.disableUseHeaderPathCache());
}
export function computeColWidth(col, startRow, endRow, table, forceCompute = !1) {
let width = getColWidthDefinedWidthResizedWidth(col, table);
return table.internalProps.transpose && "auto" === width && ("only-header" === table.columnWidthComputeMode && col >= table.rowHeaderLevelCount || "only-body" === table.columnWidthComputeMode && col < table.rowHeaderLevelCount) && (width = table.getDefaultColumnWidth(col)),
forceCompute && !table.internalProps.transpose ? computeAutoColWidth(width, col, startRow, endRow, forceCompute, table) : "number" == typeof width ? width : "auto" !== width && "string" == typeof width ? table._adjustColWidth(col, table._colWidthDefineToPxWidth(width)) : computeAutoColWidth(width, col, startRow, endRow, forceCompute, table);
}
function computeAutoColWidth(widthDeifne, col, startRow, endRow, forceCompute, table) {
var _a, _b, _c, _d, _e;
let maxWidth = 0, deltaRow = 1, prepareDeltaRow = 1;
if (endRow - startRow > 5e3 && (prepareDeltaRow = Math.ceil((endRow - startRow) / 5e3)),
table.isPivotChart() && col >= table.rowHeaderLevelCount && col < table.colCount - table.rightFrozenColCount) {
if (table.internalProps.layoutMap.indicatorsAsCol) return table.defaultColWidth;
{
const optimunWidth = table.internalProps.layoutMap.getOptimunWidthForChart(col);
if (optimunWidth > 0) return optimunWidth;
}
}
for (let row = startRow; row <= endRow; row += deltaRow) {
if (table.isPivotChart()) {
const layout = table.internalProps.layoutMap, axisConfig = layout.getAxisConfigInPivotChart(col, row);
if (axisConfig) {
const axisWidth = Factory.getFunction("computeAxisComponentWidth")(axisConfig, table);
if ("number" == typeof axisWidth) {
maxWidth = Math.max(axisWidth, maxWidth);
continue;
}
} else if (layout.isLeftBottomCorner(col, row) || layout.isRightTopCorner(col, row) || layout.isRightBottomCorner(col, row)) continue;
}
const customWidth = computeCustomRenderWidth(col, row, table);
if (customWidth && (maxWidth = Math.max(customWidth.width, maxWidth), !customWidth.renderDefault)) continue;
const indicatorWidth = widthDeifne;
if ("number" == typeof indicatorWidth && "standard" === table.widthMode && !forceCompute) {
maxWidth = Math.max(indicatorWidth, maxWidth);
continue;
}
const cellType = table.isHeader(col, row) ? null === (_a = table._getHeaderLayoutMap(col, row)) || void 0 === _a ? void 0 : _a.headerType : table.getBodyColumnType(col, row);
if (isValid(cellType) && "text" !== cellType && "link" !== cellType && "progressbar" !== cellType && "checkbox" !== cellType && "radio" !== cellType && "switch" !== cellType && "button" !== cellType) {
maxWidth = Math.max(maxWidth, table.getColWidthDefinedNumber(col) || 0);
continue;
}
let cellHierarchyIndent = 0;
const layoutMap = table.internalProps.layoutMap;
if (layoutMap.isHeader(col, row)) {
const hd = layoutMap.getHeader(col, row);
if ("only-body" === (null === (_b = null == hd ? void 0 : hd.define) || void 0 === _b ? void 0 : _b.columnWidthComputeMode)) continue;
isValid(null == hd ? void 0 : hd.hierarchyLevel) && (cellHierarchyIndent = (null !== (_c = hd.hierarchyLevel) && void 0 !== _c ? _c : 0) * ("tree" === layoutMap.rowHierarchyType && null !== (_d = layoutMap.rowHierarchyIndent) && void 0 !== _d ? _d : 0),
layoutMap.rowHierarchyTextStartAlignment && !table.internalProps.headerHelper.getHierarchyIcon(col, row) && (cellHierarchyIndent += table.internalProps.headerHelper.getHierarchyIconWidth()));
} else if (table.isListTable()) {
deltaRow = prepareDeltaRow;
const define = table.getBodyColumnDefine(col, row);
if (null == define ? void 0 : define.tree) {
const indexArr = table.dataSource.getIndexKey(table.getRecordShowIndexByCell(col, row));
cellHierarchyIndent = Array.isArray(indexArr) && table.getHierarchyState(col, row) !== HierarchyState.none ? (indexArr.length - 1) * (null !== (_e = layoutMap.hierarchyIndent) && void 0 !== _e ? _e : 0) : 0,
layoutMap.hierarchyTextStartAlignment && !table.internalProps.bodyHelper.getHierarchyIcon(col, row) && (cellHierarchyIndent += table.internalProps.headerHelper.getHierarchyIconWidth());
}
}
const textWidth = computeTextWidth(col, row, cellType, table);
maxWidth = Math.max(textWidth + cellHierarchyIndent, maxWidth), deltaRow > 1 && table.bottomFrozenRowCount > 0 && row < table.rowCount - table.bottomFrozenRowCount && row + deltaRow >= table.rowCount - table.bottomFrozenRowCount && (row = table.rowCount - table.bottomFrozenRowCount - deltaRow,
deltaRow = 1, prepareDeltaRow = 1);
}
const colMinWidth = table.getMinColWidth(col), colMaxWidth = table.getMaxColWidth(col);
return maxWidth < colMinWidth ? colMinWidth : maxWidth > colMaxWidth ? colMaxWidth : (maxWidth <= 0 && (maxWidth = table.defaultColWidth),
maxWidth);
}
function computeCustomRenderWidth(col, row, table) {
var _a, _b, _c, _d, _e, _f, _g;
const customRender = table.getCustomRender(col, row);
let customLayout = table.getCustomLayout(col, row);
if (customRender || customLayout) {
let cellRange, spanCol = 1, width = 0, renderDefault = !1, enableCellPadding = !1;
(table.isHeader(col, row) || (null === (_a = table.getBodyColumnDefine(col, row)) || void 0 === _a ? void 0 : _a.mergeCell) || table.hasCustomMerge()) && (cellRange = table.getCellRange(col, row),
spanCol = cellRange.end.col - cellRange.start.col + 1);
const arg = {
col: null !== (_b = null == cellRange ? void 0 : cellRange.start.col) && void 0 !== _b ? _b : col,
row: null !== (_c = null == cellRange ? void 0 : cellRange.start.row) && void 0 !== _c ? _c : row,
dataValue: table.getCellOriginValue(col, row),
value: table.getCellValue(col, row) || "",
rect: getCellRect(col, row, table),
table: table,
originCol: col,
originRow: row,
forComputation: !0
};
if ("react-custom-layout" === customLayout && (customLayout = (null === (_d = table.reactCustomLayout) || void 0 === _d ? void 0 : _d.getCustomLayoutFunc(col, row)) || emptyCustomLayout),
isFunction(customLayout)) {
const customLayoutObj = customLayout(arg);
if (customLayoutObj.rootContainer) {
customLayoutObj.rootContainer = decodeReactDom(customLayoutObj.rootContainer), dealPercentCalc(customLayoutObj.rootContainer, 0, table.getRowHeight(row));
const setedWidth = customLayoutObj.rootContainer.attribute.width;
customLayoutObj.rootContainer.setStage(table.scenegraph.stage), width = setedWidth > 0 ? setedWidth : null !== (_e = customLayoutObj.rootContainer.AABBBounds.width()) && void 0 !== _e ? _e : 0,
renderDefault = customLayoutObj.renderDefault, enableCellPadding = customLayoutObj.enableCellPadding;
} else width = 0, renderDefault = customLayoutObj.renderDefault, enableCellPadding = customLayoutObj.enableCellPadding;
} else if ("function" == typeof customRender) {
const customRenderObj = customRender(arg);
width = null !== (_f = null == customRenderObj ? void 0 : customRenderObj.expectedWidth) && void 0 !== _f ? _f : 0,
renderDefault = null == customRenderObj ? void 0 : customRenderObj.renderDefault;
} else width = null !== (_g = null == customRender ? void 0 : customRender.expectedWidth) && void 0 !== _g ? _g : 0,
renderDefault = null == customRender ? void 0 : customRender.renderDefault;
if (width = Math.ceil(width), enableCellPadding) {
const actStyle = table._getCellStyle(col, row), padding = getQuadProps(getProp("padding", actStyle, col, row, table));
width += padding[1] + padding[3];
}
return {
width: width / spanCol,
renderDefault: renderDefault
};
}
}
function computeIndicatorWidth(col, row, forceCompute, table) {
const {layoutMap: layoutMap} = table.internalProps;
if (table.isPivotTable() && layoutMap.isColumnIndicatorHeader(col, row)) {
const body = layoutMap.getBody(col, row);
if (body && body.width && "auto" !== body.width && !forceCompute) {
return Math.round(calc.toPx(body.width, table.internalProps.calcWidthContext));
}
}
}
function computeTextWidth(col, row, cellType, table) {
var _a, _b, _c, _d;
let maxWidth = 0;
const cellValue = table.getCellValue(col, row), actStyle = table._getCellStyle(col, row);
let iconWidth = 0, mayHaveIcon = !1;
if ("body" !== table.getCellLocation(col, row)) mayHaveIcon = !0; else {
const define = table.getBodyColumnDefine(col, row);
mayHaveIcon = !!(null == define ? void 0 : define.icon) || !!(null == define ? void 0 : define.tree) || (null == define ? void 0 : define.dragOrder);
}
if (mayHaveIcon) {
const icons = table.getCellIcons(col, row);
null == icons || icons.forEach((icon => {
var _a, _b, _c;
icon.positionType !== IconPosition.absoluteRight && (iconWidth += (null !== (_a = icon.width) && void 0 !== _a ? _a : 0) + (null !== (_b = icon.marginLeft) && void 0 !== _b ? _b : 0) + (null !== (_c = icon.marginRight) && void 0 !== _c ? _c : 0));
}));
}
let spanCol = 1;
if (table.isHeader(col, row) || (null === (_a = table.getBodyColumnDefine(col, row)) || void 0 === _a ? void 0 : _a.mergeCell) || table.hasCustomMerge()) {
const cellRange = table.getCellRange(col, row);
spanCol = cellRange.end.col - cellRange.start.col + 1;
}
const padding = getQuadProps(getProp("padding", actStyle, col, row, table)), paddingWidth = padding[1] + padding[3], fontSize = getProp("fontSize", actStyle, col, row, table), fontFamily = getProp("fontFamily", actStyle, col, row, table), fontWeight = getProp("fontWeight", actStyle, col, row, table);
let text;
if ("checkbox" === cellType) text = isObject(cellValue) ? cellValue.text : cellValue; else if ("radio" === cellType) if (isArray(cellValue)) {
text = "";
const define = table.getBodyColumnDefine(col, row), radioDirectionInCell = null !== (_b = null == define ? void 0 : define.radioDirectionInCell) && void 0 !== _b ? _b : "vertical";
"vertical" === radioDirectionInCell ? cellValue.forEach((line => {
text += (isObject(line) ? line.text : line).toString() + "\n";
})) : "horizontal" === radioDirectionInCell && cellValue.forEach((line => {
text += (isObject(line) ? line.text : line).toString();
}));
} else text = isObject(cellValue) ? cellValue.text : cellValue; else if ("button" === cellType) {
const define = table.getBodyColumnDefine(col, row), buttonTextValue = getOrApply(define.text, {
col: col,
row: row,
table: table,
context: null,
value: cellValue,
dataValue: table.getCellOriginValue(col, row)
});
text = null !== (_c = null != buttonTextValue ? buttonTextValue : cellValue) && void 0 !== _c ? _c : "";
} else text = cellValue;
const lines = breakString(text, table).text;
if (lines.length >= 1 && (1 !== lines.length || "" !== lines[0]) ? lines.forEach((line => {
const width = table.measureText(line, {
fontSize: fontSize,
fontFamily: fontFamily,
fontWeight: fontWeight
}).width;
maxWidth = Math.max((width + paddingWidth + 4 + iconWidth) / spanCol, maxWidth);
})) : maxWidth = Math.max((paddingWidth + 4 + iconWidth) / spanCol, maxWidth), !1 !== table.internalProps.limitMaxAutoWidth && (maxWidth = Math.min("number" == typeof table.internalProps.limitMaxAutoWidth ? table.internalProps.limitMaxAutoWidth : 450, maxWidth)),
"checkbox" === cellType) {
const size = getProp("size", actStyle, col, row, table);
if (maxWidth += size, text) {
const spaceBetweenTextAndIcon = getProp("spaceBetweenTextAndIcon", actStyle, col, row, table);
maxWidth += spaceBetweenTextAndIcon;
}
} else if ("radio" === cellType) {
const size = getProp("size", actStyle, col, row, table), outerRadius = getProp("outerRadius", actStyle, col, row, table), circleSize = isNumber(outerRadius) ? 2 * outerRadius : size, spaceBetweenTextAndIcon = getProp("spaceBetweenTextAndIcon", actStyle, col, row, table);
if (isArray(cellValue)) {
const define = table.getBodyColumnDefine(col, row), spaceBetweenRadio = getProp("spaceBetweenRadio", actStyle, col, row, table), radioDirectionInCell = null !== (_d = null == define ? void 0 : define.radioDirectionInCell) && void 0 !== _d ? _d : "vertical";
"vertical" === radioDirectionInCell ? (maxWidth += circleSize, maxWidth += spaceBetweenTextAndIcon) : "horizontal" === radioDirectionInCell && (maxWidth += (circleSize + spaceBetweenTextAndIcon) * cellValue.length,
maxWidth += spaceBetweenRadio * (cellValue.length - 1));
} else maxWidth += circleSize, text && (maxWidth += spaceBetweenTextAndIcon);
} else if ("switch" === cellType) {
const boxWidth = getProp("boxWidth", actStyle, col, row, table);
maxWidth = boxWidth;
} else if ("button" === cellType) {
const buttonPadding = getProp("buttonPadding", actStyle, col, row, table);
maxWidth += 2 * buttonPadding;
}
return maxWidth;
}
function getCellRect(col, row, table) {
return {
left: 0,
top: 0,
right: table.getColWidth(col),
bottom: table.getRowHeight(row),
width: null,
height: null
};
}
function getColWidthDefinedWidthResizedWidth(col, table) {
const widthDefined = table.getColWidthDefined(col);
return table.internalProps._widthResizedColMap.has(col) ? table.getColWidth(col) : widthDefined;
}
export function getAdaptiveWidth(totalDrawWidth, startCol, endColPlus1, update, newWidths, table, fromScenegraph) {
var _a, _b, _c, _d;
let actualWidth = 0;
const adaptiveColumns = [], sparklineColumns = [];
let totalSparklineAbleWidth = 0;
for (let col = startCol; col < endColPlus1; col++) {
const width = update && null !== (_a = newWidths[col]) && void 0 !== _a ? _a : table.getColWidth(col), maxWidth = table.getMaxColWidth(col), minWidth = table.getMinColWidth(col);
if (width !== maxWidth && width !== minWidth ? (actualWidth += width, adaptiveColumns.push(col)) : totalDrawWidth -= width,
null === (_b = table.options.customConfig) || void 0 === _b ? void 0 : _b.shrinkSparklineFirst) {
"sparkline" === table.getBodyColumnType(col, 0) && (sparklineColumns.push({
col: col,
width: width
}), totalSparklineAbleWidth += width - table.defaultColWidth);
}
}
const factor = totalDrawWidth / actualWidth;
if ((null === (_c = table.options.customConfig) || void 0 === _c ? void 0 : _c.shrinkSparklineFirst) && factor < 1 && actualWidth - totalDrawWidth < totalSparklineAbleWidth) for (let i = 0; i < sparklineColumns.length; i++) {
const {col: col, width: width} = sparklineColumns[i], deltaWidth = (actualWidth - totalDrawWidth) / sparklineColumns.length, colWidth = Math.floor(width - deltaWidth);
update ? newWidths[col] = table._adjustColWidth(col, colWidth) : fromScenegraph ? table.scenegraph.setColWidth(col, table._adjustColWidth(col, colWidth)) : table._setColWidth(col, table._adjustColWidth(col, colWidth), !1, !0);
} else for (let i = 0; i < adaptiveColumns.length; i++) {
const col = adaptiveColumns[i];
let colWidth;
colWidth = i === adaptiveColumns.length - 1 ? totalDrawWidth - adaptiveColumns.reduce(((acr, cur, index) => {
var _a;
return cur !== col ? acr + (update ? null !== (_a = newWidths[cur]) && void 0 !== _a ? _a : table.getColWidth(col) : table.getColWidth(cur)) : acr;
}), 0) : Math.round((update && null !== (_d = newWidths[col]) && void 0 !== _d ? _d : table.getColWidth(col)) * factor),
update ? newWidths[col] = table._adjustColWidth(col, colWidth) : fromScenegraph ? table.scenegraph.setColWidth(col, table._adjustColWidth(col, colWidth)) : table._setColWidth(col, table._adjustColWidth(col, colWidth), !1, !0);
}
}
//# sourceMappingURL=compute-col-width.js.map