zmdms-webui 2.6.2 → 2.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/canvastable/canvasTable.js +75 -27
- package/dist/es/canvastable/hooks/renderers/BadgeRenderer.js +58 -0
- package/dist/es/canvastable/hooks/renderers/BorderRenderer.js +229 -0
- package/dist/es/canvastable/hooks/renderers/DataRowRenderer.js +358 -0
- package/dist/es/canvastable/hooks/renderers/ExpandIconRenderer.js +97 -0
- package/dist/es/canvastable/hooks/renderers/FixedColumnRenderer.js +71 -0
- package/dist/es/canvastable/hooks/renderers/FixedRowRenderer.js +192 -0
- package/dist/es/canvastable/hooks/renderers/HeaderRenderer.js +395 -0
- package/dist/es/canvastable/hooks/renderers/ScrollbarRenderer.js +85 -0
- package/dist/es/canvastable/hooks/renderers/SelectionRenderer.js +181 -0
- package/dist/es/canvastable/hooks/useExpandable.js +185 -0
- package/dist/es/canvastable/hooks/useTableInteraction.js +37 -1
- package/dist/es/canvastable/hooks/useTableRender.js +172 -1464
- package/dist/es/canvastable/interface.d.ts +71 -1
- package/dist/es/canvastable/utils/renderHelpers.js +118 -0
- package/dist/es/table/excel.js +62 -9
- package/dist/es/table/table.js +17 -15
- package/package.json +3 -2
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { COLORS, FONT_WEIGHT, FONT_SIZE, FONT_FAMILY, SCROLLBAR_SIZE } from '../../utils/constants.js';
|
|
2
|
+
import { drawCheckbox, truncateText } from '../../utils/canvasDrawHelpers.js';
|
|
3
|
+
import { formatCellValue } from '../../utils/formatHelpers.js';
|
|
4
|
+
import '../../../_virtual/_tslib.js';
|
|
5
|
+
import { setTextAlign, calculateTextX } from '../../utils/renderHelpers.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 固定行渲染器
|
|
9
|
+
* 负责渲染固定的顶部行、底部行和合计行
|
|
10
|
+
*/
|
|
11
|
+
var FixedRowRenderer = /** @class */ (function () {
|
|
12
|
+
function FixedRowRenderer() {
|
|
13
|
+
this.context = null;
|
|
14
|
+
}
|
|
15
|
+
FixedRowRenderer.prototype.setContext = function (context) {
|
|
16
|
+
this.context = context;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* 渲染固定顶部�?
|
|
20
|
+
*/
|
|
21
|
+
FixedRowRenderer.prototype.renderFixedTopRows = function (onlyFixed) {
|
|
22
|
+
var _this = this;
|
|
23
|
+
if (onlyFixed === void 0) { onlyFixed = false; }
|
|
24
|
+
if (!this.context) {
|
|
25
|
+
throw new Error("FixedRowRenderer: Context not set");
|
|
26
|
+
}
|
|
27
|
+
var _a = this.context, fixedRowsCount = _a.fixedRowsCount, fixedRowsConfig = _a.fixedRowsConfig;
|
|
28
|
+
var fixedTopCount = fixedRowsCount || (fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.topCount) || 0;
|
|
29
|
+
for (var i = 0; i < fixedTopCount; i++) {
|
|
30
|
+
this.renderFixedRow(i, "top", function (idx) { return _this.context.headerHeight + idx * _this.context.rowHeight; }, onlyFixed);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* 渲染固定底部�?
|
|
35
|
+
*/
|
|
36
|
+
FixedRowRenderer.prototype.renderFixedBottomRows = function (onlyFixed) {
|
|
37
|
+
if (onlyFixed === void 0) { onlyFixed = false; }
|
|
38
|
+
if (!this.context) {
|
|
39
|
+
throw new Error("FixedRowRenderer: Context not set");
|
|
40
|
+
}
|
|
41
|
+
var _a = this.context, processedDataSource = _a.processedDataSource, displayHeight = _a.displayHeight, needHorizontalScrollbar = _a.needHorizontalScrollbar, rowHeight = _a.rowHeight, summaryFixed = _a.summaryFixed, hasSummaryRow = _a.hasSummaryRow, fixedRowsConfig = _a.fixedRowsConfig;
|
|
42
|
+
var fixedBottomCount = (fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.bottomCount) || 0;
|
|
43
|
+
if (fixedBottomCount === 0)
|
|
44
|
+
return;
|
|
45
|
+
var bottomRowsStartIndex = processedDataSource.length -
|
|
46
|
+
fixedBottomCount -
|
|
47
|
+
(summaryFixed && hasSummaryRow ? 1 : 0);
|
|
48
|
+
var _loop_1 = function (i) {
|
|
49
|
+
var rowIndex = bottomRowsStartIndex + i;
|
|
50
|
+
this_1.renderFixedRow(rowIndex, "bottom", function () {
|
|
51
|
+
var fixedSummaryHeight = summaryFixed && hasSummaryRow ? rowHeight : 0;
|
|
52
|
+
return (displayHeight -
|
|
53
|
+
(needHorizontalScrollbar ? SCROLLBAR_SIZE : 0) -
|
|
54
|
+
fixedSummaryHeight -
|
|
55
|
+
fixedBottomCount * rowHeight +
|
|
56
|
+
i * rowHeight);
|
|
57
|
+
}, onlyFixed);
|
|
58
|
+
};
|
|
59
|
+
var this_1 = this;
|
|
60
|
+
for (var i = 0; i < fixedBottomCount; i++) {
|
|
61
|
+
_loop_1(i);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* 渲染固定合计�?
|
|
66
|
+
*/
|
|
67
|
+
FixedRowRenderer.prototype.renderFixedSummaryRow = function (onlyFixed) {
|
|
68
|
+
if (onlyFixed === void 0) { onlyFixed = false; }
|
|
69
|
+
if (!this.context) {
|
|
70
|
+
throw new Error("FixedRowRenderer: Context not set");
|
|
71
|
+
}
|
|
72
|
+
var _a = this.context, summaryFixed = _a.summaryFixed, hasSummaryRow = _a.hasSummaryRow, processedDataSource = _a.processedDataSource, displayHeight = _a.displayHeight, needHorizontalScrollbar = _a.needHorizontalScrollbar, rowHeight = _a.rowHeight;
|
|
73
|
+
if (!summaryFixed || !hasSummaryRow)
|
|
74
|
+
return;
|
|
75
|
+
var summaryRowIndex = processedDataSource.length - 1;
|
|
76
|
+
var summaryRowY = displayHeight -
|
|
77
|
+
(needHorizontalScrollbar ? SCROLLBAR_SIZE : 0) -
|
|
78
|
+
rowHeight;
|
|
79
|
+
this.renderFixedRow(summaryRowIndex, "summary", function () { return summaryRowY; }, onlyFixed);
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* 通用的固定行渲染函数
|
|
83
|
+
*/
|
|
84
|
+
FixedRowRenderer.prototype.renderFixedRow = function (rowIndex, position, yCalculator, onlyFixed) {
|
|
85
|
+
if (onlyFixed === void 0) { onlyFixed = false; }
|
|
86
|
+
if (!this.context)
|
|
87
|
+
return;
|
|
88
|
+
var _a = this.context, ctx = _a.ctx, processedDataSource = _a.processedDataSource, columnRenderInfos = _a.columnRenderInfos, rowHeight = _a.rowHeight, scrollState = _a.scrollState, state = _a.state, getRowKey = _a.getRowKey, displayWidth = _a.displayWidth, fixedRowsConfig = _a.fixedRowsConfig, striped = _a.striped, getColumnWidth = _a.getColumnWidth;
|
|
89
|
+
var record = processedDataSource[rowIndex];
|
|
90
|
+
if (!record)
|
|
91
|
+
return;
|
|
92
|
+
var fixedY = yCalculator(rowIndex);
|
|
93
|
+
ctx.save();
|
|
94
|
+
var recordKey = getRowKey(record, rowIndex);
|
|
95
|
+
var isSelected = state.selectedRowKeys.includes(recordKey);
|
|
96
|
+
var isHover = state.hoverRowIndex === rowIndex;
|
|
97
|
+
columnRenderInfos.forEach(function (info, colIndex) {
|
|
98
|
+
var _a;
|
|
99
|
+
var column = info.column, x = info.x, width = info.width, fixed = info.fixed, fixedLeft = info.fixedLeft;
|
|
100
|
+
// 根据 onlyFixed 参数过滤
|
|
101
|
+
if (onlyFixed && !fixed)
|
|
102
|
+
return;
|
|
103
|
+
if (!onlyFixed && fixed)
|
|
104
|
+
return;
|
|
105
|
+
var actualWidth = getColumnWidth ? getColumnWidth(colIndex) : width;
|
|
106
|
+
var drawX = fixed ? fixedLeft : x - scrollState.scrollLeft;
|
|
107
|
+
// 跳过不可见的�?
|
|
108
|
+
if (!fixed && (drawX + actualWidth < 0 || drawX > displayWidth)) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// 绘制背景
|
|
112
|
+
var bgColor = COLORS.white;
|
|
113
|
+
if ((_a = fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.style) === null || _a === void 0 ? void 0 : _a.backgroundColor) {
|
|
114
|
+
bgColor = fixedRowsConfig.style.backgroundColor;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
if (isSelected) {
|
|
118
|
+
bgColor = COLORS.selectedBg;
|
|
119
|
+
}
|
|
120
|
+
else if (isHover) {
|
|
121
|
+
bgColor = COLORS.hoverBg;
|
|
122
|
+
}
|
|
123
|
+
else if (striped && rowIndex % 2 === 1) {
|
|
124
|
+
bgColor = COLORS.stripedBg;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
ctx.fillStyle = bgColor;
|
|
128
|
+
ctx.fillRect(drawX, fixedY, actualWidth, rowHeight);
|
|
129
|
+
// 处理序号�?
|
|
130
|
+
if (column.key === "__index__") {
|
|
131
|
+
if (position !== "summary") {
|
|
132
|
+
var indexText = String(rowIndex + 1);
|
|
133
|
+
ctx.fillStyle = COLORS.text;
|
|
134
|
+
ctx.font = "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
|
|
135
|
+
ctx.textBaseline = "middle";
|
|
136
|
+
setTextAlign(ctx, "center");
|
|
137
|
+
var textX = drawX + actualWidth / 2;
|
|
138
|
+
var textY = fixedY + rowHeight / 2;
|
|
139
|
+
ctx.fillText(indexText, textX, textY);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// 处理选择框列
|
|
144
|
+
if (column.key === "__selection__") {
|
|
145
|
+
if (position !== "summary") {
|
|
146
|
+
var checkboxX = drawX + actualWidth / 2;
|
|
147
|
+
var textY = fixedY + rowHeight / 2;
|
|
148
|
+
drawCheckbox(ctx, checkboxX, textY, isSelected, false, false);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// 获取单元格�?
|
|
153
|
+
var dataIndex = column.dataIndex || column.key;
|
|
154
|
+
var cellValue = record[dataIndex];
|
|
155
|
+
// 渲染单元格内�?
|
|
156
|
+
var cellText = formatCellValue(cellValue, column);
|
|
157
|
+
// 检查是否有render函数且返回自定义ReactNode
|
|
158
|
+
var shouldRenderInCanvas = true;
|
|
159
|
+
var isSummaryRowFixed = position === "summary";
|
|
160
|
+
if (column.render && !isSummaryRowFixed) {
|
|
161
|
+
var rendered = column.render(cellValue, record, rowIndex);
|
|
162
|
+
if (typeof rendered !== "string" &&
|
|
163
|
+
typeof rendered !== "number" &&
|
|
164
|
+
rendered !== null &&
|
|
165
|
+
rendered !== undefined) {
|
|
166
|
+
shouldRenderInCanvas = false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// 只有在需要在Canvas中渲染时才绘制文�?
|
|
170
|
+
if (cellText && shouldRenderInCanvas) {
|
|
171
|
+
ctx.fillStyle = COLORS.text;
|
|
172
|
+
ctx.font =
|
|
173
|
+
position === "summary"
|
|
174
|
+
? "bold ".concat(FONT_SIZE, "px ").concat(FONT_FAMILY)
|
|
175
|
+
: "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
|
|
176
|
+
ctx.textBaseline = "middle";
|
|
177
|
+
var align = column.align || "left";
|
|
178
|
+
setTextAlign(ctx, align);
|
|
179
|
+
var padding = 5;
|
|
180
|
+
var maxWidth = actualWidth - padding * 2;
|
|
181
|
+
var textY = fixedY + rowHeight / 2;
|
|
182
|
+
var textX = calculateTextX(drawX, actualWidth, align, padding);
|
|
183
|
+
var truncatedText = truncateText(ctx, cellText, maxWidth);
|
|
184
|
+
ctx.fillText(truncatedText, textX, textY);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
ctx.restore();
|
|
188
|
+
};
|
|
189
|
+
return FixedRowRenderer;
|
|
190
|
+
}());
|
|
191
|
+
|
|
192
|
+
export { FixedRowRenderer };
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import { isValidElement } from 'react';
|
|
2
|
+
import { COLORS, FONT_WEIGHT, FONT_SIZE, FONT_FAMILY, TEXT_PADDING } from '../../utils/constants.js';
|
|
3
|
+
import { drawCheckbox, wrapText, truncateText, drawFilterIcon, drawSortIcon } from '../../utils/canvasDrawHelpers.js';
|
|
4
|
+
import { getMaxDepth, flattenHeaders, calculateLayerHeights, getLeafColumns } from '../../utils/multiHeaderHelpers.js';
|
|
5
|
+
import 'zmdms-utils';
|
|
6
|
+
import 'dayjs';
|
|
7
|
+
import { calculateSelectionState, calculateIconArea } from '../../utils/interactionHelpers.js';
|
|
8
|
+
import '../../../_virtual/_tslib.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 表头渲染�?
|
|
12
|
+
* 负责渲染单层和多层表�?
|
|
13
|
+
*/
|
|
14
|
+
var HeaderRenderer = /** @class */ (function () {
|
|
15
|
+
function HeaderRenderer() {
|
|
16
|
+
this.context = null;
|
|
17
|
+
this.isMultiHeader = false;
|
|
18
|
+
this.flattenedHeaderRows = [];
|
|
19
|
+
this.layerHeights = [];
|
|
20
|
+
this.layerStartY = [];
|
|
21
|
+
}
|
|
22
|
+
HeaderRenderer.prototype.setContext = function (context) {
|
|
23
|
+
this.context = context;
|
|
24
|
+
// 判断是否是多级表�?
|
|
25
|
+
var maxDepth = getMaxDepth(context.columns);
|
|
26
|
+
this.isMultiHeader = maxDepth > 1;
|
|
27
|
+
// 扁平化多级表头(如果需要)
|
|
28
|
+
if (this.isMultiHeader) {
|
|
29
|
+
this.flattenedHeaderRows = flattenHeaders(context.columns);
|
|
30
|
+
}
|
|
31
|
+
// 计算多级表头每一层的高度
|
|
32
|
+
var _a = calculateLayerHeights(context.columns, context.baseHeaderHeight ||
|
|
33
|
+
(maxDepth > 1
|
|
34
|
+
? Math.floor(context.headerHeight / maxDepth)
|
|
35
|
+
: context.headerHeight), context.columnRenderInfos), layerHeights = _a.layerHeights, layerStartY = _a.layerStartY;
|
|
36
|
+
this.layerHeights = layerHeights;
|
|
37
|
+
this.layerStartY = layerStartY;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* 渲染表头主入�?
|
|
41
|
+
*/
|
|
42
|
+
HeaderRenderer.prototype.render = function () {
|
|
43
|
+
if (!this.context) {
|
|
44
|
+
throw new Error("HeaderRenderer: Context not set");
|
|
45
|
+
}
|
|
46
|
+
var _a = this.context, ctx = _a.ctx, displayWidth = _a.displayWidth, headerHeight = _a.headerHeight;
|
|
47
|
+
// 表头背景
|
|
48
|
+
ctx.fillStyle = COLORS.headerBg;
|
|
49
|
+
ctx.fillRect(0, 0, displayWidth, headerHeight);
|
|
50
|
+
if (this.isMultiHeader) {
|
|
51
|
+
this.renderMultiHeader();
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.renderSingleHeader();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* 渲染单层表头
|
|
59
|
+
*/
|
|
60
|
+
HeaderRenderer.prototype.renderSingleHeader = function () {
|
|
61
|
+
var _this = this;
|
|
62
|
+
if (!this.context)
|
|
63
|
+
return;
|
|
64
|
+
var _a = this.context, columnRenderInfos = _a.columnRenderInfos, displayWidth = _a.displayWidth, displayHeight = _a.displayHeight;
|
|
65
|
+
// 先绘制非fixed�?
|
|
66
|
+
columnRenderInfos.forEach(function (info, index) {
|
|
67
|
+
if (!info.fixed) {
|
|
68
|
+
_this.renderHeaderCell(info, index, displayWidth, displayHeight, false);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
// 再绘制fixed列(覆盖在非fixed列之上)
|
|
72
|
+
columnRenderInfos.forEach(function (info, index) {
|
|
73
|
+
if (info.fixed) {
|
|
74
|
+
_this.renderHeaderCell(info, index, displayWidth, displayHeight, false);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* 渲染多层表头
|
|
80
|
+
*/
|
|
81
|
+
HeaderRenderer.prototype.renderMultiHeader = function () {
|
|
82
|
+
var _this = this;
|
|
83
|
+
if (!this.context)
|
|
84
|
+
return;
|
|
85
|
+
var displayWidth = this.context.displayWidth;
|
|
86
|
+
// 先绘制非fixed�?
|
|
87
|
+
this.flattenedHeaderRows.forEach(function (headerRow, rowIndex) {
|
|
88
|
+
var y = _this.layerStartY[rowIndex];
|
|
89
|
+
headerRow.forEach(function (headerCell) {
|
|
90
|
+
// 计算单元格的总高度(如果跨越多层�?
|
|
91
|
+
var totalCellHeight = 0;
|
|
92
|
+
for (var i = rowIndex; i < rowIndex + headerCell.rowSpan; i++) {
|
|
93
|
+
totalCellHeight += _this.layerHeights[i];
|
|
94
|
+
}
|
|
95
|
+
_this.renderMultiHeaderCell(headerCell, y, displayWidth, rowIndex, totalCellHeight, false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
// 再绘制fixed列(覆盖在非fixed列之上)
|
|
99
|
+
this.flattenedHeaderRows.forEach(function (headerRow, rowIndex) {
|
|
100
|
+
var y = _this.layerStartY[rowIndex];
|
|
101
|
+
headerRow.forEach(function (headerCell) {
|
|
102
|
+
// 计算单元格的总高度(如果跨越多层�?
|
|
103
|
+
var totalCellHeight = 0;
|
|
104
|
+
for (var i = rowIndex; i < rowIndex + headerCell.rowSpan; i++) {
|
|
105
|
+
totalCellHeight += _this.layerHeights[i];
|
|
106
|
+
}
|
|
107
|
+
_this.renderMultiHeaderCell(headerCell, y, displayWidth, rowIndex, totalCellHeight, true);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* 渲染单个表头单元格(单层表头�?
|
|
113
|
+
*/
|
|
114
|
+
HeaderRenderer.prototype.renderHeaderCell = function (info, index, displayWidth, displayHeight, onlyFixed) {
|
|
115
|
+
if (!this.context)
|
|
116
|
+
return;
|
|
117
|
+
var _a = this.context, ctx = _a.ctx, scrollState = _a.scrollState, headerHeight = _a.headerHeight, bordered = _a.bordered, state = _a.state, processedDataSource = _a.processedDataSource, getRowKey = _a.getRowKey, rowSelection = _a.rowSelection, resizeState = _a.resizeState, getColumnWidth = _a.getColumnWidth, _b = _a.RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_WIDTH = _b === void 0 ? 8 : _b, headerAlign = _a.headerAlign;
|
|
118
|
+
var column = info.column, x = info.x, fixed = info.fixed, fixedLeft = info.fixedLeft;
|
|
119
|
+
var width = getColumnWidth ? getColumnWidth(index) : info.width;
|
|
120
|
+
var drawX = fixed ? fixedLeft : x - scrollState.scrollLeft;
|
|
121
|
+
// 跳过不在可视区域的列
|
|
122
|
+
if (!fixed && (drawX + width < 0 || drawX > displayWidth)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// 绘制表头单元�?
|
|
126
|
+
ctx.save();
|
|
127
|
+
ctx.beginPath();
|
|
128
|
+
ctx.rect(drawX, 0, width, headerHeight);
|
|
129
|
+
ctx.clip();
|
|
130
|
+
// 绘制单元格背�?
|
|
131
|
+
ctx.fillStyle = COLORS.headerBg;
|
|
132
|
+
ctx.fillRect(drawX, 0, width, headerHeight);
|
|
133
|
+
// 表头文本
|
|
134
|
+
ctx.fillStyle = COLORS.text;
|
|
135
|
+
ctx.font = "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
|
|
136
|
+
ctx.textBaseline = "middle";
|
|
137
|
+
var textY = headerHeight / 2;
|
|
138
|
+
// 绘制选择�?
|
|
139
|
+
if (column.key === "__selection__") {
|
|
140
|
+
var selectionState = calculateSelectionState(processedDataSource, state.selectedRowKeys, getRowKey, rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.getCheckboxProps);
|
|
141
|
+
var checkboxX = drawX + width / 2;
|
|
142
|
+
drawCheckbox(ctx, checkboxX, textY, selectionState.isAllSelected, false, selectionState.isIndeterminate);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// 计算图标占用的宽�?
|
|
146
|
+
var iconArea = calculateIconArea(column, width);
|
|
147
|
+
// 确定表头对齐方式
|
|
148
|
+
var columnHeaderAlign = column.headerAlign || headerAlign;
|
|
149
|
+
// 绘制文本
|
|
150
|
+
if (!isValidElement(column.title)) {
|
|
151
|
+
var titleText = String(column.title || "");
|
|
152
|
+
var textX_1;
|
|
153
|
+
var textMaxWidth = void 0;
|
|
154
|
+
if (iconArea.iconsWidth > 0) {
|
|
155
|
+
if (columnHeaderAlign === "right") {
|
|
156
|
+
ctx.textAlign = "right";
|
|
157
|
+
textX_1 = drawX + width - TEXT_PADDING - iconArea.iconsWidth;
|
|
158
|
+
textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
|
|
159
|
+
}
|
|
160
|
+
else if (columnHeaderAlign === "center") {
|
|
161
|
+
ctx.textAlign = "center";
|
|
162
|
+
textX_1 = drawX + (width - iconArea.iconsWidth) / 2;
|
|
163
|
+
textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
ctx.textAlign = "left";
|
|
167
|
+
textX_1 = drawX + TEXT_PADDING;
|
|
168
|
+
textMaxWidth = width - TEXT_PADDING - iconArea.iconsWidth;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
if (columnHeaderAlign === "left") {
|
|
173
|
+
ctx.textAlign = "left";
|
|
174
|
+
textX_1 = drawX + TEXT_PADDING;
|
|
175
|
+
textMaxWidth = width - TEXT_PADDING * 2;
|
|
176
|
+
}
|
|
177
|
+
else if (columnHeaderAlign === "right") {
|
|
178
|
+
ctx.textAlign = "right";
|
|
179
|
+
textX_1 = drawX + width - TEXT_PADDING;
|
|
180
|
+
textMaxWidth = width - TEXT_PADDING * 2;
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
ctx.textAlign = "center";
|
|
184
|
+
textX_1 = drawX + width / 2;
|
|
185
|
+
textMaxWidth = width - TEXT_PADDING * 2;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (column.wrap) {
|
|
189
|
+
var lines = wrapText(ctx, titleText, textMaxWidth);
|
|
190
|
+
var lineHeight_1 = FONT_SIZE + 5;
|
|
191
|
+
var startY_1 = textY - ((lines.length - 1) * lineHeight_1) / 2;
|
|
192
|
+
lines.forEach(function (line, idx) {
|
|
193
|
+
var lineY = startY_1 + idx * lineHeight_1;
|
|
194
|
+
ctx.fillText(line, textX_1, lineY);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
var truncatedText = truncateText(ctx, titleText, textMaxWidth);
|
|
199
|
+
ctx.fillText(truncatedText, textX_1, textY);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// 绘制筛选图�?
|
|
203
|
+
if (iconArea.hasFilter) {
|
|
204
|
+
var iconX = drawX + width - 10;
|
|
205
|
+
var hasFilterValue = state.filters[column.key] && state.filters[column.key].length > 0;
|
|
206
|
+
drawFilterIcon(ctx, iconX, textY, hasFilterValue);
|
|
207
|
+
}
|
|
208
|
+
// 绘制排序图标
|
|
209
|
+
if (iconArea.hasOrder) {
|
|
210
|
+
var iconX = drawX + width - (iconArea.hasFilter ? 24 : 10);
|
|
211
|
+
drawSortIcon(ctx, iconX, textY, column.key === state.sortField ? state.sortOrder : null);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
ctx.textAlign = "left";
|
|
215
|
+
ctx.restore();
|
|
216
|
+
// 绘制表头列之间的边框
|
|
217
|
+
if (bordered) {
|
|
218
|
+
ctx.strokeStyle = COLORS.border;
|
|
219
|
+
ctx.lineWidth = 2;
|
|
220
|
+
ctx.beginPath();
|
|
221
|
+
ctx.moveTo(drawX + width, 0);
|
|
222
|
+
ctx.lineTo(drawX + width, headerHeight);
|
|
223
|
+
ctx.stroke();
|
|
224
|
+
}
|
|
225
|
+
// 绘制列宽调整手柄
|
|
226
|
+
if (column.key !== "__selection__" && resizeState) {
|
|
227
|
+
var isHover = resizeState.hoverResizeColumnIndex === index;
|
|
228
|
+
var isResizing = resizeState.resizingColumnIndex === index;
|
|
229
|
+
if (isHover || isResizing) {
|
|
230
|
+
var handleX = drawX + width - RESIZE_HANDLE_WIDTH / 2;
|
|
231
|
+
ctx.fillStyle = isResizing ? "#1890ff" : "rgba(24, 144, 255, 0.3)";
|
|
232
|
+
ctx.fillRect(handleX, 0, RESIZE_HANDLE_WIDTH, headerHeight);
|
|
233
|
+
if (isResizing) {
|
|
234
|
+
ctx.strokeStyle = "#1890ff";
|
|
235
|
+
ctx.lineWidth = 1;
|
|
236
|
+
ctx.setLineDash([4, 4]);
|
|
237
|
+
ctx.beginPath();
|
|
238
|
+
ctx.moveTo(drawX + width, 0);
|
|
239
|
+
ctx.lineTo(drawX + width, displayHeight);
|
|
240
|
+
ctx.stroke();
|
|
241
|
+
ctx.setLineDash([]);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* 渲染多层表头单元�?
|
|
248
|
+
*/
|
|
249
|
+
HeaderRenderer.prototype.renderMultiHeaderCell = function (headerCell, y, displayWidth, currentDepth, totalCellHeight, onlyFixed) {
|
|
250
|
+
if (onlyFixed === void 0) { onlyFixed = false; }
|
|
251
|
+
if (!this.context)
|
|
252
|
+
return;
|
|
253
|
+
var _a = this.context, ctx = _a.ctx, scrollState = _a.scrollState, bordered = _a.bordered, state = _a.state, processedDataSource = _a.processedDataSource, getRowKey = _a.getRowKey, rowSelection = _a.rowSelection, columnRenderInfos = _a.columnRenderInfos, columns = _a.columns, getColumnWidth = _a.getColumnWidth, headerAlign = _a.headerAlign;
|
|
254
|
+
var column = headerCell.column, colSpan = headerCell.colSpan, rowSpan = headerCell.rowSpan, colIndex = headerCell.colIndex;
|
|
255
|
+
// 计算x位置和宽�?
|
|
256
|
+
var x = 0;
|
|
257
|
+
var width = 0;
|
|
258
|
+
var isFixed = false;
|
|
259
|
+
var fixedLeft = 0;
|
|
260
|
+
var leafColumns = getLeafColumns(columns);
|
|
261
|
+
for (var i = 0; i < leafColumns.length; i++) {
|
|
262
|
+
var leafInfo = columnRenderInfos[i];
|
|
263
|
+
if (i < colIndex) {
|
|
264
|
+
x += getColumnWidth ? getColumnWidth(i) : leafInfo.width;
|
|
265
|
+
}
|
|
266
|
+
else if (i < colIndex + colSpan) {
|
|
267
|
+
width += getColumnWidth ? getColumnWidth(i) : leafInfo.width;
|
|
268
|
+
if (leafInfo.fixed) {
|
|
269
|
+
isFixed = true;
|
|
270
|
+
if (i === colIndex) {
|
|
271
|
+
fixedLeft = leafInfo.fixedLeft;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// 根据 onlyFixed 参数过滤
|
|
277
|
+
if (onlyFixed && !isFixed)
|
|
278
|
+
return;
|
|
279
|
+
if (!onlyFixed && isFixed)
|
|
280
|
+
return;
|
|
281
|
+
var drawX = isFixed ? fixedLeft : x - scrollState.scrollLeft;
|
|
282
|
+
// 跳过不在可视区域的列
|
|
283
|
+
if (!isFixed && (drawX + width < 0 || drawX > displayWidth)) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
// 绘制单元格背�?
|
|
287
|
+
ctx.fillStyle = COLORS.headerBg;
|
|
288
|
+
ctx.fillRect(drawX, y, width, totalCellHeight);
|
|
289
|
+
// 绘制边框
|
|
290
|
+
if (bordered) {
|
|
291
|
+
ctx.strokeStyle = COLORS.border;
|
|
292
|
+
ctx.lineWidth = 1;
|
|
293
|
+
ctx.strokeRect(drawX, y, width, totalCellHeight);
|
|
294
|
+
}
|
|
295
|
+
var maxDepth = getMaxDepth(columns);
|
|
296
|
+
var isLastLevel = currentDepth + rowSpan === maxDepth;
|
|
297
|
+
var isSpecialColumn = column.key === "__selection__" || column.key === "__index__";
|
|
298
|
+
var textY = y + totalCellHeight / 2;
|
|
299
|
+
// 绘制选择�?
|
|
300
|
+
if (column.key === "__selection__" && currentDepth === 0) {
|
|
301
|
+
var selectionState = calculateSelectionState(processedDataSource, state.selectedRowKeys, getRowKey, rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.getCheckboxProps);
|
|
302
|
+
var checkboxX = drawX + width / 2;
|
|
303
|
+
drawCheckbox(ctx, checkboxX, textY, selectionState.isAllSelected, false, selectionState.isIndeterminate);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
// 绘制文本
|
|
307
|
+
ctx.fillStyle = COLORS.text;
|
|
308
|
+
ctx.font = "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
|
|
309
|
+
ctx.textBaseline = "middle";
|
|
310
|
+
if (!isValidElement(column.title)) {
|
|
311
|
+
var titleText = String(column.title || "");
|
|
312
|
+
var shouldShowIcons = isLastLevel && !isSpecialColumn;
|
|
313
|
+
var iconArea = shouldShowIcons
|
|
314
|
+
? calculateIconArea(column, width)
|
|
315
|
+
: { hasOrder: false, hasFilter: false, iconsWidth: 0 };
|
|
316
|
+
var columnHeaderAlign = column.headerAlign || headerAlign;
|
|
317
|
+
if (isLastLevel && iconArea.iconsWidth > 0) {
|
|
318
|
+
var textX_2;
|
|
319
|
+
var textMaxWidth = void 0;
|
|
320
|
+
if (columnHeaderAlign === "right") {
|
|
321
|
+
ctx.textAlign = "right";
|
|
322
|
+
textX_2 = drawX + width - TEXT_PADDING - iconArea.iconsWidth;
|
|
323
|
+
textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
|
|
324
|
+
}
|
|
325
|
+
else if (columnHeaderAlign === "center") {
|
|
326
|
+
ctx.textAlign = "center";
|
|
327
|
+
textX_2 = drawX + (width - iconArea.iconsWidth) / 2;
|
|
328
|
+
textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
ctx.textAlign = "left";
|
|
332
|
+
textX_2 = drawX + TEXT_PADDING;
|
|
333
|
+
textMaxWidth = width - TEXT_PADDING - iconArea.iconsWidth;
|
|
334
|
+
}
|
|
335
|
+
if (column.wrap) {
|
|
336
|
+
var lines = wrapText(ctx, titleText, textMaxWidth);
|
|
337
|
+
var lineHeight_2 = FONT_SIZE + 5;
|
|
338
|
+
var startY_2 = textY - ((lines.length - 1) * lineHeight_2) / 2;
|
|
339
|
+
lines.forEach(function (line, idx) {
|
|
340
|
+
var lineY = startY_2 + idx * lineHeight_2;
|
|
341
|
+
ctx.fillText(line, textX_2, lineY);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
var truncated = truncateText(ctx, titleText, textMaxWidth);
|
|
346
|
+
ctx.fillText(truncated, textX_2, textY);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
var textX_3;
|
|
351
|
+
if (columnHeaderAlign === "left") {
|
|
352
|
+
ctx.textAlign = "left";
|
|
353
|
+
textX_3 = drawX + TEXT_PADDING;
|
|
354
|
+
}
|
|
355
|
+
else if (columnHeaderAlign === "right") {
|
|
356
|
+
ctx.textAlign = "right";
|
|
357
|
+
textX_3 = drawX + width - TEXT_PADDING;
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
ctx.textAlign = "center";
|
|
361
|
+
textX_3 = drawX + width / 2;
|
|
362
|
+
}
|
|
363
|
+
if (column.wrap) {
|
|
364
|
+
var lines = wrapText(ctx, titleText, width - TEXT_PADDING * 2);
|
|
365
|
+
var lineHeight_3 = FONT_SIZE + 5;
|
|
366
|
+
var startY_3 = textY - ((lines.length - 1) * lineHeight_3) / 2;
|
|
367
|
+
lines.forEach(function (line, idx) {
|
|
368
|
+
var lineY = startY_3 + idx * lineHeight_3;
|
|
369
|
+
ctx.fillText(line, textX_3, lineY);
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
var truncated = truncateText(ctx, titleText, width - TEXT_PADDING * 2);
|
|
374
|
+
ctx.fillText(truncated, textX_3, textY);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// 绘制筛选图�?
|
|
378
|
+
if (iconArea.hasFilter) {
|
|
379
|
+
var iconX = drawX + width - 10;
|
|
380
|
+
var hasFilterValue = state.filters[column.key] && state.filters[column.key].length > 0;
|
|
381
|
+
drawFilterIcon(ctx, iconX, textY, hasFilterValue);
|
|
382
|
+
}
|
|
383
|
+
// 绘制排序图标
|
|
384
|
+
if (iconArea.hasOrder) {
|
|
385
|
+
var iconX = drawX + width - (iconArea.hasFilter ? 24 : 10);
|
|
386
|
+
drawSortIcon(ctx, iconX, textY, column.key === state.sortField ? state.sortOrder : null);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
ctx.textAlign = "left";
|
|
391
|
+
};
|
|
392
|
+
return HeaderRenderer;
|
|
393
|
+
}());
|
|
394
|
+
|
|
395
|
+
export { HeaderRenderer };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { COLORS, SCROLLBAR_SIZE, SCROLLBAR_PADDING } from '../../utils/constants.js';
|
|
2
|
+
import 'zmdms-utils';
|
|
3
|
+
import 'dayjs';
|
|
4
|
+
import '../../../_virtual/_tslib.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 滚动条渲染器
|
|
8
|
+
* 负责渲染垂直和水平滚动条
|
|
9
|
+
*/
|
|
10
|
+
var ScrollbarRenderer = /** @class */ (function () {
|
|
11
|
+
function ScrollbarRenderer() {
|
|
12
|
+
this.context = null;
|
|
13
|
+
}
|
|
14
|
+
ScrollbarRenderer.prototype.setContext = function (context) {
|
|
15
|
+
this.context = context;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* 渲染滚动�?
|
|
19
|
+
*/
|
|
20
|
+
ScrollbarRenderer.prototype.render = function () {
|
|
21
|
+
if (!this.context) {
|
|
22
|
+
throw new Error("ScrollbarRenderer: Context not set");
|
|
23
|
+
}
|
|
24
|
+
this.renderVerticalScrollbar();
|
|
25
|
+
this.renderHorizontalScrollbar();
|
|
26
|
+
this.renderScrollbarCorner();
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* 渲染垂直滚动�?
|
|
30
|
+
*/
|
|
31
|
+
ScrollbarRenderer.prototype.renderVerticalScrollbar = function () {
|
|
32
|
+
if (!this.context || !this.context.needVerticalScrollbar)
|
|
33
|
+
return;
|
|
34
|
+
var _a = this.context, ctx = _a.ctx, displayWidth = _a.displayWidth, displayHeight = _a.displayHeight, headerHeight = _a.headerHeight, needHorizontalScrollbar = _a.needHorizontalScrollbar, scrollState = _a.scrollState, verticalScrollbarTop = _a.verticalScrollbarTop, verticalScrollbarHeight = _a.verticalScrollbarHeight;
|
|
35
|
+
var scrollbarX = displayWidth - SCROLLBAR_SIZE;
|
|
36
|
+
var scrollbarY = headerHeight;
|
|
37
|
+
var scrollbarHeight = needHorizontalScrollbar
|
|
38
|
+
? displayHeight - SCROLLBAR_SIZE - headerHeight
|
|
39
|
+
: displayHeight - headerHeight;
|
|
40
|
+
// 滚动条轨�?
|
|
41
|
+
ctx.fillStyle = COLORS.scrollbarTrack;
|
|
42
|
+
ctx.fillRect(scrollbarX, scrollbarY, SCROLLBAR_SIZE, scrollbarHeight);
|
|
43
|
+
// 滚动条滑�?
|
|
44
|
+
ctx.fillStyle = scrollState.isDraggingVertical
|
|
45
|
+
? COLORS.scrollbarThumbActive
|
|
46
|
+
: COLORS.scrollbarThumb;
|
|
47
|
+
ctx.fillRect(scrollbarX + SCROLLBAR_PADDING, verticalScrollbarTop + headerHeight + SCROLLBAR_PADDING, SCROLLBAR_SIZE - SCROLLBAR_PADDING * 2, verticalScrollbarHeight - SCROLLBAR_PADDING * 2);
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* 渲染水平滚动�?
|
|
51
|
+
*/
|
|
52
|
+
ScrollbarRenderer.prototype.renderHorizontalScrollbar = function () {
|
|
53
|
+
if (!this.context || !this.context.needHorizontalScrollbar)
|
|
54
|
+
return;
|
|
55
|
+
var _a = this.context, ctx = _a.ctx, displayWidth = _a.displayWidth, displayHeight = _a.displayHeight, needVerticalScrollbar = _a.needVerticalScrollbar, scrollState = _a.scrollState, horizontalScrollbarLeft = _a.horizontalScrollbarLeft, horizontalScrollbarWidth = _a.horizontalScrollbarWidth;
|
|
56
|
+
var scrollbarX = 0;
|
|
57
|
+
var scrollbarY = displayHeight - SCROLLBAR_SIZE;
|
|
58
|
+
var scrollbarWidth = needVerticalScrollbar
|
|
59
|
+
? displayWidth - SCROLLBAR_SIZE
|
|
60
|
+
: displayWidth;
|
|
61
|
+
// 滚动条轨�?
|
|
62
|
+
ctx.fillStyle = COLORS.scrollbarTrack;
|
|
63
|
+
ctx.fillRect(scrollbarX, scrollbarY, scrollbarWidth, SCROLLBAR_SIZE);
|
|
64
|
+
// 滚动条滑�?
|
|
65
|
+
ctx.fillStyle = scrollState.isDraggingHorizontal
|
|
66
|
+
? COLORS.scrollbarThumbActive
|
|
67
|
+
: COLORS.scrollbarThumb;
|
|
68
|
+
ctx.fillRect(horizontalScrollbarLeft + SCROLLBAR_PADDING, scrollbarY + SCROLLBAR_PADDING, horizontalScrollbarWidth - SCROLLBAR_PADDING * 2, SCROLLBAR_SIZE - SCROLLBAR_PADDING * 2);
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* 渲染滚动条交叉处
|
|
72
|
+
*/
|
|
73
|
+
ScrollbarRenderer.prototype.renderScrollbarCorner = function () {
|
|
74
|
+
if (!this.context)
|
|
75
|
+
return;
|
|
76
|
+
var _a = this.context, ctx = _a.ctx, displayWidth = _a.displayWidth, displayHeight = _a.displayHeight, needVerticalScrollbar = _a.needVerticalScrollbar, needHorizontalScrollbar = _a.needHorizontalScrollbar;
|
|
77
|
+
if (needVerticalScrollbar && needHorizontalScrollbar) {
|
|
78
|
+
ctx.fillStyle = COLORS.scrollbarTrack;
|
|
79
|
+
ctx.fillRect(displayWidth - SCROLLBAR_SIZE, displayHeight - SCROLLBAR_SIZE, SCROLLBAR_SIZE, SCROLLBAR_SIZE);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return ScrollbarRenderer;
|
|
83
|
+
}());
|
|
84
|
+
|
|
85
|
+
export { ScrollbarRenderer };
|