zmdms-webui 2.6.2 → 2.6.3
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 +63 -21
- 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 +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { COLORS, FONT_WEIGHT, FONT_SIZE, FONT_FAMILY, SCROLLBAR_SIZE, TEXT_PADDING } from '../../utils/constants.js';
|
|
2
|
+
import { drawCheckbox, wrapText, truncateText } from '../../utils/canvasDrawHelpers.js';
|
|
3
|
+
import { extractCellText } from '../../utils/cellHelpers.js';
|
|
4
|
+
import { formatCellValue } from '../../utils/formatHelpers.js';
|
|
5
|
+
import '../../../_virtual/_tslib.js';
|
|
6
|
+
import { setupCellClip, drawCellBackground, shouldRenderInCanvas } from '../../utils/renderHelpers.js';
|
|
7
|
+
import { IS_SUMMARY } from '../../../table/constant.js';
|
|
8
|
+
import { BadgeRenderer } from './BadgeRenderer.js';
|
|
9
|
+
import { ExpandIconRenderer } from './ExpandIconRenderer.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 数据行渲染器
|
|
13
|
+
* 负责渲染表格的数据行
|
|
14
|
+
*/
|
|
15
|
+
var DataRowRenderer = /** @class */ (function () {
|
|
16
|
+
function DataRowRenderer() {
|
|
17
|
+
this.context = null;
|
|
18
|
+
this.badgeRenderer = new BadgeRenderer();
|
|
19
|
+
this.expandIconRenderer = new ExpandIconRenderer();
|
|
20
|
+
}
|
|
21
|
+
DataRowRenderer.prototype.setContext = function (context) {
|
|
22
|
+
this.context = context;
|
|
23
|
+
this.badgeRenderer.setContext(context);
|
|
24
|
+
this.expandIconRenderer.setContext(context);
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* 渲染单行数据
|
|
28
|
+
*/
|
|
29
|
+
DataRowRenderer.prototype.renderRow = function (rowIndex, onlyFixed) {
|
|
30
|
+
var _this = this;
|
|
31
|
+
if (onlyFixed === void 0) { onlyFixed = false; }
|
|
32
|
+
if (!this.context) {
|
|
33
|
+
throw new Error("DataRowRenderer: Context not set");
|
|
34
|
+
}
|
|
35
|
+
var _a = this.context, processedDataSource = _a.processedDataSource, rowHeight = _a.rowHeight, headerHeight = _a.headerHeight, scrollState = _a.scrollState, state = _a.state, getRowKey = _a.getRowKey, displayHeight = _a.displayHeight, needHorizontalScrollbar = _a.needHorizontalScrollbar, fixedRowsCount = _a.fixedRowsCount, fixedRowsConfig = _a.fixedRowsConfig, summaryFixed = _a.summaryFixed, hasSummaryRow = _a.hasSummaryRow, mergeCellMap = _a.mergeCellMap, columnRenderInfos = _a.columnRenderInfos;
|
|
36
|
+
var record = processedDataSource[rowIndex];
|
|
37
|
+
if (!record)
|
|
38
|
+
return;
|
|
39
|
+
// 计算固定行数�?
|
|
40
|
+
var fixedTopCount = fixedRowsCount || (fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.topCount) || 0;
|
|
41
|
+
// 计算Y坐标
|
|
42
|
+
var y = headerHeight +
|
|
43
|
+
fixedTopCount * rowHeight +
|
|
44
|
+
(rowIndex - fixedTopCount) * rowHeight -
|
|
45
|
+
scrollState.scrollTop;
|
|
46
|
+
// 计算实际可用的渲染区域高�?
|
|
47
|
+
var fixedBottomRowsCount = (fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.bottomCount) || 0;
|
|
48
|
+
var fixedBottomHeight = fixedBottomRowsCount * rowHeight;
|
|
49
|
+
var fixedSummaryHeight = summaryFixed && hasSummaryRow ? rowHeight : 0;
|
|
50
|
+
var effectiveHeight = displayHeight -
|
|
51
|
+
(needHorizontalScrollbar ? SCROLLBAR_SIZE : 0) -
|
|
52
|
+
fixedBottomHeight -
|
|
53
|
+
fixedSummaryHeight;
|
|
54
|
+
// 提前检查这一行是否有合并单元格,找出最大的rowSpan
|
|
55
|
+
var maxRowSpanInRow = 1;
|
|
56
|
+
if (mergeCellMap) {
|
|
57
|
+
columnRenderInfos.forEach(function (_, colIndex) {
|
|
58
|
+
var mergeCellKey = "".concat(rowIndex, "-").concat(colIndex);
|
|
59
|
+
var mergeInfo = mergeCellMap.get(mergeCellKey);
|
|
60
|
+
if (mergeInfo &&
|
|
61
|
+
!mergeInfo.skip &&
|
|
62
|
+
mergeInfo.rowSpan > maxRowSpanInRow) {
|
|
63
|
+
maxRowSpanInRow = mergeInfo.rowSpan;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
// 计算这一行的实际高度(考虑合并单元格)
|
|
68
|
+
var actualRowHeight = rowHeight * maxRowSpanInRow;
|
|
69
|
+
// 跳过不在可视区域的行
|
|
70
|
+
if (y + actualRowHeight < headerHeight || y >= effectiveHeight) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
var recordKey = getRowKey(record, rowIndex);
|
|
74
|
+
var isSelected = state.selectedRowKeys.includes(recordKey);
|
|
75
|
+
var isHover = state.hoverRowIndex === rowIndex;
|
|
76
|
+
// 计算fixed列的右边�?
|
|
77
|
+
var fixedColumnsRightEdge = 0;
|
|
78
|
+
if (!onlyFixed) {
|
|
79
|
+
columnRenderInfos.forEach(function (info) {
|
|
80
|
+
if (info.fixed) {
|
|
81
|
+
var actualWidth = _this.context.getColumnWidth
|
|
82
|
+
? _this.context.getColumnWidth(columnRenderInfos.indexOf(info))
|
|
83
|
+
: info.width;
|
|
84
|
+
var rightEdge = info.fixedLeft + actualWidth;
|
|
85
|
+
fixedColumnsRightEdge = Math.max(fixedColumnsRightEdge, rightEdge);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// 绘制单元�?
|
|
90
|
+
columnRenderInfos.forEach(function (info, colIndex) {
|
|
91
|
+
_this.renderCell(info, colIndex, rowIndex, record, y, isSelected, isHover, fixedColumnsRightEdge, effectiveHeight, onlyFixed);
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* 渲染单个单元�?
|
|
96
|
+
*/
|
|
97
|
+
DataRowRenderer.prototype.renderCell = function (info, colIndex, rowIndex, record, y, isSelected, isHover, fixedColumnsRightEdge, effectiveHeight, onlyFixed) {
|
|
98
|
+
if (!this.context)
|
|
99
|
+
return;
|
|
100
|
+
var _a = this.context, ctx = _a.ctx, scrollState = _a.scrollState, displayWidth = _a.displayWidth, headerHeight = _a.headerHeight, rowHeight = _a.rowHeight, mergeCellMap = _a.mergeCellMap, getColumnWidth = _a.getColumnWidth;
|
|
101
|
+
var column = info.column, x = info.x, fixed = info.fixed, fixedLeft = info.fixedLeft;
|
|
102
|
+
// 根据 onlyFixed 参数过滤
|
|
103
|
+
if (onlyFixed && !fixed)
|
|
104
|
+
return;
|
|
105
|
+
if (!onlyFixed && fixed)
|
|
106
|
+
return;
|
|
107
|
+
// 检查合并单元格
|
|
108
|
+
var mergeCellKey = "".concat(rowIndex, "-").concat(colIndex);
|
|
109
|
+
var mergeInfo = mergeCellMap === null || mergeCellMap === void 0 ? void 0 : mergeCellMap.get(mergeCellKey);
|
|
110
|
+
// 如果是被合并的单元格,跳过渲�?
|
|
111
|
+
if (mergeInfo && mergeInfo.skip) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
var width = getColumnWidth ? getColumnWidth(colIndex) : info.width;
|
|
115
|
+
var drawX = fixed ? fixedLeft : x - scrollState.scrollLeft;
|
|
116
|
+
// 跳过不在可视区域的列
|
|
117
|
+
if (!fixed && (drawX + width < 0 || drawX > displayWidth)) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// 对于非fixed列,检查是否被fixed列遮�?
|
|
121
|
+
if (!fixed && fixedColumnsRightEdge > 0 && drawX < fixedColumnsRightEdge) {
|
|
122
|
+
if (drawX + width <= fixedColumnsRightEdge) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// 计算单元格高度(考虑合并�?
|
|
127
|
+
var cellHeight = mergeInfo && mergeInfo.rowSpan > 1
|
|
128
|
+
? rowHeight * mergeInfo.rowSpan
|
|
129
|
+
: rowHeight;
|
|
130
|
+
ctx.save();
|
|
131
|
+
// 设置裁剪区域
|
|
132
|
+
var _b = setupCellClip({
|
|
133
|
+
ctx: ctx,
|
|
134
|
+
drawX: drawX,
|
|
135
|
+
y: y,
|
|
136
|
+
width: width,
|
|
137
|
+
cellHeight: cellHeight,
|
|
138
|
+
headerHeight: headerHeight,
|
|
139
|
+
effectiveHeight: effectiveHeight,
|
|
140
|
+
fixedColumnsRightEdge: !fixed ? fixedColumnsRightEdge : undefined,
|
|
141
|
+
isFixed: fixed,
|
|
142
|
+
}), clipX = _b.clipX, clipY = _b.clipY, clipWidth = _b.clipWidth, clipHeight = _b.clipHeight;
|
|
143
|
+
// 绘制单元格背�?
|
|
144
|
+
var isSummaryRow = record[IS_SUMMARY];
|
|
145
|
+
drawCellBackground({
|
|
146
|
+
ctx: ctx,
|
|
147
|
+
clipX: clipX,
|
|
148
|
+
clipY: clipY,
|
|
149
|
+
clipWidth: clipWidth,
|
|
150
|
+
clipHeight: clipHeight,
|
|
151
|
+
isSelected: isSelected,
|
|
152
|
+
isHover: isHover,
|
|
153
|
+
isSummaryRow: isSummaryRow,
|
|
154
|
+
isStriped: this.context.striped,
|
|
155
|
+
rowIndex: rowIndex,
|
|
156
|
+
});
|
|
157
|
+
// 渲染单元格内�?
|
|
158
|
+
this.renderCellContent(column, colIndex, rowIndex, record, drawX, y, width, cellHeight, isSummaryRow);
|
|
159
|
+
ctx.restore();
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* 渲染单元格内�?
|
|
163
|
+
*/
|
|
164
|
+
DataRowRenderer.prototype.renderCellContent = function (column, colIndex, rowIndex, record, drawX, y, width, cellHeight, isSummaryRow) {
|
|
165
|
+
if (!this.context)
|
|
166
|
+
return;
|
|
167
|
+
if (column.key === "__selection__") {
|
|
168
|
+
this.renderSelectionCell(record, rowIndex, column, drawX, y, width, cellHeight, isSummaryRow);
|
|
169
|
+
}
|
|
170
|
+
else if (column.key === "__index__") {
|
|
171
|
+
// 处理序号列
|
|
172
|
+
this.renderIndexCell(rowIndex, drawX, y, width, cellHeight);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
this.renderDataCell(column, colIndex, rowIndex, record, drawX, y, width, cellHeight, isSummaryRow);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* 渲染序号单元格
|
|
180
|
+
*/
|
|
181
|
+
DataRowRenderer.prototype.renderIndexCell = function (rowIndex, drawX, y, width, cellHeight) {
|
|
182
|
+
if (!this.context)
|
|
183
|
+
return;
|
|
184
|
+
var _a = this.context, ctx = _a.ctx, flattenedData = _a.flattenedData, expandable = _a.expandable;
|
|
185
|
+
var indexText = String(rowIndex + 1); // 默认使用行索引
|
|
186
|
+
if (flattenedData && flattenedData[rowIndex]) {
|
|
187
|
+
var flattenedRow = flattenedData[rowIndex];
|
|
188
|
+
// 使用 indexInParent 作为显示序号
|
|
189
|
+
indexText = String(flattenedRow.indexInParent);
|
|
190
|
+
}
|
|
191
|
+
// 检查是否需要在序号列中渲染展开图标
|
|
192
|
+
var expandIconWidth = 0;
|
|
193
|
+
var expandIconColumnIndex = (expandable === null || expandable === void 0 ? void 0 : expandable.expandIconColumnIndex) || 0;
|
|
194
|
+
// 如果展开图标列索引是0(第一列),且当前是序号列,则需要渲染展开图标
|
|
195
|
+
if (expandable && flattenedData && expandIconColumnIndex === 0) {
|
|
196
|
+
var flattenedRow = flattenedData[rowIndex];
|
|
197
|
+
if (flattenedRow) {
|
|
198
|
+
var level = flattenedRow.level, hasChildren = flattenedRow.hasChildren;
|
|
199
|
+
// 使用 ExpandIconRenderer 渲染展开图标(colIndex传0因为这是第一列)
|
|
200
|
+
this.expandIconRenderer.render(0, rowIndex, drawX, y, cellHeight);
|
|
201
|
+
// 计算展开图标占用的宽度(包括图标和5px间距)
|
|
202
|
+
if (hasChildren) {
|
|
203
|
+
// 基础边距 + 层级缩进 + 图标宽度 + 5px间距
|
|
204
|
+
expandIconWidth = 8 + level * 20 + 12 + 5;
|
|
205
|
+
}
|
|
206
|
+
else if (level > 0) {
|
|
207
|
+
// 子节点但没有子级,也需要缩进对齐
|
|
208
|
+
expandIconWidth = 8 + level * 20 + 5;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// 绘制序号,位置向右偏移以避开展开图标
|
|
213
|
+
ctx.fillStyle = COLORS.text;
|
|
214
|
+
ctx.font = "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
|
|
215
|
+
ctx.textBaseline = "middle";
|
|
216
|
+
ctx.textAlign = "left";
|
|
217
|
+
var textX = drawX + TEXT_PADDING + expandIconWidth;
|
|
218
|
+
var textY = y + cellHeight / 2;
|
|
219
|
+
ctx.fillText(indexText, textX, textY);
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* 渲染选择框单元格
|
|
223
|
+
*/
|
|
224
|
+
DataRowRenderer.prototype.renderSelectionCell = function (record, rowIndex, column, drawX, y, width, cellHeight, isSummaryRow) {
|
|
225
|
+
var _a;
|
|
226
|
+
if (!this.context)
|
|
227
|
+
return;
|
|
228
|
+
var _b = this.context, ctx = _b.ctx, state = _b.state, rowSelection = _b.rowSelection, getRowKey = _b.getRowKey;
|
|
229
|
+
if (!isSummaryRow) {
|
|
230
|
+
var checkboxProps = ((_a = rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.getCheckboxProps) === null || _a === void 0 ? void 0 : _a.call(rowSelection, record)) || {};
|
|
231
|
+
var disabled = checkboxProps.disabled || false;
|
|
232
|
+
var recordKey = getRowKey(record, rowIndex);
|
|
233
|
+
var isSelected = state.selectedRowKeys.includes(recordKey);
|
|
234
|
+
drawCheckbox(ctx, drawX + width / 2, y + cellHeight / 2, isSelected, disabled, false);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// 合计行选择框列显示文本
|
|
238
|
+
var dataIndex = column.dataIndex || column.key;
|
|
239
|
+
var cellValue = record[dataIndex];
|
|
240
|
+
var cellText = formatCellValue(cellValue, column, true);
|
|
241
|
+
if (cellText) {
|
|
242
|
+
ctx.fillStyle = COLORS.text;
|
|
243
|
+
ctx.font = "bold ".concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
|
|
244
|
+
ctx.textBaseline = "middle";
|
|
245
|
+
ctx.textAlign = "center";
|
|
246
|
+
var textX = drawX + width / 2;
|
|
247
|
+
var textY = y + cellHeight / 2;
|
|
248
|
+
ctx.fillText(cellText, textX, textY);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* 渲染数据单元�?
|
|
254
|
+
*/
|
|
255
|
+
DataRowRenderer.prototype.renderDataCell = function (column, colIndex, rowIndex, record, drawX, y, width, cellHeight, isSummaryRow) {
|
|
256
|
+
if (!this.context)
|
|
257
|
+
return;
|
|
258
|
+
var ctx = this.context.ctx;
|
|
259
|
+
var dataIndex = column.dataIndex || column.key;
|
|
260
|
+
var cellValue = record[dataIndex];
|
|
261
|
+
// 检查是否应该在 Canvas 中渲�?
|
|
262
|
+
if (!shouldRenderInCanvas(column.render, cellValue, record, rowIndex, isSummaryRow)) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
// 应用格式�?
|
|
266
|
+
var cellText;
|
|
267
|
+
if (isSummaryRow && column.key !== "__index__") {
|
|
268
|
+
cellText = formatCellValue(cellValue, column);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
cellText = extractCellText({
|
|
272
|
+
cellValue: cellValue,
|
|
273
|
+
record: record,
|
|
274
|
+
rowIndex: rowIndex,
|
|
275
|
+
renderFn: column.render,
|
|
276
|
+
});
|
|
277
|
+
if (!column.render) {
|
|
278
|
+
cellText = formatCellValue(cellValue, column);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// 绘制文本
|
|
282
|
+
ctx.fillStyle = COLORS.text;
|
|
283
|
+
ctx.font = isSummaryRow
|
|
284
|
+
? "bold ".concat(FONT_SIZE, "px ").concat(FONT_FAMILY)
|
|
285
|
+
: "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
|
|
286
|
+
ctx.textBaseline = "middle";
|
|
287
|
+
var align = column.align || "left";
|
|
288
|
+
var textX = drawX + TEXT_PADDING;
|
|
289
|
+
if (align === "center") {
|
|
290
|
+
ctx.textAlign = "center";
|
|
291
|
+
textX = drawX + width / 2;
|
|
292
|
+
}
|
|
293
|
+
else if (align === "right") {
|
|
294
|
+
ctx.textAlign = "right";
|
|
295
|
+
textX = drawX + width - TEXT_PADDING;
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
ctx.textAlign = "left";
|
|
299
|
+
}
|
|
300
|
+
// 绘制展开图标并获取文本缩进偏移量
|
|
301
|
+
var indentOffset = this.expandIconRenderer.render(colIndex, rowIndex, drawX, y, cellHeight);
|
|
302
|
+
textX += indentOffset;
|
|
303
|
+
// 处理文本显示
|
|
304
|
+
this.renderTextContent(ctx, cellText, textX, y, width, cellHeight, column.ellipsis !== false, column.wrap === true);
|
|
305
|
+
// 绘制角标
|
|
306
|
+
if (column.badge && !isSummaryRow) {
|
|
307
|
+
var badgeProps = typeof column.badge === "function"
|
|
308
|
+
? column.badge(record)
|
|
309
|
+
: column.badge;
|
|
310
|
+
if (badgeProps) {
|
|
311
|
+
this.badgeRenderer.render(badgeProps, drawX, y, width, cellHeight);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* 渲染文本内容(处�?ellipsis/wrap�?
|
|
317
|
+
*/
|
|
318
|
+
DataRowRenderer.prototype.renderTextContent = function (ctx, text, textX, y, width, cellHeight, ellipsis, wrap) {
|
|
319
|
+
var maxWidth = width - TEXT_PADDING * 2;
|
|
320
|
+
if (wrap) {
|
|
321
|
+
// 换行显示,最多显�?�?
|
|
322
|
+
var allLines = wrapText(ctx, text, maxWidth);
|
|
323
|
+
var maxLines = 2;
|
|
324
|
+
var lines = allLines.slice(0, maxLines);
|
|
325
|
+
// 如果超过2行,在第2行末尾强制添加省略号
|
|
326
|
+
if (allLines.length > maxLines && lines.length === maxLines) {
|
|
327
|
+
var lastLine = lines[maxLines - 1];
|
|
328
|
+
var ellipsisText = "...";
|
|
329
|
+
while (lastLine.length > 0 &&
|
|
330
|
+
ctx.measureText(lastLine + ellipsisText).width > maxWidth) {
|
|
331
|
+
lastLine = lastLine.slice(0, -1);
|
|
332
|
+
}
|
|
333
|
+
lines[maxLines - 1] = lastLine + ellipsisText;
|
|
334
|
+
}
|
|
335
|
+
var lineHeight_1 = FONT_SIZE + 5;
|
|
336
|
+
var totalHeight = lines.length * lineHeight_1;
|
|
337
|
+
var startY_1 = y + (cellHeight - totalHeight) / 2 + lineHeight_1 / 2;
|
|
338
|
+
lines.forEach(function (line, lineIndex) {
|
|
339
|
+
var lineY = startY_1 + lineIndex * lineHeight_1;
|
|
340
|
+
if (lineY >= y && lineY <= y + cellHeight) {
|
|
341
|
+
ctx.fillText(line, textX, lineY);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
else if (ellipsis) {
|
|
346
|
+
var textY = y + cellHeight / 2;
|
|
347
|
+
var truncatedText = truncateText(ctx, text, maxWidth);
|
|
348
|
+
ctx.fillText(truncatedText, textX, textY);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
var textY = y + cellHeight / 2;
|
|
352
|
+
ctx.fillText(text, textX, textY);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
return DataRowRenderer;
|
|
356
|
+
}());
|
|
357
|
+
|
|
358
|
+
export { DataRowRenderer };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { TEXT_PADDING } from '../../utils/constants.js';
|
|
2
|
+
import 'zmdms-utils';
|
|
3
|
+
import 'dayjs';
|
|
4
|
+
import '../../../_virtual/_tslib.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 展开图标渲染器
|
|
8
|
+
* 负责绘制树形表格的展开/收起图标
|
|
9
|
+
*/
|
|
10
|
+
var ExpandIconRenderer = /** @class */ (function () {
|
|
11
|
+
function ExpandIconRenderer() {
|
|
12
|
+
this.context = null;
|
|
13
|
+
}
|
|
14
|
+
ExpandIconRenderer.prototype.setContext = function (context) {
|
|
15
|
+
this.context = context;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* 渲染展开图标
|
|
19
|
+
* @param colIndex 当前列索引
|
|
20
|
+
* @param rowIndex 当前行索引
|
|
21
|
+
* @param drawX 绘制起始X坐标
|
|
22
|
+
* @param y 绘制起始Y坐标
|
|
23
|
+
* @param cellHeight 单元格高度
|
|
24
|
+
* @returns 文本缩进偏移量
|
|
25
|
+
*/
|
|
26
|
+
ExpandIconRenderer.prototype.render = function (colIndex, rowIndex, drawX, y, cellHeight) {
|
|
27
|
+
if (!this.context) {
|
|
28
|
+
throw new Error("ExpandIconRenderer: Context not set");
|
|
29
|
+
}
|
|
30
|
+
var _a = this.context, expandable = _a.expandable, flattenedData = _a.flattenedData;
|
|
31
|
+
// 检查是否启用展开功能
|
|
32
|
+
if (!expandable || !flattenedData) {
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
// 检查当前列是否是展开图标列
|
|
36
|
+
var expandIconColumnIndex = expandable.expandIconColumnIndex || 0;
|
|
37
|
+
if (colIndex !== expandIconColumnIndex) {
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
// 获取当前行的展开信息
|
|
41
|
+
var flattenedRow = flattenedData[rowIndex];
|
|
42
|
+
if (!flattenedRow) {
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
var level = flattenedRow.level, hasChildren = flattenedRow.hasChildren, isExpanded = flattenedRow.isExpanded;
|
|
46
|
+
// 计算图标位置(增加8px基础左边距)
|
|
47
|
+
var iconX = drawX + TEXT_PADDING + 8 + level * 20;
|
|
48
|
+
var iconY = y + cellHeight / 2;
|
|
49
|
+
// 绘制展开图标
|
|
50
|
+
this.drawExpandIcon(iconX, iconY, isExpanded, hasChildren);
|
|
51
|
+
// 计算文本缩进偏移量(加上基础边距)
|
|
52
|
+
if (level > 0 || hasChildren) {
|
|
53
|
+
return 8 + level * 20 + 20;
|
|
54
|
+
}
|
|
55
|
+
return 0;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* 绘制展开图标(+ / -)
|
|
59
|
+
*/
|
|
60
|
+
ExpandIconRenderer.prototype.drawExpandIcon = function (x, y, expanded, hasChildren) {
|
|
61
|
+
if (!this.context)
|
|
62
|
+
return;
|
|
63
|
+
var ctx = this.context.ctx;
|
|
64
|
+
// 没有子节点,不绘制图标
|
|
65
|
+
if (!hasChildren) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
var size = 16; // 图标大小
|
|
69
|
+
var half = size / 2;
|
|
70
|
+
// 绘制矩形背景
|
|
71
|
+
ctx.fillStyle = "#ffffff";
|
|
72
|
+
ctx.strokeStyle = "#dee9f6";
|
|
73
|
+
ctx.lineWidth = 1;
|
|
74
|
+
ctx.beginPath();
|
|
75
|
+
ctx.rect(x - half, y - half, size, size);
|
|
76
|
+
ctx.fill();
|
|
77
|
+
ctx.stroke();
|
|
78
|
+
// 绘制 + 或 - 符号
|
|
79
|
+
ctx.strokeStyle = "currentcolor";
|
|
80
|
+
ctx.lineWidth = 1;
|
|
81
|
+
// 水平线(总是绘制)
|
|
82
|
+
ctx.beginPath();
|
|
83
|
+
ctx.moveTo(x - 4, y);
|
|
84
|
+
ctx.lineTo(x + 4, y);
|
|
85
|
+
ctx.stroke();
|
|
86
|
+
// 垂直线(仅在收起状态时绘制,形成 + 号)
|
|
87
|
+
if (!expanded) {
|
|
88
|
+
ctx.beginPath();
|
|
89
|
+
ctx.moveTo(x, y - 4);
|
|
90
|
+
ctx.lineTo(x, y + 4);
|
|
91
|
+
ctx.stroke();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
return ExpandIconRenderer;
|
|
95
|
+
}());
|
|
96
|
+
|
|
97
|
+
export { ExpandIconRenderer };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import 'zmdms-utils';
|
|
2
|
+
import 'dayjs';
|
|
3
|
+
import '../../../_virtual/_tslib.js';
|
|
4
|
+
import { calculateFixedColumnsRightEdge } from '../../utils/renderHelpers.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 固定列效果渲染器
|
|
8
|
+
* 负责渲染固定列的阴影和边界线
|
|
9
|
+
*/
|
|
10
|
+
var FixedColumnRenderer = /** @class */ (function () {
|
|
11
|
+
function FixedColumnRenderer() {
|
|
12
|
+
this.context = null;
|
|
13
|
+
}
|
|
14
|
+
FixedColumnRenderer.prototype.setContext = function (context) {
|
|
15
|
+
this.context = context;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* 渲染固定列效�?
|
|
19
|
+
*/
|
|
20
|
+
FixedColumnRenderer.prototype.render = function () {
|
|
21
|
+
if (!this.context) {
|
|
22
|
+
throw new Error("FixedColumnRenderer: Context not set");
|
|
23
|
+
}
|
|
24
|
+
var _a = this.context, columnRenderInfos = _a.columnRenderInfos, getColumnWidth = _a.getColumnWidth, scrollState = _a.scrollState, displayWidth = _a.displayWidth;
|
|
25
|
+
var fixedColumns = columnRenderInfos.filter(function (info) { return info.fixed; });
|
|
26
|
+
if (fixedColumns.length === 0)
|
|
27
|
+
return;
|
|
28
|
+
// 计算固定列的实际右边�?
|
|
29
|
+
var fixedRightEdge = calculateFixedColumnsRightEdge(columnRenderInfos, getColumnWidth);
|
|
30
|
+
// 只在有横向滚动时显示阴影
|
|
31
|
+
if (scrollState.scrollLeft > 0 && fixedRightEdge < displayWidth) {
|
|
32
|
+
this.renderShadow(fixedRightEdge);
|
|
33
|
+
}
|
|
34
|
+
// 绘制边界�?
|
|
35
|
+
if (fixedRightEdge > 0 && fixedRightEdge < displayWidth) {
|
|
36
|
+
this.renderBorder(fixedRightEdge);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* 渲染阴影
|
|
41
|
+
*/
|
|
42
|
+
FixedColumnRenderer.prototype.renderShadow = function (fixedRightEdge) {
|
|
43
|
+
if (!this.context)
|
|
44
|
+
return;
|
|
45
|
+
var _a = this.context, ctx = _a.ctx, headerHeight = _a.headerHeight, displayHeight = _a.displayHeight;
|
|
46
|
+
var shadowWidth = 12;
|
|
47
|
+
var gradient = ctx.createLinearGradient(fixedRightEdge, 0, fixedRightEdge + shadowWidth, 0);
|
|
48
|
+
gradient.addColorStop(0, "rgba(0, 0, 0, 0.12)");
|
|
49
|
+
gradient.addColorStop(0.6, "rgba(0, 0, 0, 0.04)");
|
|
50
|
+
gradient.addColorStop(1, "rgba(0, 0, 0, 0)");
|
|
51
|
+
ctx.fillStyle = gradient;
|
|
52
|
+
ctx.fillRect(fixedRightEdge, headerHeight, shadowWidth, displayHeight - headerHeight);
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* 渲染边界�?
|
|
56
|
+
*/
|
|
57
|
+
FixedColumnRenderer.prototype.renderBorder = function (fixedRightEdge) {
|
|
58
|
+
if (!this.context)
|
|
59
|
+
return;
|
|
60
|
+
var _a = this.context, ctx = _a.ctx, headerHeight = _a.headerHeight, displayHeight = _a.displayHeight;
|
|
61
|
+
ctx.strokeStyle = "rgba(0, 0, 0, 0.06)";
|
|
62
|
+
ctx.lineWidth = 1;
|
|
63
|
+
ctx.beginPath();
|
|
64
|
+
ctx.moveTo(fixedRightEdge, headerHeight);
|
|
65
|
+
ctx.lineTo(fixedRightEdge, displayHeight);
|
|
66
|
+
ctx.stroke();
|
|
67
|
+
};
|
|
68
|
+
return FixedColumnRenderer;
|
|
69
|
+
}());
|
|
70
|
+
|
|
71
|
+
export { FixedColumnRenderer };
|