@canvas-components/print-design 0.1.1 → 0.1.2
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/README.md +135 -125
- package/dist/index.cjs +1832 -395
- package/dist/index.d.cts +134 -5
- package/dist/index.d.ts +134 -5
- package/dist/index.js +1833 -398
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { drawBarcodeToCanvas, exportBarcodeToSvg } from '@canvas-components/barcode';
|
|
2
|
+
import { drawQrCodeToCanvas, exportQrCodeToSvg } from '@canvas-components/qrcode';
|
|
3
3
|
import { drawCanvasChartToCanvas, exportCanvasChartToSvg } from '@canvas-components/chart';
|
|
4
4
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
@@ -725,6 +725,21 @@ function resolveTableDataSource(data, path) {
|
|
|
725
725
|
}
|
|
726
726
|
|
|
727
727
|
// src/model/table-options.ts
|
|
728
|
+
function resolveTableCellOverflow(column, element) {
|
|
729
|
+
return column.cellOverflow ?? (column.ellipsis == null ? element.cellOverflow ?? "wrap" : column.ellipsis ? "ellipsis" : "wrap");
|
|
730
|
+
}
|
|
731
|
+
function resolveTableCellPadding(column, element) {
|
|
732
|
+
const value = (side, fallback) => Math.max(
|
|
733
|
+
0,
|
|
734
|
+
column.cellPadding?.[side] ?? element.cellPadding?.[side] ?? fallback
|
|
735
|
+
);
|
|
736
|
+
return {
|
|
737
|
+
top: value("top", 0),
|
|
738
|
+
right: value("right", 4),
|
|
739
|
+
bottom: value("bottom", 0),
|
|
740
|
+
left: value("left", 4)
|
|
741
|
+
};
|
|
742
|
+
}
|
|
728
743
|
function resolvePrintTableOptions(element, data) {
|
|
729
744
|
const pixelsPerMillimeter = 96 / 25.4;
|
|
730
745
|
const columns = (items) => items.map((column) => ({
|
|
@@ -734,7 +749,8 @@ function resolvePrintTableOptions(element, data) {
|
|
|
734
749
|
([, value]) => value !== void 0
|
|
735
750
|
)
|
|
736
751
|
) : void 0,
|
|
737
|
-
|
|
752
|
+
cellOverflow: resolveTableCellOverflow(column, element),
|
|
753
|
+
ellipsis: resolveTableCellOverflow(column, element) === "ellipsis",
|
|
738
754
|
summary: element.showSummary === false ? false : column.summary,
|
|
739
755
|
summaryTitle: element.showSummary === false ? void 0 : column.summaryTitle,
|
|
740
756
|
children: column.children ? columns(column.children) : void 0
|
|
@@ -853,6 +869,249 @@ function computePrintTableSummaryValues(rows, columns) {
|
|
|
853
869
|
return result;
|
|
854
870
|
}
|
|
855
871
|
|
|
872
|
+
// src/model/table-layout.ts
|
|
873
|
+
function tableHeaderDepth(columns) {
|
|
874
|
+
return Math.max(
|
|
875
|
+
0,
|
|
876
|
+
...columns.filter((column) => !column.hidden).map(
|
|
877
|
+
(column) => 1 + tableHeaderDepth(column.children?.length ? column.children : [])
|
|
878
|
+
)
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
function tableHeaderCells(element) {
|
|
882
|
+
const depth = tableHeaderDepth(element.columns);
|
|
883
|
+
const cells = [];
|
|
884
|
+
const walk = (columns, level, start) => {
|
|
885
|
+
let index = start;
|
|
886
|
+
for (const column of columns) {
|
|
887
|
+
if (column.hidden) continue;
|
|
888
|
+
const children = column.children?.filter((item) => !item.hidden) ?? [];
|
|
889
|
+
const span = children.length ? tableLeafColumns(children).filter((item) => !item.hidden).length : 1;
|
|
890
|
+
if (!span) continue;
|
|
891
|
+
cells.push({
|
|
892
|
+
rowIndex: level,
|
|
893
|
+
columnIndex: index,
|
|
894
|
+
rowSpan: children.length ? 1 : depth - level,
|
|
895
|
+
colSpan: span,
|
|
896
|
+
column
|
|
897
|
+
});
|
|
898
|
+
if (children.length) walk(children, level + 1, index);
|
|
899
|
+
index += span;
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
walk(element.columns, 0, 0);
|
|
903
|
+
for (const merge of element.headerCells ?? []) {
|
|
904
|
+
const rowSpan = Math.max(1, merge.rowSpan ?? 1);
|
|
905
|
+
const colSpan = Math.max(1, merge.colSpan ?? 1);
|
|
906
|
+
if (rowSpan * colSpan < 2) continue;
|
|
907
|
+
const anchor = cells.find(
|
|
908
|
+
(cell) => cell.rowIndex === merge.rowIndex && cell.columnIndex === merge.columnIndex
|
|
909
|
+
);
|
|
910
|
+
if (!anchor) continue;
|
|
911
|
+
const inside = (cell) => cell.rowIndex >= merge.rowIndex && cell.rowIndex + cell.rowSpan <= merge.rowIndex + rowSpan && cell.columnIndex >= merge.columnIndex && cell.columnIndex + cell.colSpan <= merge.columnIndex + colSpan;
|
|
912
|
+
const intersects = (cell) => cell.rowIndex < merge.rowIndex + rowSpan && cell.rowIndex + cell.rowSpan > merge.rowIndex && cell.columnIndex < merge.columnIndex + colSpan && cell.columnIndex + cell.colSpan > merge.columnIndex;
|
|
913
|
+
if (cells.some((cell) => intersects(cell) && !inside(cell))) continue;
|
|
914
|
+
const retained = cells.filter((cell) => !intersects(cell));
|
|
915
|
+
cells.length = 0;
|
|
916
|
+
cells.push(...retained, { ...anchor, rowSpan, colSpan });
|
|
917
|
+
}
|
|
918
|
+
return cells.sort(
|
|
919
|
+
(a, b) => a.rowIndex - b.rowIndex || a.columnIndex - b.columnIndex
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
function tableContentHeight(element, rowCount, showSummary = true) {
|
|
923
|
+
const depth = element.showHeader === false ? 0 : tableHeaderDepth(element.columns);
|
|
924
|
+
const header = depth * (element.headerRowHeight ?? 9);
|
|
925
|
+
const rows = Math.max(
|
|
926
|
+
rowCount,
|
|
927
|
+
element.fillEmptyRows ? element.printRowCount ?? 0 : 0
|
|
928
|
+
);
|
|
929
|
+
const summary = showSummary && element.showSummary !== false && tableLeafColumns(element.columns).some(
|
|
930
|
+
(column) => !!column.summary || column.summaryTitle != null
|
|
931
|
+
) ? element.summaryRowHeight ?? element.rowHeight ?? 8 : 0;
|
|
932
|
+
return header + rows * (element.rowHeight ?? 8) + summary;
|
|
933
|
+
}
|
|
934
|
+
function resolvedTableHeight(element, data = {}) {
|
|
935
|
+
const rows = resolveTableRows(element, data);
|
|
936
|
+
const limit = Math.max(0, Math.floor(element.printRowCount ?? 0));
|
|
937
|
+
if (element.rotation) return element.height;
|
|
938
|
+
if (!rows.length && !element.fillEmptyRows) return element.height;
|
|
939
|
+
return tableContentHeight(
|
|
940
|
+
element,
|
|
941
|
+
limit ? Math.min(rows.length, limit) : rows.length
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
function coveringTableCell(cells, rowIndex, columnIndex) {
|
|
945
|
+
let covering;
|
|
946
|
+
let largest = 0;
|
|
947
|
+
for (const cell of cells ?? []) {
|
|
948
|
+
const rowSpan = Math.max(1, cell.rowSpan ?? 1);
|
|
949
|
+
const colSpan = Math.max(1, cell.colSpan ?? 1);
|
|
950
|
+
if (rowIndex < cell.rowIndex || rowIndex >= cell.rowIndex + rowSpan || columnIndex < cell.columnIndex || columnIndex >= cell.columnIndex + colSpan)
|
|
951
|
+
continue;
|
|
952
|
+
if (rowSpan * colSpan > largest) {
|
|
953
|
+
covering = cell;
|
|
954
|
+
largest = rowSpan * colSpan;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
return covering;
|
|
958
|
+
}
|
|
959
|
+
function resolveTableCells(element, rows, columns) {
|
|
960
|
+
const cells = [...element.cells ?? []];
|
|
961
|
+
const rule = element.mergeCell;
|
|
962
|
+
if (!rule || !rows.length || !columns.length) return cells;
|
|
963
|
+
const samePath = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
964
|
+
const valueKey = (value) => value == null ? "" : typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
965
|
+
const overlaps = (row, column, rowSpan, colSpan) => cells.some(
|
|
966
|
+
(cell) => ((cell.rowSpan ?? 1) > 1 || (cell.colSpan ?? 1) > 1) && row < cell.rowIndex + Math.max(1, cell.rowSpan ?? 1) && row + rowSpan > cell.rowIndex && column < cell.columnIndex + Math.max(1, cell.colSpan ?? 1) && column + colSpan > cell.columnIndex
|
|
967
|
+
);
|
|
968
|
+
const rowRule = rule.row;
|
|
969
|
+
if (rowRule?.keys?.length) {
|
|
970
|
+
const targets = rowRule.columns?.length ? rowRule.columns : rowRule.keys;
|
|
971
|
+
const groupKey = (row) => JSON.stringify(
|
|
972
|
+
rowRule.keys.map((key) => valueKey(readTableCell(row, key)))
|
|
973
|
+
);
|
|
974
|
+
for (const [columnIndex, column] of columns.entries()) {
|
|
975
|
+
if (!targets.some((key) => samePath(column.dataIndex, key))) continue;
|
|
976
|
+
let rowIndex = 0;
|
|
977
|
+
while (rowIndex < rows.length) {
|
|
978
|
+
if (overlaps(rowIndex, columnIndex, 1, 1)) {
|
|
979
|
+
rowIndex++;
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
const current = groupKey(rows[rowIndex]);
|
|
983
|
+
let rowSpan = 1;
|
|
984
|
+
while (rowIndex + rowSpan < rows.length && groupKey(rows[rowIndex + rowSpan]) === current && !overlaps(rowIndex + rowSpan, columnIndex, 1, 1))
|
|
985
|
+
rowSpan++;
|
|
986
|
+
if (rowSpan > 1)
|
|
987
|
+
cells.push({
|
|
988
|
+
...cells.find(
|
|
989
|
+
(cell) => cell.rowIndex === rowIndex && cell.columnIndex === columnIndex
|
|
990
|
+
),
|
|
991
|
+
rowIndex,
|
|
992
|
+
columnIndex,
|
|
993
|
+
rowSpan
|
|
994
|
+
});
|
|
995
|
+
rowIndex += rowSpan;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
const columnRule = rule.column;
|
|
1000
|
+
if (columnRule?.keys?.length) {
|
|
1001
|
+
for (const [rowIndex, row] of rows.entries()) {
|
|
1002
|
+
let columnIndex = 0;
|
|
1003
|
+
while (columnIndex < columns.length) {
|
|
1004
|
+
const column = columns[columnIndex];
|
|
1005
|
+
if (!columnRule.keys.some((key) => samePath(column.dataIndex, key)) || overlaps(rowIndex, columnIndex, 1, 1)) {
|
|
1006
|
+
columnIndex++;
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
const current = valueKey(readTableCell(row, column.dataIndex));
|
|
1010
|
+
let colSpan = 1;
|
|
1011
|
+
while (columnIndex + colSpan < columns.length) {
|
|
1012
|
+
const nextIndex = columnIndex + colSpan;
|
|
1013
|
+
const next = columns[nextIndex];
|
|
1014
|
+
if (!columnRule.keys.some((key) => samePath(next.dataIndex, key)) || valueKey(readTableCell(row, next.dataIndex)) !== current || overlaps(rowIndex, nextIndex, 1, 1))
|
|
1015
|
+
break;
|
|
1016
|
+
colSpan++;
|
|
1017
|
+
}
|
|
1018
|
+
if (colSpan > 1)
|
|
1019
|
+
cells.push({
|
|
1020
|
+
...cells.find(
|
|
1021
|
+
(cell) => cell.rowIndex === rowIndex && cell.columnIndex === columnIndex
|
|
1022
|
+
),
|
|
1023
|
+
rowIndex,
|
|
1024
|
+
columnIndex,
|
|
1025
|
+
colSpan
|
|
1026
|
+
});
|
|
1027
|
+
columnIndex += colSpan;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return cells;
|
|
1032
|
+
}
|
|
1033
|
+
function expandTableCellSelection(cells, selection) {
|
|
1034
|
+
let firstRow = Math.min(selection.startRow, selection.endRow);
|
|
1035
|
+
let lastRow = Math.max(selection.startRow, selection.endRow);
|
|
1036
|
+
let firstColumn = Math.min(selection.startColumn, selection.endColumn);
|
|
1037
|
+
let lastColumn = Math.max(selection.startColumn, selection.endColumn);
|
|
1038
|
+
let changed = true;
|
|
1039
|
+
while (changed) {
|
|
1040
|
+
changed = false;
|
|
1041
|
+
for (const cell of cells ?? []) {
|
|
1042
|
+
const endRow = cell.rowIndex + Math.max(1, cell.rowSpan ?? 1) - 1;
|
|
1043
|
+
const endColumn = cell.columnIndex + Math.max(1, cell.colSpan ?? 1) - 1;
|
|
1044
|
+
if (cell.rowIndex > lastRow || endRow < firstRow || cell.columnIndex > lastColumn || endColumn < firstColumn)
|
|
1045
|
+
continue;
|
|
1046
|
+
const nextFirstRow = Math.min(firstRow, cell.rowIndex);
|
|
1047
|
+
const nextLastRow = Math.max(lastRow, endRow);
|
|
1048
|
+
const nextFirstColumn = Math.min(firstColumn, cell.columnIndex);
|
|
1049
|
+
const nextLastColumn = Math.max(lastColumn, endColumn);
|
|
1050
|
+
changed = changed || nextFirstRow !== firstRow || nextLastRow !== lastRow || nextFirstColumn !== firstColumn || nextLastColumn !== lastColumn;
|
|
1051
|
+
firstRow = nextFirstRow;
|
|
1052
|
+
lastRow = nextLastRow;
|
|
1053
|
+
firstColumn = nextFirstColumn;
|
|
1054
|
+
lastColumn = nextLastColumn;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return { firstRow, lastRow, firstColumn, lastColumn };
|
|
1058
|
+
}
|
|
1059
|
+
function tableBorderVisible(element, data, cell, row) {
|
|
1060
|
+
const path = cell?.borderPath || (element.borderMode === "binding" ? element.borderPath : void 0);
|
|
1061
|
+
if (path) {
|
|
1062
|
+
const local = row ? resolvePrintDesignDataPath(row, path) : void 0;
|
|
1063
|
+
const value = local === void 0 ? resolvePrintDesignDataPath(data, path) : local;
|
|
1064
|
+
return value !== false && value !== 0 && value !== "" && value != null;
|
|
1065
|
+
}
|
|
1066
|
+
return element.borderMode !== "hide" && element.borderMode !== "binding";
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
// src/rendering/elements/image.ts
|
|
1070
|
+
var drawImageElement = (element, context) => {
|
|
1071
|
+
const { ctx, x, y, width, height, onImageLoad } = context;
|
|
1072
|
+
const image = resolveImage(element.src, onImageLoad);
|
|
1073
|
+
if (image?.complete && image.naturalWidth > 0) {
|
|
1074
|
+
drawImageFit(ctx, image, x, y, width, height, element.fit ?? "contain");
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
var imageCache = /* @__PURE__ */ new Map();
|
|
1078
|
+
var pendingImages = /* @__PURE__ */ new Set();
|
|
1079
|
+
function resolveImage(src, onLoad) {
|
|
1080
|
+
if (typeof Image === "undefined" || !src) return void 0;
|
|
1081
|
+
const cached = imageCache.get(src);
|
|
1082
|
+
if (cached) return cached;
|
|
1083
|
+
if (pendingImages.has(src)) return void 0;
|
|
1084
|
+
pendingImages.add(src);
|
|
1085
|
+
const image = new Image();
|
|
1086
|
+
image.onload = () => {
|
|
1087
|
+
pendingImages.delete(src);
|
|
1088
|
+
imageCache.set(src, image);
|
|
1089
|
+
onLoad?.();
|
|
1090
|
+
};
|
|
1091
|
+
image.onerror = () => pendingImages.delete(src);
|
|
1092
|
+
image.src = src;
|
|
1093
|
+
return void 0;
|
|
1094
|
+
}
|
|
1095
|
+
function drawImageFit(ctx, image, x, y, width, height, fit) {
|
|
1096
|
+
if (fit === "fill") {
|
|
1097
|
+
ctx.drawImage(image, x, y, width, height);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
const ratio = fit === "cover" ? Math.max(width / image.naturalWidth, height / image.naturalHeight) : Math.min(width / image.naturalWidth, height / image.naturalHeight);
|
|
1101
|
+
const drawWidth = image.naturalWidth * ratio;
|
|
1102
|
+
const drawHeight = image.naturalHeight * ratio;
|
|
1103
|
+
const drawX = x + (width - drawWidth) / 2;
|
|
1104
|
+
const drawY = y + (height - drawHeight) / 2;
|
|
1105
|
+
ctx.save();
|
|
1106
|
+
if (fit === "cover") {
|
|
1107
|
+
ctx.beginPath();
|
|
1108
|
+
ctx.rect(x, y, width, height);
|
|
1109
|
+
ctx.clip();
|
|
1110
|
+
}
|
|
1111
|
+
ctx.drawImage(image, drawX, drawY, drawWidth, drawHeight);
|
|
1112
|
+
ctx.restore();
|
|
1113
|
+
}
|
|
1114
|
+
|
|
856
1115
|
// src/rendering/elements/table.ts
|
|
857
1116
|
function cellText(value) {
|
|
858
1117
|
if (value == null) return "";
|
|
@@ -876,18 +1135,269 @@ function displayCell(value, column) {
|
|
|
876
1135
|
const parts = formatted.split(".");
|
|
877
1136
|
if (separator !== false)
|
|
878
1137
|
parts[0] = parts[0].replace(
|
|
879
|
-
|
|
1138
|
+
/\B(?=(\d{3})+(?!\d))/g,
|
|
880
1139
|
typeof separator === "string" ? separator : ","
|
|
881
1140
|
);
|
|
882
1141
|
return (column.moneyFormat?.symbol ?? "") + parts.join(".");
|
|
883
1142
|
}
|
|
884
|
-
function
|
|
1143
|
+
function wrapCellText(ctx, value, width) {
|
|
1144
|
+
const lines = [];
|
|
1145
|
+
for (const paragraph of value.split(/\r?\n/)) {
|
|
1146
|
+
let line = "";
|
|
1147
|
+
for (const character of paragraph) {
|
|
1148
|
+
if (line && ctx.measureText(line + character).width > width) {
|
|
1149
|
+
lines.push(line);
|
|
1150
|
+
line = "";
|
|
1151
|
+
}
|
|
1152
|
+
line += character;
|
|
1153
|
+
}
|
|
1154
|
+
lines.push(line);
|
|
1155
|
+
}
|
|
1156
|
+
return lines;
|
|
1157
|
+
}
|
|
1158
|
+
function ellipsisCellText(ctx, value, width) {
|
|
1159
|
+
if (ctx.measureText(value).width <= width) return value;
|
|
1160
|
+
const suffix = "...";
|
|
1161
|
+
if (ctx.measureText(suffix).width > width) return "";
|
|
1162
|
+
let text = "";
|
|
1163
|
+
for (const character of value) {
|
|
1164
|
+
if (ctx.measureText(text + character + suffix).width > width) break;
|
|
1165
|
+
text += character;
|
|
1166
|
+
}
|
|
1167
|
+
return text + suffix;
|
|
1168
|
+
}
|
|
1169
|
+
function drawTypedCell(ctx, column, value, x, y, width, height, onImageLoad) {
|
|
1170
|
+
const content = value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
1171
|
+
const type = typeof content?.type === "string" ? content.type : column.cellType;
|
|
1172
|
+
const payload = content?.value ?? content?.src ?? content?.text ?? value;
|
|
1173
|
+
if (!type || ["text", "emoji", "money", "link", "json"].includes(type))
|
|
1174
|
+
return false;
|
|
1175
|
+
const inset = Math.min(6, width / 8, height / 8);
|
|
1176
|
+
ctx.save();
|
|
1177
|
+
try {
|
|
1178
|
+
if (type === "chart") {
|
|
1179
|
+
if (typeof content?.chartType !== "string") return false;
|
|
1180
|
+
try {
|
|
1181
|
+
drawCanvasChartToCanvas({
|
|
1182
|
+
ctx,
|
|
1183
|
+
x: x + inset,
|
|
1184
|
+
y: y + inset,
|
|
1185
|
+
width: Math.max(1, width - inset * 2),
|
|
1186
|
+
height: Math.max(1, height - inset * 2),
|
|
1187
|
+
type: content.chartType,
|
|
1188
|
+
option: content.option ?? payload,
|
|
1189
|
+
simple: true
|
|
1190
|
+
});
|
|
1191
|
+
} catch {
|
|
1192
|
+
return false;
|
|
1193
|
+
}
|
|
1194
|
+
return true;
|
|
1195
|
+
}
|
|
1196
|
+
if (type === "timeline") {
|
|
1197
|
+
const items = Array.isArray(content?.items) ? content.items : Array.isArray(payload) ? payload : [];
|
|
1198
|
+
if (!items.length) return false;
|
|
1199
|
+
ctx.strokeStyle = "#94a3b8";
|
|
1200
|
+
ctx.fillStyle = "#1677ff";
|
|
1201
|
+
ctx.beginPath();
|
|
1202
|
+
ctx.moveTo(x + inset + 3, y + inset);
|
|
1203
|
+
ctx.lineTo(x + inset + 3, y + height - inset);
|
|
1204
|
+
ctx.stroke();
|
|
1205
|
+
ctx.font = `${Math.min(12, Math.max(8, height / items.length / 2))}px sans-serif`;
|
|
1206
|
+
ctx.textAlign = "left";
|
|
1207
|
+
ctx.textBaseline = "middle";
|
|
1208
|
+
items.slice(0, Math.max(1, Math.floor(height / 10))).forEach((item, index, shown) => {
|
|
1209
|
+
const mid = y + (index + 0.5) * height / shown.length;
|
|
1210
|
+
ctx.beginPath();
|
|
1211
|
+
ctx.arc(x + inset + 3, mid, 2, 0, Math.PI * 2);
|
|
1212
|
+
ctx.fill();
|
|
1213
|
+
const label = item && typeof item === "object" ? cellText(
|
|
1214
|
+
item.title ?? item.content
|
|
1215
|
+
) : cellText(item);
|
|
1216
|
+
ctx.fillText(
|
|
1217
|
+
label,
|
|
1218
|
+
x + inset + 10,
|
|
1219
|
+
mid,
|
|
1220
|
+
Math.max(1, width - inset * 2 - 10)
|
|
1221
|
+
);
|
|
1222
|
+
});
|
|
1223
|
+
return true;
|
|
1224
|
+
}
|
|
1225
|
+
if (type === "image") {
|
|
1226
|
+
drawImageElement(
|
|
1227
|
+
{
|
|
1228
|
+
id: "table-cell-image",
|
|
1229
|
+
type: "image",
|
|
1230
|
+
x: 0,
|
|
1231
|
+
y: 0,
|
|
1232
|
+
width: 1,
|
|
1233
|
+
height: 1,
|
|
1234
|
+
src: cellText(payload),
|
|
1235
|
+
fit: "contain"
|
|
1236
|
+
},
|
|
1237
|
+
{
|
|
1238
|
+
ctx,
|
|
1239
|
+
x: x + inset,
|
|
1240
|
+
y: y + inset,
|
|
1241
|
+
width: width - inset * 2,
|
|
1242
|
+
height: height - inset * 2,
|
|
1243
|
+
centerX: x + width / 2,
|
|
1244
|
+
centerY: y + height / 2,
|
|
1245
|
+
scale: 1,
|
|
1246
|
+
data: {},
|
|
1247
|
+
onImageLoad
|
|
1248
|
+
}
|
|
1249
|
+
);
|
|
1250
|
+
return true;
|
|
1251
|
+
}
|
|
1252
|
+
if (type === "qrcode") {
|
|
1253
|
+
const size = Math.max(1, Math.min(width, height) - inset * 2);
|
|
1254
|
+
try {
|
|
1255
|
+
drawQrCodeToCanvas({
|
|
1256
|
+
ctx,
|
|
1257
|
+
x: x + (width - size) / 2,
|
|
1258
|
+
y: y + (height - size) / 2,
|
|
1259
|
+
width: size,
|
|
1260
|
+
height: size,
|
|
1261
|
+
value: cellText(payload)
|
|
1262
|
+
});
|
|
1263
|
+
} catch {
|
|
1264
|
+
return false;
|
|
1265
|
+
}
|
|
1266
|
+
return true;
|
|
1267
|
+
}
|
|
1268
|
+
if (type === "barcode") {
|
|
1269
|
+
try {
|
|
1270
|
+
drawBarcodeToCanvas({
|
|
1271
|
+
ctx,
|
|
1272
|
+
x: x + inset,
|
|
1273
|
+
y: y + inset,
|
|
1274
|
+
width: Math.max(1, width - inset * 2),
|
|
1275
|
+
height: Math.max(1, height - inset * 2),
|
|
1276
|
+
value: cellText(payload),
|
|
1277
|
+
format: "code128",
|
|
1278
|
+
displayValue: false
|
|
1279
|
+
});
|
|
1280
|
+
} catch {
|
|
1281
|
+
return false;
|
|
1282
|
+
}
|
|
1283
|
+
return true;
|
|
1284
|
+
}
|
|
1285
|
+
if (type === "color") {
|
|
1286
|
+
ctx.fillStyle = cellText(payload) || "transparent";
|
|
1287
|
+
ctx.fillRect(
|
|
1288
|
+
x + inset,
|
|
1289
|
+
y + inset,
|
|
1290
|
+
Math.max(0, width - inset * 2),
|
|
1291
|
+
Math.max(0, height - inset * 2)
|
|
1292
|
+
);
|
|
1293
|
+
return true;
|
|
1294
|
+
}
|
|
1295
|
+
if (type === "progress") {
|
|
1296
|
+
const percent = Math.max(0, Math.min(100, Number(payload) || 0));
|
|
1297
|
+
const barY = y + height / 2 - 3;
|
|
1298
|
+
ctx.fillStyle = "#e5e7eb";
|
|
1299
|
+
ctx.fillRect(x + inset, barY, Math.max(0, width - inset * 2), 6);
|
|
1300
|
+
ctx.fillStyle = "#1677ff";
|
|
1301
|
+
ctx.fillRect(
|
|
1302
|
+
x + inset,
|
|
1303
|
+
barY,
|
|
1304
|
+
Math.max(0, width - inset * 2) * percent / 100,
|
|
1305
|
+
6
|
|
1306
|
+
);
|
|
1307
|
+
return true;
|
|
1308
|
+
}
|
|
1309
|
+
if (["checkbox", "radio", "switch"].includes(type)) {
|
|
1310
|
+
const checked = payload === true || payload === 1 || payload === "true";
|
|
1311
|
+
const size = Math.min(14, height - inset * 2);
|
|
1312
|
+
const centerX = x + width / 2, centerY = y + height / 2;
|
|
1313
|
+
ctx.strokeStyle = checked ? "#1677ff" : "#6b7280";
|
|
1314
|
+
ctx.fillStyle = checked ? "#1677ff" : "#ffffff";
|
|
1315
|
+
ctx.lineWidth = 1.5;
|
|
1316
|
+
if (type === "radio") {
|
|
1317
|
+
ctx.beginPath();
|
|
1318
|
+
ctx.arc(centerX, centerY, size / 2, 0, Math.PI * 2);
|
|
1319
|
+
ctx.stroke();
|
|
1320
|
+
if (checked) {
|
|
1321
|
+
ctx.beginPath();
|
|
1322
|
+
ctx.arc(centerX, centerY, size / 4, 0, Math.PI * 2);
|
|
1323
|
+
ctx.fill();
|
|
1324
|
+
}
|
|
1325
|
+
} else if (type === "switch") {
|
|
1326
|
+
ctx.fillRect(
|
|
1327
|
+
centerX - size,
|
|
1328
|
+
centerY - size / 3,
|
|
1329
|
+
size * 2,
|
|
1330
|
+
size * 2 / 3
|
|
1331
|
+
);
|
|
1332
|
+
ctx.fillStyle = "#ffffff";
|
|
1333
|
+
ctx.beginPath();
|
|
1334
|
+
ctx.arc(
|
|
1335
|
+
centerX + (checked ? size / 2 : -size / 2),
|
|
1336
|
+
centerY,
|
|
1337
|
+
size / 3,
|
|
1338
|
+
0,
|
|
1339
|
+
Math.PI * 2
|
|
1340
|
+
);
|
|
1341
|
+
ctx.fill();
|
|
1342
|
+
} else {
|
|
1343
|
+
ctx.strokeRect(centerX - size / 2, centerY - size / 2, size, size);
|
|
1344
|
+
if (checked) {
|
|
1345
|
+
ctx.fillStyle = "#1677ff";
|
|
1346
|
+
ctx.fillRect(
|
|
1347
|
+
centerX - size / 2 + 3,
|
|
1348
|
+
centerY - size / 2 + 3,
|
|
1349
|
+
size - 6,
|
|
1350
|
+
size - 6
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
return true;
|
|
1355
|
+
}
|
|
1356
|
+
if (type === "rate") {
|
|
1357
|
+
ctx.fillStyle = "#f59e0b";
|
|
1358
|
+
ctx.textAlign = "center";
|
|
1359
|
+
ctx.textBaseline = "middle";
|
|
1360
|
+
ctx.fillText(
|
|
1361
|
+
"\u2605".repeat(Math.max(0, Math.min(5, Math.round(Number(payload) || 0)))) + "\u2606".repeat(
|
|
1362
|
+
5 - Math.max(0, Math.min(5, Math.round(Number(payload) || 0)))
|
|
1363
|
+
),
|
|
1364
|
+
x + width / 2,
|
|
1365
|
+
y + height / 2,
|
|
1366
|
+
width - inset * 2
|
|
1367
|
+
);
|
|
1368
|
+
return true;
|
|
1369
|
+
}
|
|
1370
|
+
if (type === "tag" || type === "button") {
|
|
1371
|
+
ctx.fillStyle = type === "tag" ? "#e6f4ff" : "#1677ff";
|
|
1372
|
+
ctx.fillRect(
|
|
1373
|
+
x + inset,
|
|
1374
|
+
y + inset,
|
|
1375
|
+
Math.max(0, width - inset * 2),
|
|
1376
|
+
Math.max(0, height - inset * 2)
|
|
1377
|
+
);
|
|
1378
|
+
ctx.fillStyle = type === "tag" ? "#1677ff" : "#ffffff";
|
|
1379
|
+
ctx.textAlign = "center";
|
|
1380
|
+
ctx.textBaseline = "middle";
|
|
1381
|
+
ctx.fillText(
|
|
1382
|
+
cellText(payload),
|
|
1383
|
+
x + width / 2,
|
|
1384
|
+
y + height / 2,
|
|
1385
|
+
width - inset * 4
|
|
1386
|
+
);
|
|
1387
|
+
return true;
|
|
1388
|
+
}
|
|
1389
|
+
return false;
|
|
1390
|
+
} finally {
|
|
1391
|
+
ctx.restore();
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
function drawTableElement(element, { ctx, x, y, width, scale, data, onImageLoad }) {
|
|
885
1395
|
const pxPerMm = 96 / 25.4;
|
|
886
1396
|
const zoom = scale / pxPerMm;
|
|
887
1397
|
const options = resolvePrintTableOptions(element, data);
|
|
888
|
-
const columns = tableLeafColumns(
|
|
889
|
-
(column) => column.hidden
|
|
890
|
-
);
|
|
1398
|
+
const columns = tableLeafColumns(
|
|
1399
|
+
options.columns.filter((column) => !column.hidden)
|
|
1400
|
+
).filter((column) => column.hidden !== true);
|
|
891
1401
|
if (!columns.length) return [];
|
|
892
1402
|
const records = options.dataSource;
|
|
893
1403
|
const count = Math.max(0, Math.floor(element.printRowCount ?? 0));
|
|
@@ -899,6 +1409,7 @@ function drawTableElement(element, { ctx, x, y, width, scale, data }) {
|
|
|
899
1409
|
() => ({})
|
|
900
1410
|
)
|
|
901
1411
|
];
|
|
1412
|
+
const resolvedCells = resolveTableCells(element, records, columns);
|
|
902
1413
|
const summary = element.showSummary === false ? /* @__PURE__ */ new Map() : computePrintTableSummaryValues(records, columns);
|
|
903
1414
|
const availableWidth = width / zoom;
|
|
904
1415
|
const configured = columns.map((column) => Math.max(1, column.width ?? 100));
|
|
@@ -906,57 +1417,151 @@ function drawTableElement(element, { ctx, x, y, width, scale, data }) {
|
|
|
906
1417
|
const widths = configured.map(
|
|
907
1418
|
(value) => availableWidth * value / totalWidth
|
|
908
1419
|
);
|
|
909
|
-
const
|
|
1420
|
+
const headerRowHeight = options.headerRowHeight ?? 0;
|
|
1421
|
+
const headerDepth = headerRowHeight ? tableHeaderDepth(options.columns) : 0;
|
|
1422
|
+
const headerHeight = headerRowHeight * headerDepth;
|
|
910
1423
|
const rowHeight = options.rowHeight;
|
|
911
1424
|
const summaryHeight = options.summaryRowHeight ?? rowHeight;
|
|
912
1425
|
const borderWidth = options.styles.cell.borderWidth ?? 1;
|
|
913
1426
|
const borderColor = options.styles.cell.borderColor;
|
|
914
1427
|
const fontSize = options.theme.fontSize;
|
|
915
1428
|
const cells = [];
|
|
916
|
-
const paint = (value, column, left, top, cellWidth, cellHeight, zone) => {
|
|
1429
|
+
const paint = (value, column, left, top, cellWidth, cellHeight, zone, cell, row, rawValue) => {
|
|
917
1430
|
const style = options.styles[zone];
|
|
918
|
-
ctx.fillStyle = column[zone === "header" ? "headerStyle" : zone === "summary" ? "summaryStyle" : "cellStyle"]?.backgroundColor ?? style.backgroundColor;
|
|
1431
|
+
ctx.fillStyle = cell?.backgroundColor ?? column[zone === "header" ? "headerStyle" : zone === "summary" ? "summaryStyle" : "cellStyle"]?.backgroundColor ?? style.backgroundColor;
|
|
919
1432
|
ctx.fillRect(left, top, cellWidth, cellHeight);
|
|
920
|
-
if (borderWidth > 0) {
|
|
921
|
-
ctx.strokeStyle = borderColor;
|
|
1433
|
+
if (borderWidth > 0 && tableBorderVisible(element, data, cell, row)) {
|
|
1434
|
+
ctx.strokeStyle = cell?.borderColor ?? borderColor;
|
|
922
1435
|
ctx.lineWidth = borderWidth;
|
|
923
1436
|
ctx.strokeRect(left, top, cellWidth, cellHeight);
|
|
924
1437
|
}
|
|
925
|
-
ctx.fillStyle = column[zone === "header" ? "headerStyle" : zone === "summary" ? "summaryStyle" : "cellStyle"]?.color ?? style.color ?? "#000000";
|
|
1438
|
+
ctx.fillStyle = cell?.color ?? column[zone === "header" ? "headerStyle" : zone === "summary" ? "summaryStyle" : "cellStyle"]?.color ?? style.color ?? "#000000";
|
|
1439
|
+
if (zone === "body" && column.cellType === "link" && !cell?.color)
|
|
1440
|
+
ctx.fillStyle = "#1677ff";
|
|
926
1441
|
ctx.font = fontSize + "px sans-serif";
|
|
927
1442
|
ctx.textBaseline = "middle";
|
|
928
|
-
ctx.textAlign = zone === "header" ? column.headerAlign ?? column.align ?? element.cellAlign ?? "left" : column.align ?? element.cellAlign ?? "left";
|
|
929
|
-
const
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
);
|
|
1443
|
+
ctx.textAlign = zone === "header" ? column.headerAlign ?? column.align ?? element.cellAlign ?? "left" : column.align ?? column.cellStyle?.textAlign ?? element.cellAlign ?? "left";
|
|
1444
|
+
const {
|
|
1445
|
+
top: topPadding,
|
|
1446
|
+
right: rightPadding,
|
|
1447
|
+
bottom: bottomPadding,
|
|
1448
|
+
left: leftPadding
|
|
1449
|
+
} = resolveTableCellPadding(column, element);
|
|
1450
|
+
const contentWidth = Math.max(0, cellWidth - leftPadding - rightPadding);
|
|
1451
|
+
const contentHeight = Math.max(0, cellHeight - topPadding - bottomPadding);
|
|
1452
|
+
if (!contentWidth || !contentHeight) return;
|
|
1453
|
+
if (cell?.diagonal) {
|
|
1454
|
+
ctx.save();
|
|
1455
|
+
ctx.strokeStyle = cell.borderColor ?? borderColor;
|
|
1456
|
+
ctx.lineWidth = Math.max(borderWidth, 1);
|
|
1457
|
+
ctx.beginPath();
|
|
1458
|
+
if (cell.diagonal === "down") {
|
|
1459
|
+
ctx.moveTo(left, top);
|
|
1460
|
+
ctx.lineTo(left + cellWidth, top + cellHeight);
|
|
1461
|
+
} else {
|
|
1462
|
+
ctx.moveTo(left, top + cellHeight);
|
|
1463
|
+
ctx.lineTo(left + cellWidth, top);
|
|
1464
|
+
}
|
|
1465
|
+
ctx.stroke();
|
|
1466
|
+
ctx.textAlign = "left";
|
|
1467
|
+
ctx.textBaseline = "top";
|
|
1468
|
+
ctx.fillText(
|
|
1469
|
+
cell.diagonalStart ?? value,
|
|
1470
|
+
left + leftPadding,
|
|
1471
|
+
top + topPadding
|
|
1472
|
+
);
|
|
1473
|
+
ctx.textAlign = "right";
|
|
1474
|
+
ctx.textBaseline = "bottom";
|
|
1475
|
+
ctx.fillText(
|
|
1476
|
+
cell.diagonalEnd ?? "",
|
|
1477
|
+
left + cellWidth - rightPadding,
|
|
1478
|
+
top + cellHeight - bottomPadding
|
|
1479
|
+
);
|
|
1480
|
+
ctx.restore();
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
if (zone === "body" && drawTypedCell(
|
|
1484
|
+
ctx,
|
|
1485
|
+
column,
|
|
1486
|
+
rawValue,
|
|
1487
|
+
left,
|
|
1488
|
+
top,
|
|
1489
|
+
cellWidth,
|
|
1490
|
+
cellHeight,
|
|
1491
|
+
onImageLoad
|
|
1492
|
+
))
|
|
1493
|
+
return;
|
|
1494
|
+
const overflow = column.cellOverflow ?? "wrap";
|
|
1495
|
+
const singleLine = value.replace(/\r?\n/g, " ");
|
|
1496
|
+
const lines = overflow === "wrap" ? wrapCellText(ctx, value, contentWidth) : [
|
|
1497
|
+
overflow === "ellipsis" ? ellipsisCellText(ctx, singleLine, contentWidth) : singleLine
|
|
1498
|
+
];
|
|
1499
|
+
const lineHeight = fontSize * 1.2;
|
|
1500
|
+
const vertical = column.cellStyle?.verticalAlign ?? element.cellVerticalAlign ?? "middle";
|
|
1501
|
+
const firstY = vertical === "top" || lines.length * lineHeight > contentHeight ? top + topPadding + lineHeight / 2 : vertical === "bottom" ? top + cellHeight - bottomPadding - lines.length * lineHeight + lineHeight / 2 : top + topPadding + (contentHeight - lines.length * lineHeight) / 2 + lineHeight / 2;
|
|
1502
|
+
const textX = ctx.textAlign === "right" ? left + cellWidth - rightPadding : ctx.textAlign === "center" ? left + leftPadding + contentWidth / 2 : left + leftPadding;
|
|
1503
|
+
ctx.save();
|
|
1504
|
+
ctx.beginPath();
|
|
1505
|
+
ctx.rect(left + leftPadding, top + topPadding, contentWidth, contentHeight);
|
|
1506
|
+
ctx.clip();
|
|
1507
|
+
lines.forEach((line, index) => {
|
|
1508
|
+
if (overflow === "shrink")
|
|
1509
|
+
ctx.fillText(line, textX, firstY + index * lineHeight, contentWidth);
|
|
1510
|
+
else ctx.fillText(line, textX, firstY + index * lineHeight);
|
|
1511
|
+
});
|
|
1512
|
+
ctx.restore();
|
|
937
1513
|
};
|
|
938
1514
|
ctx.save();
|
|
939
1515
|
try {
|
|
940
1516
|
ctx.translate(x, y);
|
|
941
1517
|
ctx.scale(zoom, zoom);
|
|
942
1518
|
let left = 0;
|
|
943
|
-
if (headerHeight > 0)
|
|
944
|
-
for (const
|
|
1519
|
+
if (headerHeight > 0) {
|
|
1520
|
+
for (const header of tableHeaderCells(element)) {
|
|
1521
|
+
const cellLeft = widths.slice(0, header.columnIndex).reduce((sum, value) => sum + value, 0);
|
|
1522
|
+
const cellWidth = widths.slice(header.columnIndex, header.columnIndex + header.colSpan).reduce((sum, value) => sum + value, 0);
|
|
1523
|
+
const rect = {
|
|
1524
|
+
x: cellLeft,
|
|
1525
|
+
y: header.rowIndex * headerRowHeight,
|
|
1526
|
+
width: cellWidth,
|
|
1527
|
+
height: header.rowSpan * headerRowHeight
|
|
1528
|
+
};
|
|
945
1529
|
paint(
|
|
946
|
-
cellText(column.title ?? column.key ?? ""),
|
|
947
|
-
column,
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1530
|
+
cellText(header.column.title ?? header.column.key ?? ""),
|
|
1531
|
+
header.column,
|
|
1532
|
+
rect.x,
|
|
1533
|
+
rect.y,
|
|
1534
|
+
rect.width,
|
|
1535
|
+
rect.height,
|
|
952
1536
|
"header"
|
|
953
1537
|
);
|
|
954
|
-
|
|
1538
|
+
cells.push({
|
|
1539
|
+
area: "header",
|
|
1540
|
+
rowIndex: header.rowIndex,
|
|
1541
|
+
columnIndex: header.columnIndex,
|
|
1542
|
+
column: header.column,
|
|
1543
|
+
rect
|
|
1544
|
+
});
|
|
955
1545
|
}
|
|
1546
|
+
}
|
|
956
1547
|
for (const [rowIndex, row] of visibleRows.entries()) {
|
|
957
1548
|
left = 0;
|
|
958
1549
|
for (const [index, column] of columns.entries()) {
|
|
1550
|
+
const covering = coveringTableCell(resolvedCells, rowIndex, index);
|
|
1551
|
+
if (covering && (covering.rowIndex !== rowIndex || covering.columnIndex !== index)) {
|
|
1552
|
+
left += widths[index];
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
959
1555
|
const top = headerHeight + rowIndex * rowHeight;
|
|
1556
|
+
const colSpan = Math.min(
|
|
1557
|
+
Math.max(1, covering?.colSpan ?? 1),
|
|
1558
|
+
columns.length - index
|
|
1559
|
+
);
|
|
1560
|
+
const rowSpan = Math.min(
|
|
1561
|
+
Math.max(1, covering?.rowSpan ?? 1),
|
|
1562
|
+
visibleRows.length - rowIndex
|
|
1563
|
+
);
|
|
1564
|
+
const cellWidth = widths.slice(index, index + colSpan).reduce((sum, value2) => sum + value2, 0);
|
|
960
1565
|
const value = rowIndex < records.length ? readTableCell(row, column.dataIndex ?? column.key) : void 0;
|
|
961
1566
|
const rendered = rowIndex < records.length ? column.render?.(value, row, rowIndex, column) : void 0;
|
|
962
1567
|
paint(
|
|
@@ -964,15 +1569,25 @@ function drawTableElement(element, { ctx, x, y, width, scale, data }) {
|
|
|
964
1569
|
column,
|
|
965
1570
|
left,
|
|
966
1571
|
top,
|
|
967
|
-
|
|
968
|
-
rowHeight,
|
|
969
|
-
"body"
|
|
1572
|
+
cellWidth,
|
|
1573
|
+
rowHeight * rowSpan,
|
|
1574
|
+
"body",
|
|
1575
|
+
covering,
|
|
1576
|
+
row,
|
|
1577
|
+
rendered ?? value
|
|
970
1578
|
);
|
|
971
1579
|
if (rowIndex < records.length)
|
|
972
1580
|
cells.push({
|
|
1581
|
+
area: "body",
|
|
973
1582
|
rowIndex,
|
|
1583
|
+
columnIndex: index,
|
|
974
1584
|
column,
|
|
975
|
-
rect: {
|
|
1585
|
+
rect: {
|
|
1586
|
+
x: left,
|
|
1587
|
+
y: top,
|
|
1588
|
+
width: cellWidth,
|
|
1589
|
+
height: rowHeight * rowSpan
|
|
1590
|
+
}
|
|
976
1591
|
});
|
|
977
1592
|
left += widths[index];
|
|
978
1593
|
}
|
|
@@ -2403,52 +3018,6 @@ var drawDividerElement = (element, context) => {
|
|
|
2403
3018
|
}
|
|
2404
3019
|
ctx.stroke();
|
|
2405
3020
|
};
|
|
2406
|
-
|
|
2407
|
-
// src/rendering/elements/image.ts
|
|
2408
|
-
var drawImageElement = (element, context) => {
|
|
2409
|
-
const { ctx, x, y, width, height, onImageLoad } = context;
|
|
2410
|
-
const image = resolveImage(element.src, onImageLoad);
|
|
2411
|
-
if (image?.complete && image.naturalWidth > 0) {
|
|
2412
|
-
drawImageFit(ctx, image, x, y, width, height, element.fit ?? "contain");
|
|
2413
|
-
}
|
|
2414
|
-
};
|
|
2415
|
-
var imageCache = /* @__PURE__ */ new Map();
|
|
2416
|
-
var pendingImages = /* @__PURE__ */ new Set();
|
|
2417
|
-
function resolveImage(src, onLoad) {
|
|
2418
|
-
if (typeof Image === "undefined" || !src) return void 0;
|
|
2419
|
-
const cached = imageCache.get(src);
|
|
2420
|
-
if (cached) return cached;
|
|
2421
|
-
if (pendingImages.has(src)) return void 0;
|
|
2422
|
-
pendingImages.add(src);
|
|
2423
|
-
const image = new Image();
|
|
2424
|
-
image.onload = () => {
|
|
2425
|
-
pendingImages.delete(src);
|
|
2426
|
-
imageCache.set(src, image);
|
|
2427
|
-
onLoad?.();
|
|
2428
|
-
};
|
|
2429
|
-
image.onerror = () => pendingImages.delete(src);
|
|
2430
|
-
image.src = src;
|
|
2431
|
-
return void 0;
|
|
2432
|
-
}
|
|
2433
|
-
function drawImageFit(ctx, image, x, y, width, height, fit) {
|
|
2434
|
-
if (fit === "fill") {
|
|
2435
|
-
ctx.drawImage(image, x, y, width, height);
|
|
2436
|
-
return;
|
|
2437
|
-
}
|
|
2438
|
-
const ratio = fit === "cover" ? Math.max(width / image.naturalWidth, height / image.naturalHeight) : Math.min(width / image.naturalWidth, height / image.naturalHeight);
|
|
2439
|
-
const drawWidth = image.naturalWidth * ratio;
|
|
2440
|
-
const drawHeight = image.naturalHeight * ratio;
|
|
2441
|
-
const drawX = x + (width - drawWidth) / 2;
|
|
2442
|
-
const drawY = y + (height - drawHeight) / 2;
|
|
2443
|
-
ctx.save();
|
|
2444
|
-
if (fit === "cover") {
|
|
2445
|
-
ctx.beginPath();
|
|
2446
|
-
ctx.rect(x, y, width, height);
|
|
2447
|
-
ctx.clip();
|
|
2448
|
-
}
|
|
2449
|
-
ctx.drawImage(image, drawX, drawY, drawWidth, drawHeight);
|
|
2450
|
-
ctx.restore();
|
|
2451
|
-
}
|
|
2452
3021
|
var drawBarcodeElement = (element, context) => {
|
|
2453
3022
|
const { ctx, x, y, width, height, data } = context;
|
|
2454
3023
|
try {
|
|
@@ -2760,7 +3329,8 @@ function drawPrintDesignElement(ctx, element, scale, data = {}, onImageLoad) {
|
|
|
2760
3329
|
const x = element.x * scale;
|
|
2761
3330
|
const y = (element.y - (element.overflowCrop?.offset ?? 0)) * scale;
|
|
2762
3331
|
const width = element.width * scale;
|
|
2763
|
-
const
|
|
3332
|
+
const visualHeight = element.type === "table" ? resolvedTableHeight(element, data) : element.height;
|
|
3333
|
+
const height = (element.overflowCrop?.fullHeight ?? visualHeight) * scale;
|
|
2764
3334
|
const centerX = x + width / 2;
|
|
2765
3335
|
const centerY = y + height / 2;
|
|
2766
3336
|
ctx.save();
|
|
@@ -2851,11 +3421,12 @@ function hitTestPrintDesignPage(page, point, tolerance = 0, data = {}) {
|
|
|
2851
3421
|
for (let index = page.elements.length - 1; index >= 0; index -= 1) {
|
|
2852
3422
|
const element = page.elements[index];
|
|
2853
3423
|
if (!resolvePrintDesignElementVisible(element, data)) continue;
|
|
3424
|
+
const visualHeight = element.type === "table" ? resolvedTableHeight(element, data) : element.height;
|
|
2854
3425
|
const localPoint = rotatePoint(
|
|
2855
3426
|
point,
|
|
2856
3427
|
{
|
|
2857
3428
|
x: element.x + element.width / 2,
|
|
2858
|
-
y: element.y +
|
|
3429
|
+
y: element.y + visualHeight / 2
|
|
2859
3430
|
},
|
|
2860
3431
|
-((element.rotation ?? 0) * Math.PI) / 180
|
|
2861
3432
|
);
|
|
@@ -2882,7 +3453,7 @@ function hitTestPrintDesignPage(page, point, tolerance = 0, data = {}) {
|
|
|
2882
3453
|
}
|
|
2883
3454
|
continue;
|
|
2884
3455
|
}
|
|
2885
|
-
if (localPoint.x >= element.x && localPoint.x <= element.x + element.width && localPoint.y >= element.y && localPoint.y <= element.y +
|
|
3456
|
+
if (localPoint.x >= element.x && localPoint.x <= element.x + element.width && localPoint.y >= element.y && localPoint.y <= element.y + visualHeight) {
|
|
2886
3457
|
return element;
|
|
2887
3458
|
}
|
|
2888
3459
|
}
|
|
@@ -3135,6 +3706,223 @@ function resolveFontSize(value, max) {
|
|
|
3135
3706
|
return Number.isFinite(value) ? Math.max(8, Math.min(max, value)) : 9;
|
|
3136
3707
|
}
|
|
3137
3708
|
|
|
3709
|
+
// src/interaction/geometry.ts
|
|
3710
|
+
var RESIZE_HANDLES = [
|
|
3711
|
+
"nw",
|
|
3712
|
+
"ne",
|
|
3713
|
+
"se",
|
|
3714
|
+
"sw",
|
|
3715
|
+
"n",
|
|
3716
|
+
"s",
|
|
3717
|
+
"w",
|
|
3718
|
+
"e"
|
|
3719
|
+
];
|
|
3720
|
+
function rotatePoint2(point, center, radians) {
|
|
3721
|
+
const x = point.x - center.x;
|
|
3722
|
+
const y = point.y - center.y;
|
|
3723
|
+
const cosine = Math.cos(radians);
|
|
3724
|
+
const sine = Math.sin(radians);
|
|
3725
|
+
return {
|
|
3726
|
+
x: center.x + x * cosine - y * sine,
|
|
3727
|
+
y: center.y + x * sine + y * cosine
|
|
3728
|
+
};
|
|
3729
|
+
}
|
|
3730
|
+
function getSelectionRect(element, scale, data = {}) {
|
|
3731
|
+
const minimumSize = 12 / scale;
|
|
3732
|
+
const width = Math.max(element.width, minimumSize);
|
|
3733
|
+
const visualHeight = element.type === "table" ? resolvedTableHeight(element, data) : element.height;
|
|
3734
|
+
const height = Math.max(visualHeight, minimumSize);
|
|
3735
|
+
return {
|
|
3736
|
+
x: element.x - (width - element.width) / 2,
|
|
3737
|
+
y: element.y - (height - visualHeight) / 2,
|
|
3738
|
+
width,
|
|
3739
|
+
height
|
|
3740
|
+
};
|
|
3741
|
+
}
|
|
3742
|
+
function getRotatedRectangleCorner(rect, rotation, handle) {
|
|
3743
|
+
const x = handle.includes("w") ? rect.x : handle.includes("e") ? rect.x + rect.width : rect.x + rect.width / 2;
|
|
3744
|
+
const y = handle.includes("n") ? rect.y : handle.includes("s") ? rect.y + rect.height : rect.y + rect.height / 2;
|
|
3745
|
+
return rotatePoint2(
|
|
3746
|
+
{ x, y },
|
|
3747
|
+
{ x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 },
|
|
3748
|
+
rotation * Math.PI / 180
|
|
3749
|
+
);
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
// src/helper/measurement-layout.ts
|
|
3753
|
+
function measurementObstacles(elements, scale) {
|
|
3754
|
+
return elements.flatMap((element) => {
|
|
3755
|
+
const rect = getSelectionRect(element, scale);
|
|
3756
|
+
const angle = element.rotation ?? 0;
|
|
3757
|
+
const corners = RESIZE_HANDLES.map(
|
|
3758
|
+
(handle) => getRotatedRectangleCorner(rect, angle, handle)
|
|
3759
|
+
);
|
|
3760
|
+
const center = { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };
|
|
3761
|
+
const stem = rotatePoint2(
|
|
3762
|
+
{ x: center.x, y: rect.y },
|
|
3763
|
+
center,
|
|
3764
|
+
angle * Math.PI / 180
|
|
3765
|
+
);
|
|
3766
|
+
const rotate = rotatePoint2(
|
|
3767
|
+
{ x: center.x, y: rect.y - 17 / scale },
|
|
3768
|
+
center,
|
|
3769
|
+
angle * Math.PI / 180
|
|
3770
|
+
);
|
|
3771
|
+
return [
|
|
3772
|
+
...[...corners, rotate].map((p) => ({
|
|
3773
|
+
x: p.x * scale - 10,
|
|
3774
|
+
y: p.y * scale - 10,
|
|
3775
|
+
width: 20,
|
|
3776
|
+
height: 20
|
|
3777
|
+
})),
|
|
3778
|
+
{
|
|
3779
|
+
x: Math.min(stem.x, rotate.x) * scale - 5,
|
|
3780
|
+
y: Math.min(stem.y, rotate.y) * scale - 5,
|
|
3781
|
+
width: Math.abs(stem.x - rotate.x) * scale + 10,
|
|
3782
|
+
height: Math.abs(stem.y - rotate.y) * scale + 10
|
|
3783
|
+
}
|
|
3784
|
+
];
|
|
3785
|
+
});
|
|
3786
|
+
}
|
|
3787
|
+
function placeMeasurement(line, textWidth, obstacles, viewport) {
|
|
3788
|
+
const horizontal = line.y1 === line.y2;
|
|
3789
|
+
const intersects = (a, b) => a.x <= b.x + b.width && a.x + a.width >= b.x && a.y <= b.y + b.height && a.y + a.height >= b.y;
|
|
3790
|
+
const limit = horizontal ? viewport.height : viewport.width;
|
|
3791
|
+
for (let step = 0; step <= Math.ceil(limit / 16); step++) {
|
|
3792
|
+
for (const sign of step === 0 ? [1] : [1, -1]) {
|
|
3793
|
+
const offset = step * 16 * sign;
|
|
3794
|
+
const x1 = line.x1 + (horizontal ? 0 : offset), x2 = line.x2 + (horizontal ? 0 : offset);
|
|
3795
|
+
const y1 = line.y1 + (horizontal ? offset : 0), y2 = line.y2 + (horizontal ? offset : 0);
|
|
3796
|
+
const textX = (x1 + x2) / 2 + 4, textY = (y1 + y2) / 2 - 4;
|
|
3797
|
+
const boxes = [
|
|
3798
|
+
{
|
|
3799
|
+
x: Math.min(x1, x2) - 3,
|
|
3800
|
+
y: Math.min(y1, y2) - 3,
|
|
3801
|
+
width: Math.abs(x2 - x1) + 6,
|
|
3802
|
+
height: Math.abs(y2 - y1) + 6
|
|
3803
|
+
},
|
|
3804
|
+
{ x: textX - 2, y: textY - 12, width: textWidth + 4, height: 16 }
|
|
3805
|
+
];
|
|
3806
|
+
if (boxes.some(
|
|
3807
|
+
(b) => b.x < 0 || b.y < 0 || b.x + b.width > viewport.width || b.y + b.height > viewport.height
|
|
3808
|
+
))
|
|
3809
|
+
continue;
|
|
3810
|
+
if (boxes.some((b) => obstacles.some((o) => intersects(b, o)))) continue;
|
|
3811
|
+
return { x1, y1, x2, y2, textX, textY };
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
return null;
|
|
3815
|
+
}
|
|
3816
|
+
|
|
3817
|
+
// src/helper/alignment.ts
|
|
3818
|
+
function elementBounds(element) {
|
|
3819
|
+
const angle = (element.rotation ?? 0) * Math.PI / 180;
|
|
3820
|
+
const width = Math.abs(element.width * Math.cos(angle)) + Math.abs(element.height * Math.sin(angle));
|
|
3821
|
+
const height = Math.abs(element.width * Math.sin(angle)) + Math.abs(element.height * Math.cos(angle));
|
|
3822
|
+
return {
|
|
3823
|
+
x: element.x + (element.width - width) / 2,
|
|
3824
|
+
y: element.y + (element.height - height) / 2,
|
|
3825
|
+
width,
|
|
3826
|
+
height
|
|
3827
|
+
};
|
|
3828
|
+
}
|
|
3829
|
+
function snapCoordinate(value, targets, tolerance) {
|
|
3830
|
+
return targets.reduce(
|
|
3831
|
+
(best, target) => Math.abs(target - value) <= tolerance && Math.abs(target - value) < Math.abs(best - value) ? target : best,
|
|
3832
|
+
targets.find((target) => Math.abs(target - value) <= tolerance) ?? value
|
|
3833
|
+
);
|
|
3834
|
+
}
|
|
3835
|
+
function guideTargets(page, axis) {
|
|
3836
|
+
const vertical = axis === "vertical";
|
|
3837
|
+
const size = vertical ? page.width : page.height;
|
|
3838
|
+
const margins = page.margins ?? { top: 10, right: 10, bottom: 10, left: 10 };
|
|
3839
|
+
return [
|
|
3840
|
+
0,
|
|
3841
|
+
size / 2,
|
|
3842
|
+
size,
|
|
3843
|
+
vertical ? margins.left : margins.top,
|
|
3844
|
+
size - (vertical ? margins.right : margins.bottom),
|
|
3845
|
+
...page.elements.filter((e) => e.visible !== false).flatMap((e) => {
|
|
3846
|
+
const b = elementBounds(e);
|
|
3847
|
+
const start = vertical ? b.x : b.y, length = vertical ? b.width : b.height;
|
|
3848
|
+
return [start, start + length / 2, start + length];
|
|
3849
|
+
})
|
|
3850
|
+
];
|
|
3851
|
+
}
|
|
3852
|
+
function nearestMeasurements(page, selectedIds) {
|
|
3853
|
+
const selected = page.elements.filter((e) => selectedIds.includes(e.id) && e.visible !== false).map(elementBounds);
|
|
3854
|
+
if (!selected.length) return [];
|
|
3855
|
+
const left = Math.min(...selected.map((b) => b.x)), top = Math.min(...selected.map((b) => b.y));
|
|
3856
|
+
const right = Math.max(...selected.map((b) => b.x + b.width)), bottom = Math.max(...selected.map((b) => b.y + b.height));
|
|
3857
|
+
const result = /* @__PURE__ */ new Map();
|
|
3858
|
+
const add = (key, x1, y1, x2, y2) => {
|
|
3859
|
+
const distance = Math.hypot(x2 - x1, y2 - y1);
|
|
3860
|
+
if (!result.has(key) || distance < result.get(key).distance)
|
|
3861
|
+
result.set(key, { x1, y1, x2, y2, distance });
|
|
3862
|
+
};
|
|
3863
|
+
for (const e of page.elements) {
|
|
3864
|
+
if (selectedIds.includes(e.id) || e.visible === false) continue;
|
|
3865
|
+
const b = elementBounds(e), r = b.x + b.width, d = b.y + b.height;
|
|
3866
|
+
if (b.y <= bottom && d >= top) {
|
|
3867
|
+
const y = (Math.max(top, b.y) + Math.min(bottom, d)) / 2;
|
|
3868
|
+
if (r <= left) add("left", r, y, left, y);
|
|
3869
|
+
if (b.x >= right) add("right", right, y, b.x, y);
|
|
3870
|
+
}
|
|
3871
|
+
if (b.x <= right && r >= left) {
|
|
3872
|
+
const x = (Math.max(left, b.x) + Math.min(right, r)) / 2;
|
|
3873
|
+
if (d <= top) add("top", x, d, x, top);
|
|
3874
|
+
if (b.y >= bottom) add("bottom", x, bottom, x, b.y);
|
|
3875
|
+
}
|
|
3876
|
+
}
|
|
3877
|
+
return [...result.values()];
|
|
3878
|
+
}
|
|
3879
|
+
function drawMeasurements(context, page, selectedIds, scale, unit = "mm") {
|
|
3880
|
+
context.save();
|
|
3881
|
+
context.strokeStyle = "#e11d48";
|
|
3882
|
+
context.fillStyle = "#e11d48";
|
|
3883
|
+
context.font = "11px sans-serif";
|
|
3884
|
+
context.setLineDash([]);
|
|
3885
|
+
context.lineWidth = 1;
|
|
3886
|
+
const obstacles = measurementObstacles(
|
|
3887
|
+
page.elements.filter(
|
|
3888
|
+
(e) => selectedIds.includes(e.id) && e.visible !== false
|
|
3889
|
+
),
|
|
3890
|
+
scale
|
|
3891
|
+
);
|
|
3892
|
+
context.textAlign = "left";
|
|
3893
|
+
context.textBaseline = "alphabetic";
|
|
3894
|
+
for (const m of nearestMeasurements(page, selectedIds)) {
|
|
3895
|
+
const label = formatDisplayUnit(m.distance, unit);
|
|
3896
|
+
const placement = placeMeasurement(
|
|
3897
|
+
{
|
|
3898
|
+
x1: m.x1 * scale,
|
|
3899
|
+
y1: m.y1 * scale,
|
|
3900
|
+
x2: m.x2 * scale,
|
|
3901
|
+
y2: m.y2 * scale
|
|
3902
|
+
},
|
|
3903
|
+
context.measureText(label).width,
|
|
3904
|
+
obstacles,
|
|
3905
|
+
{ width: page.width * scale, height: page.height * scale }
|
|
3906
|
+
);
|
|
3907
|
+
if (!placement) continue;
|
|
3908
|
+
const { x1, y1, x2, y2, textX, textY } = placement;
|
|
3909
|
+
const horizontal = y1 === y2;
|
|
3910
|
+
context.beginPath();
|
|
3911
|
+
context.moveTo(x1, y1);
|
|
3912
|
+
context.lineTo(x2, y2);
|
|
3913
|
+
for (const [x, y] of [
|
|
3914
|
+
[x1, y1],
|
|
3915
|
+
[x2, y2]
|
|
3916
|
+
]) {
|
|
3917
|
+
context.moveTo(x - (horizontal ? 0 : 3), y - (horizontal ? 3 : 0));
|
|
3918
|
+
context.lineTo(x + (horizontal ? 0 : 3), y + (horizontal ? 3 : 0));
|
|
3919
|
+
}
|
|
3920
|
+
context.stroke();
|
|
3921
|
+
context.fillText(label, textX, textY);
|
|
3922
|
+
}
|
|
3923
|
+
context.restore();
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3138
3926
|
// src/model/pagination.ts
|
|
3139
3927
|
var MAX_PAGES = 1e3;
|
|
3140
3928
|
var PT_TO_MM = 25.4 / 72;
|
|
@@ -3242,7 +4030,7 @@ function paginatePrintDesignDocument(document, data = {}) {
|
|
|
3242
4030
|
bottom,
|
|
3243
4031
|
pageAt
|
|
3244
4032
|
);
|
|
3245
|
-
shift =
|
|
4033
|
+
shift = result.logicalEnd - originalEnd;
|
|
3246
4034
|
continue;
|
|
3247
4035
|
}
|
|
3248
4036
|
if (element.type === "text") {
|
|
@@ -3283,8 +4071,16 @@ function splitTable(element, data, startPage, startY, top, bottom, pageAt) {
|
|
|
3283
4071
|
const rows = resolveTableRows(element, data);
|
|
3284
4072
|
const limit = Math.max(0, Math.floor(element.printRowCount ?? 0));
|
|
3285
4073
|
const records = limit ? rows.slice(0, limit) : rows;
|
|
4074
|
+
const visibleRows = element.fillEmptyRows && limit > records.length ? [
|
|
4075
|
+
...records,
|
|
4076
|
+
...Array.from({ length: limit - records.length }, () => ({}))
|
|
4077
|
+
] : records;
|
|
4078
|
+
const columns = tableLeafColumns(element.columns).filter(
|
|
4079
|
+
(column) => !column.hidden
|
|
4080
|
+
);
|
|
4081
|
+
const resolvedCells = resolveTableCells(element, records, columns);
|
|
3286
4082
|
const rowHeight = Math.max(1, element.rowHeight ?? 8);
|
|
3287
|
-
const header = element.showHeader === false ? 0 : Math.max(1, element.headerRowHeight ?? 9);
|
|
4083
|
+
const header = element.showHeader === false ? 0 : tableHeaderDepth(element.columns) * Math.max(1, element.headerRowHeight ?? 9);
|
|
3288
4084
|
const hasSummary = element.showSummary !== false && tableLeafColumns(element.columns).some(
|
|
3289
4085
|
(column) => !!column.summary || column.summaryTitle != null
|
|
3290
4086
|
);
|
|
@@ -3294,16 +4090,29 @@ function splitTable(element, data, startPage, startY, top, bottom, pageAt) {
|
|
|
3294
4090
|
let offset = 0;
|
|
3295
4091
|
do {
|
|
3296
4092
|
let room = bottom - y;
|
|
3297
|
-
if (room < header + Math.min(rowHeight,
|
|
4093
|
+
if (room < header + Math.min(rowHeight, visibleRows.length ? rowHeight : 0) && y > top) {
|
|
3298
4094
|
pageIndex++;
|
|
3299
4095
|
y = top;
|
|
3300
4096
|
room = bottom - y;
|
|
3301
4097
|
}
|
|
3302
|
-
const remaining =
|
|
3303
|
-
let count =
|
|
4098
|
+
const remaining = visibleRows.length - offset;
|
|
4099
|
+
let count = visibleRows.length ? Math.min(
|
|
3304
4100
|
remaining,
|
|
3305
4101
|
Math.max(1, Math.floor((room - header) / rowHeight))
|
|
3306
4102
|
) : 0;
|
|
4103
|
+
if (count > 0 && count < remaining) {
|
|
4104
|
+
let boundary = offset + count;
|
|
4105
|
+
for (const cell of resolvedCells) {
|
|
4106
|
+
if (cell.rowIndex < boundary && cell.rowIndex + Math.max(1, cell.rowSpan ?? 1) > boundary)
|
|
4107
|
+
boundary = Math.min(boundary, cell.rowIndex);
|
|
4108
|
+
}
|
|
4109
|
+
if (boundary > offset) count = boundary - offset;
|
|
4110
|
+
else if (y > top) {
|
|
4111
|
+
pageIndex++;
|
|
4112
|
+
y = top;
|
|
4113
|
+
continue;
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
3307
4116
|
if (hasSummary && count === remaining && header + count * rowHeight + summaryHeight > room) {
|
|
3308
4117
|
const countWithSummary = Math.floor(
|
|
3309
4118
|
(room - header - summaryHeight) / rowHeight
|
|
@@ -3318,8 +4127,21 @@ function splitTable(element, data, startPage, startY, top, bottom, pageAt) {
|
|
|
3318
4127
|
count--;
|
|
3319
4128
|
}
|
|
3320
4129
|
}
|
|
3321
|
-
|
|
3322
|
-
|
|
4130
|
+
if (count > 0 && count < remaining) {
|
|
4131
|
+
let boundary = offset + count;
|
|
4132
|
+
for (const cell of resolvedCells) {
|
|
4133
|
+
if (cell.rowIndex < boundary && cell.rowIndex + Math.max(1, cell.rowSpan ?? 1) > boundary)
|
|
4134
|
+
boundary = Math.min(boundary, cell.rowIndex);
|
|
4135
|
+
}
|
|
4136
|
+
if (boundary > offset) count = boundary - offset;
|
|
4137
|
+
else if (y > top) {
|
|
4138
|
+
pageIndex++;
|
|
4139
|
+
y = top;
|
|
4140
|
+
continue;
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
const chunk = visibleRows.slice(offset, offset + count);
|
|
4144
|
+
const finalChunk = offset + chunk.length >= visibleRows.length;
|
|
3323
4145
|
const height = Math.min(
|
|
3324
4146
|
room,
|
|
3325
4147
|
Math.max(
|
|
@@ -3334,17 +4156,31 @@ function splitTable(element, data, startPage, startY, top, bottom, pageAt) {
|
|
|
3334
4156
|
height,
|
|
3335
4157
|
dataMode: "static",
|
|
3336
4158
|
dataSource: chunk,
|
|
4159
|
+
cells: resolvedCells.filter(
|
|
4160
|
+
(cell) => cell.rowIndex < offset + count && cell.rowIndex + Math.max(1, cell.rowSpan ?? 1) > offset
|
|
4161
|
+
).map((cell) => {
|
|
4162
|
+
const start = Math.max(cell.rowIndex, offset);
|
|
4163
|
+
return {
|
|
4164
|
+
...cell,
|
|
4165
|
+
rowIndex: start - offset,
|
|
4166
|
+
rowSpan: Math.min(
|
|
4167
|
+
cell.rowIndex + Math.max(1, cell.rowSpan ?? 1),
|
|
4168
|
+
offset + count
|
|
4169
|
+
) - start
|
|
4170
|
+
};
|
|
4171
|
+
}),
|
|
4172
|
+
mergeCell: void 0,
|
|
3337
4173
|
printRowCount: 0,
|
|
3338
4174
|
fillEmptyRows: false,
|
|
3339
4175
|
showSummary: finalChunk ? element.showSummary : false
|
|
3340
4176
|
});
|
|
3341
4177
|
offset += chunk.length;
|
|
3342
4178
|
y += height;
|
|
3343
|
-
if (offset <
|
|
4179
|
+
if (offset < visibleRows.length) {
|
|
3344
4180
|
pageIndex++;
|
|
3345
4181
|
y = top;
|
|
3346
4182
|
}
|
|
3347
|
-
} while (offset <
|
|
4183
|
+
} while (offset < visibleRows.length);
|
|
3348
4184
|
return { logicalEnd: pageIndex * (bottom - top) + (y - top) };
|
|
3349
4185
|
}
|
|
3350
4186
|
function splitText(element, data, startPage, startY, top, bottom, pageAt) {
|
|
@@ -3717,52 +4553,159 @@ function tableMarkup(element, data) {
|
|
|
3717
4553
|
const limit = Math.max(0, Math.floor(element.printRowCount ?? 0));
|
|
3718
4554
|
const rows = limit > 0 ? allRows.slice(0, limit) : allRows;
|
|
3719
4555
|
const displayRows = element.fillEmptyRows && limit > rows.length ? [...rows, ...Array.from({ length: limit - rows.length }, () => ({}))] : rows;
|
|
4556
|
+
const resolvedCells = resolveTableCells(element, rows, columns);
|
|
3720
4557
|
const totalWidth = columns.reduce(
|
|
3721
4558
|
(sum, column) => sum + Math.max(1, Number(column.width) || 100),
|
|
3722
4559
|
0
|
|
3723
4560
|
);
|
|
3724
4561
|
const borderWidth = element.cellBorder?.width === 0 ? 0 : Math.max(0.1, (element.cellBorder?.width ?? 1) * (25.4 / 96));
|
|
3725
|
-
const border = borderWidth ? `${borderWidth}mm solid ${cssColor(element.cellBorder?.color, "#000000")}` : "none";
|
|
4562
|
+
const border = borderWidth && tableBorderVisible(element, data) ? `${borderWidth}mm solid ${cssColor(element.cellBorder?.color, "#000000")}` : "none";
|
|
3726
4563
|
const fontSize = Math.max(1, element.fontSize ?? 10);
|
|
3727
|
-
const
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
0,
|
|
3732
|
-
|
|
3733
|
-
)
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
4564
|
+
const cellCss = (column) => {
|
|
4565
|
+
const padding = resolveTableCellPadding(column, element);
|
|
4566
|
+
const side = (value, fallback) => `${Math.max(0, cssNumber(value, fallback)) * (25.4 / 96)}mm`;
|
|
4567
|
+
const overflow = resolveTableCellOverflow(column, element);
|
|
4568
|
+
return `padding:${side(padding.top, 0)} ${side(padding.right, 4)} ${side(padding.bottom, 0)} ${side(padding.left, 4)};overflow:hidden;white-space:${overflow === "wrap" ? "pre-wrap" : "nowrap"};text-overflow:${overflow === "ellipsis" ? "ellipsis" : "clip"};`;
|
|
4569
|
+
};
|
|
4570
|
+
const cellContent = (column, value, weight) => {
|
|
4571
|
+
const text = cellText2(value);
|
|
4572
|
+
if (resolveTableCellOverflow(column, element) !== "shrink")
|
|
4573
|
+
return escapeHtml(text);
|
|
4574
|
+
const fontPx = fontSize * 96 / 72;
|
|
4575
|
+
const padding = resolveTableCellPadding(column, element);
|
|
4576
|
+
const widthPx = Math.max(
|
|
4577
|
+
1,
|
|
4578
|
+
element.width * 96 / 25.4 * weight / totalWidth - padding.left - padding.right
|
|
4579
|
+
);
|
|
4580
|
+
const estimatedPx = Array.from(text).reduce(
|
|
4581
|
+
(sum, character) => sum + fontPx * (character.charCodeAt(0) < 128 ? 0.55 : 1),
|
|
4582
|
+
0
|
|
4583
|
+
);
|
|
4584
|
+
if (estimatedPx <= widthPx) return escapeHtml(text);
|
|
4585
|
+
return `<svg style="display:block;width:100%;height:1.2em" viewBox="0 0 ${widthPx} ${fontPx * 1.2}" preserveAspectRatio="none"><text x="0" y="${fontPx}" font-size="${fontPx}" fill="currentColor" textLength="${widthPx}" lengthAdjust="spacingAndGlyphs">${escapeHtml(text)}</text></svg>`;
|
|
4586
|
+
};
|
|
4587
|
+
const bodyCellContent = (column, value) => {
|
|
4588
|
+
const content = value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
4589
|
+
const type = typeof content?.type === "string" ? content.type : column.cellType;
|
|
4590
|
+
const payload = content?.value ?? content?.src ?? content?.text ?? value;
|
|
4591
|
+
const text = cellText2(payload);
|
|
4592
|
+
if (type === "chart" && typeof content?.chartType === "string") {
|
|
4593
|
+
try {
|
|
4594
|
+
return exportCanvasChartToSvg({
|
|
4595
|
+
type: content.chartType,
|
|
4596
|
+
option: content.option ?? payload,
|
|
4597
|
+
width: 200,
|
|
4598
|
+
height: 60,
|
|
4599
|
+
simple: true
|
|
4600
|
+
});
|
|
4601
|
+
} catch {
|
|
4602
|
+
return escapeHtml(text);
|
|
4603
|
+
}
|
|
3747
4604
|
}
|
|
4605
|
+
if (type === "timeline") {
|
|
4606
|
+
const items = Array.isArray(content?.items) ? content.items : Array.isArray(payload) ? payload : [];
|
|
4607
|
+
return `<div style="border-left:0.3mm solid #94a3b8;padding-left:1mm">${items.map((item) => `<div style="white-space:nowrap;overflow:hidden;text-overflow:ellipsis">\u2022 ${escapeHtml(item && typeof item === "object" ? cellText2(item.title ?? item.content) : cellText2(item))}</div>`).join("")}</div>`;
|
|
4608
|
+
}
|
|
4609
|
+
if (type === "image")
|
|
4610
|
+
return `<img src="${imageSource(text)}" alt="" style="display:block;max-width:100%;max-height:100%;margin:auto;object-fit:contain">`;
|
|
4611
|
+
if (type === "qrcode") {
|
|
4612
|
+
try {
|
|
4613
|
+
return exportQrCodeToSvg({ value: text, width: 96, height: 96 });
|
|
4614
|
+
} catch {
|
|
4615
|
+
return escapeHtml(text);
|
|
4616
|
+
}
|
|
4617
|
+
}
|
|
4618
|
+
if (type === "barcode") {
|
|
4619
|
+
try {
|
|
4620
|
+
return exportBarcodeToSvg({
|
|
4621
|
+
value: text,
|
|
4622
|
+
width: 200,
|
|
4623
|
+
height: 50,
|
|
4624
|
+
format: "code128",
|
|
4625
|
+
displayValue: false
|
|
4626
|
+
});
|
|
4627
|
+
} catch {
|
|
4628
|
+
return escapeHtml(text);
|
|
4629
|
+
}
|
|
4630
|
+
}
|
|
4631
|
+
if (type === "color")
|
|
4632
|
+
return `<span style="display:block;width:100%;height:100%;min-height:4mm;background:${cssColor(text, "transparent")}"></span>`;
|
|
4633
|
+
if (type === "progress")
|
|
4634
|
+
return `<span style="display:block;height:2mm;background:#e5e7eb"><span style="display:block;height:100%;width:${Math.max(0, Math.min(100, Number(payload) || 0))}%;background:#1677ff"></span></span>`;
|
|
4635
|
+
if (["checkbox", "radio", "switch"].includes(type ?? ""))
|
|
4636
|
+
return payload === true || payload === 1 || payload === "true" ? "\u2611" : "\u2610";
|
|
4637
|
+
if (type === "rate") {
|
|
4638
|
+
const count = Math.max(0, Math.min(5, Math.round(Number(payload) || 0)));
|
|
4639
|
+
return `<span style="color:#f59e0b">${"\u2605".repeat(count)}${"\u2606".repeat(5 - count)}</span>`;
|
|
4640
|
+
}
|
|
4641
|
+
if (type === "tag" || type === "button")
|
|
4642
|
+
return `<span style="display:inline-block;padding:0.3mm 1mm;background:${type === "tag" ? "#e6f4ff" : "#1677ff"};color:${type === "tag" ? "#1677ff" : "#fff"}">${escapeHtml(text)}</span>`;
|
|
4643
|
+
if (type === "json")
|
|
4644
|
+
return escapeHtml(
|
|
4645
|
+
typeof value === "object" ? JSON.stringify(value) : text
|
|
4646
|
+
);
|
|
4647
|
+
if (type === "link")
|
|
4648
|
+
return `<span style="color:#1677ff;text-decoration:underline">${escapeHtml(text)}</span>`;
|
|
4649
|
+
return cellContent(column, value, Math.max(1, Number(column.width) || 100));
|
|
3748
4650
|
};
|
|
3749
|
-
|
|
4651
|
+
const colgroup = columns.map(
|
|
4652
|
+
(column) => `<col style="width:${Math.max(1, Number(column.width) || 100) / totalWidth * 100}%">`
|
|
4653
|
+
).join("");
|
|
4654
|
+
const depth = tableHeaderDepth(visibleColumns);
|
|
4655
|
+
const headerRows = Array.from({ length: depth }, () => []);
|
|
4656
|
+
for (const header2 of tableHeaderCells(element)) {
|
|
4657
|
+
const { column } = header2;
|
|
4658
|
+
const title = typeof column.title === "string" || typeof column.title === "number" ? column.title : column.key ?? "";
|
|
4659
|
+
headerRows[header2.rowIndex].push(
|
|
4660
|
+
`<th colspan="${header2.colSpan}" rowspan="${header2.rowSpan}" style="height:${cssNumber(element.headerRowHeight, 9)}mm;text-align:${cssAlign(column.headerAlign ?? column.align ?? element.cellAlign)};background:${cssColor(element.colors?.header?.backgroundColor, "transparent")};color:${cssColor(element.colors?.header?.color, "#000000")};${cellCss(column)}">${cellContent(
|
|
4661
|
+
column,
|
|
4662
|
+
title,
|
|
4663
|
+
columns.slice(header2.columnIndex, header2.columnIndex + header2.colSpan).reduce(
|
|
4664
|
+
(sum, leaf) => sum + Math.max(1, Number(leaf.width) || 100),
|
|
4665
|
+
0
|
|
4666
|
+
)
|
|
4667
|
+
)}</th>`
|
|
4668
|
+
);
|
|
4669
|
+
}
|
|
3750
4670
|
const header = element.showHeader === false ? "" : `<thead>${headerRows.map((cells) => `<tr>${cells.join("")}</tr>`).join("")}</thead>`;
|
|
3751
4671
|
const body = displayRows.map(
|
|
3752
|
-
(row) => `<tr>${columns.map((column) => {
|
|
4672
|
+
(row, rowIndex) => `<tr>${columns.map((column, columnIndex) => {
|
|
4673
|
+
const cell = coveringTableCell(
|
|
4674
|
+
resolvedCells,
|
|
4675
|
+
rowIndex,
|
|
4676
|
+
columnIndex
|
|
4677
|
+
);
|
|
4678
|
+
if (cell && (cell.rowIndex !== rowIndex || cell.columnIndex !== columnIndex))
|
|
4679
|
+
return "";
|
|
3753
4680
|
const value = readTableCell(row, column.dataIndex ?? column.key);
|
|
3754
|
-
const
|
|
3755
|
-
const
|
|
4681
|
+
const rendered = column.render?.(value, row, rowIndex, column) ?? value;
|
|
4682
|
+
const align = cssAlign(
|
|
4683
|
+
column.align ?? column.cellStyle?.textAlign ?? element.cellAlign
|
|
4684
|
+
);
|
|
4685
|
+
const vertical = column.cellStyle?.verticalAlign ?? element.cellVerticalAlign ?? "middle";
|
|
3756
4686
|
const background = cssColor(
|
|
3757
|
-
element.colors?.body?.backgroundColor,
|
|
4687
|
+
cell?.backgroundColor ?? column.cellStyle?.backgroundColor ?? element.colors?.body?.backgroundColor,
|
|
3758
4688
|
"transparent"
|
|
3759
4689
|
);
|
|
3760
|
-
const color2 = cssColor(
|
|
3761
|
-
|
|
4690
|
+
const color2 = cssColor(
|
|
4691
|
+
cell?.color ?? column.cellStyle?.color ?? element.colors?.body?.color,
|
|
4692
|
+
"#000000"
|
|
4693
|
+
);
|
|
4694
|
+
const borderStyle = tableBorderVisible(element, data, cell, row) ? cell?.borderColor ? `border-color:${cssColor(cell.borderColor, "transparent")};` : "" : "border-color:transparent;";
|
|
4695
|
+
const colSpan = Math.min(
|
|
4696
|
+
Math.max(1, cell?.colSpan ?? 1),
|
|
4697
|
+
columns.length - columnIndex
|
|
4698
|
+
);
|
|
4699
|
+
const rowSpan = Math.min(
|
|
4700
|
+
Math.max(1, cell?.rowSpan ?? 1),
|
|
4701
|
+
displayRows.length - rowIndex
|
|
4702
|
+
);
|
|
4703
|
+
const content = cell?.diagonal ? `<div style="display:flex;flex-direction:column;justify-content:space-between;width:100%;height:100%;min-height:${cssNumber(element.rowHeight, 8) * rowSpan}mm;background:linear-gradient(${cell.diagonal === "down" ? "to top right" : "to bottom right"},transparent 49.5%,${cssColor(cell.borderColor ?? element.cellBorder?.color, "#000000")} 50%,transparent 50.5%)"><span style="align-self:flex-start">${escapeHtml(cell.diagonalStart ?? cellText2(value))}</span><span style="align-self:flex-end">${escapeHtml(cell.diagonalEnd ?? "")}</span></div>` : bodyCellContent(column, rendered);
|
|
4704
|
+
return `<td colspan="${colSpan}" rowspan="${rowSpan}" style="height:${cssNumber(element.rowHeight, 8)}mm;text-align:${align};vertical-align:${vertical === "top" || vertical === "bottom" ? vertical : "middle"};background:${background};color:${color2};${borderStyle}${cellCss(column)}">${content}</td>`;
|
|
3762
4705
|
}).join("")}</tr>`
|
|
3763
4706
|
).join("");
|
|
3764
4707
|
const summary = element.showSummary === false ? /* @__PURE__ */ new Map() : computePrintTableSummaryValues(rows, columns);
|
|
3765
|
-
const summaryRow = summary.size ? `<tfoot><tr>${columns.map((column, index) => `<td style="height:${cssNumber(element.summaryRowHeight ?? element.rowHeight, 8)}mm;text-align:${cssAlign(column.align ?? element.cellAlign)};background:${cssColor(element.colors?.summary?.backgroundColor, "transparent")};color:${cssColor(element.colors?.summary?.color, "#000000")}">${
|
|
4708
|
+
const summaryRow = summary.size ? `<tfoot><tr>${columns.map((column, index) => `<td style="height:${cssNumber(element.summaryRowHeight ?? element.rowHeight, 8)}mm;text-align:${cssAlign(column.align ?? element.cellAlign)};background:${cssColor(element.colors?.summary?.backgroundColor, "transparent")};color:${cssColor(element.colors?.summary?.color, "#000000")};${cellCss(column)}">${cellContent(column, summary.get(String(column.key ?? column.dataIndex ?? index)) ?? "", Math.max(1, Number(column.width) || 100))}</td>`).join("")}</tr></tfoot>` : "";
|
|
3766
4709
|
return `<table class="pd-table" style="font-size:${fontSize}pt;--pd-border:${border}"><colgroup>${colgroup}</colgroup>${header}<tbody>${body}</tbody>${summaryRow}</table>`;
|
|
3767
4710
|
}
|
|
3768
4711
|
function chartMarkup(element, data) {
|
|
@@ -3931,7 +4874,7 @@ function elementMarkup(source, data, pageNumber) {
|
|
|
3931
4874
|
const body = element.overflowCrop ? `<div style="position:relative;top:-${cssNumber(element.overflowCrop.offset, 0)}mm;width:100%;height:${cssNumber(element.overflowCrop.fullHeight, element.height)}mm">${content}</div>` : content;
|
|
3932
4875
|
return `<div class="pd-element" style="${style}">${body}</div>`;
|
|
3933
4876
|
}
|
|
3934
|
-
function
|
|
4877
|
+
function* generatePrintHtml(document, options = {}, physicalPages, pageOffset = 0) {
|
|
3935
4878
|
const data = options.data ?? {};
|
|
3936
4879
|
const selectedPages = options.pageIds ? options.pageIds.map((id) => {
|
|
3937
4880
|
const page = document.pages.find((item) => item.id === id);
|
|
@@ -3939,10 +4882,15 @@ function transformPrintDesignToHtml(document, options = {}) {
|
|
|
3939
4882
|
return page;
|
|
3940
4883
|
}) : document.pages;
|
|
3941
4884
|
if (!selectedPages.length) throw new RangeError("\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u6253\u5370\u9875\u9762\u3002");
|
|
3942
|
-
const pages =
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
4885
|
+
const pages = physicalPages ?? [];
|
|
4886
|
+
for (let index = 0; !physicalPages && index < selectedPages.length; index++) {
|
|
4887
|
+
const result = paginatePrintDesignDocument(
|
|
4888
|
+
{ ...document, pages: [selectedPages[index]] },
|
|
4889
|
+
data
|
|
4890
|
+
).pages;
|
|
4891
|
+
for (const page of result) pages.push(page);
|
|
4892
|
+
yield (index + 1) / selectedPages.length * 0.3;
|
|
4893
|
+
}
|
|
3946
4894
|
const firstPage = pages[0];
|
|
3947
4895
|
const uniformPageSize = pages.every(
|
|
3948
4896
|
(page) => page.width === firstPage.width && page.height === firstPage.height
|
|
@@ -3968,9 +4916,15 @@ function transformPrintDesignToHtml(document, options = {}) {
|
|
|
3968
4916
|
if (!/^[\w:/?&=.%+#;,@-]+$/.test(source)) return "";
|
|
3969
4917
|
return `@font-face{font-family:${cssFont(element.fontFamily)};src:url("${source}")}`;
|
|
3970
4918
|
}).join("");
|
|
3971
|
-
const
|
|
3972
|
-
|
|
3973
|
-
|
|
4919
|
+
const parts = [];
|
|
4920
|
+
for (let index = 0; index < pages.length; index++) {
|
|
4921
|
+
const page = pages[index];
|
|
4922
|
+
parts.push(
|
|
4923
|
+
`<section class="pd-page pd-page-${index}" style="background:${cssColor(page.background, "#ffffff")}">${page.elements.map((element) => elementMarkup(element, data, pageOffset + index + 1)).join("")}</section>`
|
|
4924
|
+
);
|
|
4925
|
+
yield 0.3 + (index + 1) / pages.length * 0.7;
|
|
4926
|
+
}
|
|
4927
|
+
const markup = parts.join("");
|
|
3974
4928
|
return `<!doctype html><html><head><meta charset="utf-8"><title>${escapeHtml(document.name)}</title><style>${fontStyles}${pageStyles}*{box-sizing:border-box}html,body{margin:0;padding:0}body{-webkit-print-color-adjust:exact;print-color-adjust:exact}.pd-page{position:relative;overflow:hidden;break-after:page;page-break-after:always}.pd-page:last-child{break-after:auto;page-break-after:auto}.pd-element{position:absolute;overflow:hidden;transform-origin:center center}.pd-element>svg{display:block;width:100%;height:100%}.pd-text{text-spacing-trim:space-all;text-autospace:no-autospace;width:100%;height:100%;display:flex;flex-direction:column;white-space:pre-wrap;overflow:hidden;overflow-wrap:anywhere}.pd-media,.pd-watermark{display:block;width:100%;height:100%}.pd-media{object-fit:contain}.pd-watermark{display:grid;overflow:hidden}.pd-watermark span{display:flex;align-items:center;justify-content:center;white-space:nowrap}.pd-table{border-collapse:collapse;width:100%;table-layout:fixed}.pd-table th,.pd-table td{border:var(--pd-border);padding:0 1mm;overflow:hidden;overflow-wrap:anywhere}.pd-table th{font-weight:600}.pd-divider{position:absolute;left:0;top:50%;width:100%;height:0}.pd-element:has(>.pd-divider[style*="border-left"]){overflow:visible}.pd-element .pd-divider[style*="border-left"]{left:50%;top:0;width:0;height:100%}@media print{.pd-page{margin:0}}</style></head><body>${markup}</body></html>`;
|
|
3975
4929
|
}
|
|
3976
4930
|
function printPrintDesignHtml(popup, html) {
|
|
@@ -3992,47 +4946,73 @@ function printPrintDesignHtml(popup, html) {
|
|
|
3992
4946
|
if (popup.document.readyState === "complete") print();
|
|
3993
4947
|
else popup.addEventListener("load", print, { once: true });
|
|
3994
4948
|
}
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
const
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4949
|
+
function transformPrintDesignToHtml(document, options = {}) {
|
|
4950
|
+
const task = generatePrintHtml(document, options);
|
|
4951
|
+
let next = task.next();
|
|
4952
|
+
while (!next.done) next = task.next();
|
|
4953
|
+
return next.value;
|
|
4954
|
+
}
|
|
4955
|
+
async function transformPrintDesignToHtmlAsync(document, options = {}) {
|
|
4956
|
+
const task = generatePrintHtml(document, options);
|
|
4957
|
+
while (true) {
|
|
4958
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
4959
|
+
options.signal?.throwIfAborted();
|
|
4960
|
+
const deadline = performance.now() + 8;
|
|
4961
|
+
do {
|
|
4962
|
+
const next = task.next();
|
|
4963
|
+
if (next.done) return next.value;
|
|
4964
|
+
options.onProgress?.(next.value);
|
|
4965
|
+
} while (performance.now() < deadline);
|
|
4966
|
+
}
|
|
4967
|
+
}
|
|
4968
|
+
async function* transformPrintDesignToHtmlBatches(document, options) {
|
|
4969
|
+
const limit = Math.max(1, Math.floor(options.pagesPerBatch));
|
|
4970
|
+
if (!Number.isFinite(limit)) throw new RangeError("\u6BCF\u6B21\u6253\u5370\u9875\u6570\u5FC5\u987B\u662F\u6B63\u6574\u6570");
|
|
4971
|
+
let buffer = [];
|
|
4972
|
+
let offset = 0;
|
|
4973
|
+
const render = async () => {
|
|
4974
|
+
const task = generatePrintHtml(document, options, buffer, offset);
|
|
4975
|
+
while (true) {
|
|
4976
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
4977
|
+
options.signal?.throwIfAborted();
|
|
4978
|
+
const deadline = performance.now() + 8;
|
|
4979
|
+
do {
|
|
4980
|
+
const next = task.next();
|
|
4981
|
+
if (next.done) return next.value;
|
|
4982
|
+
} while (performance.now() < deadline);
|
|
4983
|
+
}
|
|
4026
4984
|
};
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4985
|
+
for (let index = 0; index < document.pages.length; index++) {
|
|
4986
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
4987
|
+
options.signal?.throwIfAborted();
|
|
4988
|
+
const pages = paginatePrintDesignDocument(
|
|
4989
|
+
{ ...document, pages: [document.pages[index]] },
|
|
4990
|
+
options.data ?? {}
|
|
4991
|
+
).pages;
|
|
4992
|
+
for (let pageIndex = 0; pageIndex < pages.length; pageIndex++) {
|
|
4993
|
+
buffer.push(pages[pageIndex]);
|
|
4994
|
+
if (buffer.length === limit) {
|
|
4995
|
+
const html = await render();
|
|
4996
|
+
yield {
|
|
4997
|
+
html,
|
|
4998
|
+
firstPage: offset + 1,
|
|
4999
|
+
lastPage: offset + buffer.length,
|
|
5000
|
+
hasMore: pageIndex + 1 < pages.length || index + 1 < document.pages.length
|
|
5001
|
+
};
|
|
5002
|
+
offset += buffer.length;
|
|
5003
|
+
buffer = [];
|
|
5004
|
+
options.signal?.throwIfAborted();
|
|
5005
|
+
}
|
|
5006
|
+
}
|
|
5007
|
+
options.onProgress?.((index + 1) / document.pages.length);
|
|
5008
|
+
}
|
|
5009
|
+
if (buffer.length)
|
|
5010
|
+
yield {
|
|
5011
|
+
html: await render(),
|
|
5012
|
+
firstPage: offset + 1,
|
|
5013
|
+
lastPage: offset + buffer.length,
|
|
5014
|
+
hasMore: false
|
|
5015
|
+
};
|
|
4036
5016
|
}
|
|
4037
5017
|
|
|
4038
5018
|
// src/interaction/table-column-resize.ts
|
|
@@ -4058,215 +5038,41 @@ function hitTableColumnBoundary(element, point, scale, _document) {
|
|
|
4058
5038
|
offset += widths[i];
|
|
4059
5039
|
const edge = offset * 25.4 / 96;
|
|
4060
5040
|
if (Math.abs(local.x - element.x - edge) * scale <= 5)
|
|
4061
|
-
return {
|
|
4062
|
-
elementId: element.id,
|
|
4063
|
-
boundary: i,
|
|
4064
|
-
widths,
|
|
4065
|
-
columns: element.columns,
|
|
4066
|
-
rotation: element.rotation ?? 0
|
|
4067
|
-
};
|
|
4068
|
-
}
|
|
4069
|
-
}
|
|
4070
|
-
function resizeTableColumns(session, dx, dy) {
|
|
4071
|
-
const angle = session.rotation * Math.PI / 180;
|
|
4072
|
-
const delta = (dx * Math.cos(angle) + dy * Math.sin(angle)) * 96 / 25.4;
|
|
4073
|
-
const widths = [...session.widths];
|
|
4074
|
-
const i = session.boundary;
|
|
4075
|
-
const minimum = Math.min(8, widths[i], widths[i + 1]);
|
|
4076
|
-
const change = Math.max(
|
|
4077
|
-
minimum - widths[i],
|
|
4078
|
-
Math.min(widths[i + 1] - minimum, delta)
|
|
4079
|
-
);
|
|
4080
|
-
widths[i] += change;
|
|
4081
|
-
widths[i + 1] -= change;
|
|
4082
|
-
let index = 0;
|
|
4083
|
-
const map = (columns) => columns.map((column) => {
|
|
4084
|
-
if (column.hidden) return column;
|
|
4085
|
-
if (column.children?.length)
|
|
4086
|
-
return { ...column, children: map(column.children) };
|
|
4087
|
-
const width = widths[index++];
|
|
4088
|
-
return width == null ? column : {
|
|
4089
|
-
...column,
|
|
4090
|
-
width,
|
|
4091
|
-
minWidth: Math.min(column.minWidth ?? 60, width),
|
|
4092
|
-
maxWidth: Math.max(column.maxWidth ?? 480, width)
|
|
4093
|
-
};
|
|
4094
|
-
});
|
|
4095
|
-
return map(session.columns);
|
|
4096
|
-
}
|
|
4097
|
-
|
|
4098
|
-
// src/helper/measurement-layout.ts
|
|
4099
|
-
function measurementObstacles(elements, scale) {
|
|
4100
|
-
return elements.flatMap((element) => {
|
|
4101
|
-
const rect = getSelectionRect(element, scale);
|
|
4102
|
-
const angle = element.rotation ?? 0;
|
|
4103
|
-
const corners = RESIZE_HANDLES.map(
|
|
4104
|
-
(handle) => getRotatedRectangleCorner(rect, angle, handle)
|
|
4105
|
-
);
|
|
4106
|
-
const center = { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };
|
|
4107
|
-
const stem = rotatePoint2(
|
|
4108
|
-
{ x: center.x, y: rect.y },
|
|
4109
|
-
center,
|
|
4110
|
-
angle * Math.PI / 180
|
|
4111
|
-
);
|
|
4112
|
-
const rotate = rotatePoint2(
|
|
4113
|
-
{ x: center.x, y: rect.y - 17 / scale },
|
|
4114
|
-
center,
|
|
4115
|
-
angle * Math.PI / 180
|
|
4116
|
-
);
|
|
4117
|
-
return [
|
|
4118
|
-
...[...corners, rotate].map((p) => ({
|
|
4119
|
-
x: p.x * scale - 10,
|
|
4120
|
-
y: p.y * scale - 10,
|
|
4121
|
-
width: 20,
|
|
4122
|
-
height: 20
|
|
4123
|
-
})),
|
|
4124
|
-
{
|
|
4125
|
-
x: Math.min(stem.x, rotate.x) * scale - 5,
|
|
4126
|
-
y: Math.min(stem.y, rotate.y) * scale - 5,
|
|
4127
|
-
width: Math.abs(stem.x - rotate.x) * scale + 10,
|
|
4128
|
-
height: Math.abs(stem.y - rotate.y) * scale + 10
|
|
4129
|
-
}
|
|
4130
|
-
];
|
|
4131
|
-
});
|
|
4132
|
-
}
|
|
4133
|
-
function placeMeasurement(line, textWidth, obstacles, viewport) {
|
|
4134
|
-
const horizontal = line.y1 === line.y2;
|
|
4135
|
-
const intersects = (a, b) => a.x <= b.x + b.width && a.x + a.width >= b.x && a.y <= b.y + b.height && a.y + a.height >= b.y;
|
|
4136
|
-
const limit = horizontal ? viewport.height : viewport.width;
|
|
4137
|
-
for (let step = 0; step <= Math.ceil(limit / 16); step++) {
|
|
4138
|
-
for (const sign of step === 0 ? [1] : [1, -1]) {
|
|
4139
|
-
const offset = step * 16 * sign;
|
|
4140
|
-
const x1 = line.x1 + (horizontal ? 0 : offset), x2 = line.x2 + (horizontal ? 0 : offset);
|
|
4141
|
-
const y1 = line.y1 + (horizontal ? offset : 0), y2 = line.y2 + (horizontal ? offset : 0);
|
|
4142
|
-
const textX = (x1 + x2) / 2 + 4, textY = (y1 + y2) / 2 - 4;
|
|
4143
|
-
const boxes = [
|
|
4144
|
-
{
|
|
4145
|
-
x: Math.min(x1, x2) - 3,
|
|
4146
|
-
y: Math.min(y1, y2) - 3,
|
|
4147
|
-
width: Math.abs(x2 - x1) + 6,
|
|
4148
|
-
height: Math.abs(y2 - y1) + 6
|
|
4149
|
-
},
|
|
4150
|
-
{ x: textX - 2, y: textY - 12, width: textWidth + 4, height: 16 }
|
|
4151
|
-
];
|
|
4152
|
-
if (boxes.some(
|
|
4153
|
-
(b) => b.x < 0 || b.y < 0 || b.x + b.width > viewport.width || b.y + b.height > viewport.height
|
|
4154
|
-
))
|
|
4155
|
-
continue;
|
|
4156
|
-
if (boxes.some((b) => obstacles.some((o) => intersects(b, o)))) continue;
|
|
4157
|
-
return { x1, y1, x2, y2, textX, textY };
|
|
4158
|
-
}
|
|
4159
|
-
}
|
|
4160
|
-
return null;
|
|
4161
|
-
}
|
|
4162
|
-
|
|
4163
|
-
// src/helper/alignment.ts
|
|
4164
|
-
function elementBounds(element) {
|
|
4165
|
-
const angle = (element.rotation ?? 0) * Math.PI / 180;
|
|
4166
|
-
const width = Math.abs(element.width * Math.cos(angle)) + Math.abs(element.height * Math.sin(angle));
|
|
4167
|
-
const height = Math.abs(element.width * Math.sin(angle)) + Math.abs(element.height * Math.cos(angle));
|
|
4168
|
-
return {
|
|
4169
|
-
x: element.x + (element.width - width) / 2,
|
|
4170
|
-
y: element.y + (element.height - height) / 2,
|
|
4171
|
-
width,
|
|
4172
|
-
height
|
|
4173
|
-
};
|
|
4174
|
-
}
|
|
4175
|
-
function snapCoordinate(value, targets, tolerance) {
|
|
4176
|
-
return targets.reduce(
|
|
4177
|
-
(best, target) => Math.abs(target - value) <= tolerance && Math.abs(target - value) < Math.abs(best - value) ? target : best,
|
|
4178
|
-
targets.find((target) => Math.abs(target - value) <= tolerance) ?? value
|
|
4179
|
-
);
|
|
4180
|
-
}
|
|
4181
|
-
function guideTargets(page, axis) {
|
|
4182
|
-
const vertical = axis === "vertical";
|
|
4183
|
-
const size = vertical ? page.width : page.height;
|
|
4184
|
-
const margins = page.margins ?? { top: 10, right: 10, bottom: 10, left: 10 };
|
|
4185
|
-
return [
|
|
4186
|
-
0,
|
|
4187
|
-
size / 2,
|
|
4188
|
-
size,
|
|
4189
|
-
vertical ? margins.left : margins.top,
|
|
4190
|
-
size - (vertical ? margins.right : margins.bottom),
|
|
4191
|
-
...page.elements.filter((e) => e.visible !== false).flatMap((e) => {
|
|
4192
|
-
const b = elementBounds(e);
|
|
4193
|
-
const start = vertical ? b.x : b.y, length = vertical ? b.width : b.height;
|
|
4194
|
-
return [start, start + length / 2, start + length];
|
|
4195
|
-
})
|
|
4196
|
-
];
|
|
4197
|
-
}
|
|
4198
|
-
function nearestMeasurements(page, selectedIds) {
|
|
4199
|
-
const selected = page.elements.filter((e) => selectedIds.includes(e.id) && e.visible !== false).map(elementBounds);
|
|
4200
|
-
if (!selected.length) return [];
|
|
4201
|
-
const left = Math.min(...selected.map((b) => b.x)), top = Math.min(...selected.map((b) => b.y));
|
|
4202
|
-
const right = Math.max(...selected.map((b) => b.x + b.width)), bottom = Math.max(...selected.map((b) => b.y + b.height));
|
|
4203
|
-
const result = /* @__PURE__ */ new Map();
|
|
4204
|
-
const add = (key, x1, y1, x2, y2) => {
|
|
4205
|
-
const distance = Math.hypot(x2 - x1, y2 - y1);
|
|
4206
|
-
if (!result.has(key) || distance < result.get(key).distance)
|
|
4207
|
-
result.set(key, { x1, y1, x2, y2, distance });
|
|
4208
|
-
};
|
|
4209
|
-
for (const e of page.elements) {
|
|
4210
|
-
if (selectedIds.includes(e.id) || e.visible === false) continue;
|
|
4211
|
-
const b = elementBounds(e), r = b.x + b.width, d = b.y + b.height;
|
|
4212
|
-
if (b.y <= bottom && d >= top) {
|
|
4213
|
-
const y = (Math.max(top, b.y) + Math.min(bottom, d)) / 2;
|
|
4214
|
-
if (r <= left) add("left", r, y, left, y);
|
|
4215
|
-
if (b.x >= right) add("right", right, y, b.x, y);
|
|
4216
|
-
}
|
|
4217
|
-
if (b.x <= right && r >= left) {
|
|
4218
|
-
const x = (Math.max(left, b.x) + Math.min(right, r)) / 2;
|
|
4219
|
-
if (d <= top) add("top", x, d, x, top);
|
|
4220
|
-
if (b.y >= bottom) add("bottom", x, bottom, x, b.y);
|
|
4221
|
-
}
|
|
4222
|
-
}
|
|
4223
|
-
return [...result.values()];
|
|
4224
|
-
}
|
|
4225
|
-
function drawMeasurements(context, page, selectedIds, scale, unit = "mm") {
|
|
4226
|
-
context.save();
|
|
4227
|
-
context.strokeStyle = "#e11d48";
|
|
4228
|
-
context.fillStyle = "#e11d48";
|
|
4229
|
-
context.font = "11px sans-serif";
|
|
4230
|
-
context.setLineDash([]);
|
|
4231
|
-
context.lineWidth = 1;
|
|
4232
|
-
const obstacles = measurementObstacles(
|
|
4233
|
-
page.elements.filter(
|
|
4234
|
-
(e) => selectedIds.includes(e.id) && e.visible !== false
|
|
4235
|
-
),
|
|
4236
|
-
scale
|
|
4237
|
-
);
|
|
4238
|
-
context.textAlign = "left";
|
|
4239
|
-
context.textBaseline = "alphabetic";
|
|
4240
|
-
for (const m of nearestMeasurements(page, selectedIds)) {
|
|
4241
|
-
const label = formatDisplayUnit(m.distance, unit);
|
|
4242
|
-
const placement = placeMeasurement(
|
|
4243
|
-
{
|
|
4244
|
-
x1: m.x1 * scale,
|
|
4245
|
-
y1: m.y1 * scale,
|
|
4246
|
-
x2: m.x2 * scale,
|
|
4247
|
-
y2: m.y2 * scale
|
|
4248
|
-
},
|
|
4249
|
-
context.measureText(label).width,
|
|
4250
|
-
obstacles,
|
|
4251
|
-
{ width: page.width * scale, height: page.height * scale }
|
|
4252
|
-
);
|
|
4253
|
-
if (!placement) continue;
|
|
4254
|
-
const { x1, y1, x2, y2, textX, textY } = placement;
|
|
4255
|
-
const horizontal = y1 === y2;
|
|
4256
|
-
context.beginPath();
|
|
4257
|
-
context.moveTo(x1, y1);
|
|
4258
|
-
context.lineTo(x2, y2);
|
|
4259
|
-
for (const [x, y] of [
|
|
4260
|
-
[x1, y1],
|
|
4261
|
-
[x2, y2]
|
|
4262
|
-
]) {
|
|
4263
|
-
context.moveTo(x - (horizontal ? 0 : 3), y - (horizontal ? 3 : 0));
|
|
4264
|
-
context.lineTo(x + (horizontal ? 0 : 3), y + (horizontal ? 3 : 0));
|
|
4265
|
-
}
|
|
4266
|
-
context.stroke();
|
|
4267
|
-
context.fillText(label, textX, textY);
|
|
5041
|
+
return {
|
|
5042
|
+
elementId: element.id,
|
|
5043
|
+
boundary: i,
|
|
5044
|
+
widths,
|
|
5045
|
+
columns: element.columns,
|
|
5046
|
+
rotation: element.rotation ?? 0
|
|
5047
|
+
};
|
|
4268
5048
|
}
|
|
4269
|
-
|
|
5049
|
+
}
|
|
5050
|
+
function resizeTableColumns(session, dx, dy) {
|
|
5051
|
+
const angle = session.rotation * Math.PI / 180;
|
|
5052
|
+
const delta = (dx * Math.cos(angle) + dy * Math.sin(angle)) * 96 / 25.4;
|
|
5053
|
+
const widths = [...session.widths];
|
|
5054
|
+
const i = session.boundary;
|
|
5055
|
+
const minimum = Math.min(8, widths[i], widths[i + 1]);
|
|
5056
|
+
const change = Math.max(
|
|
5057
|
+
minimum - widths[i],
|
|
5058
|
+
Math.min(widths[i + 1] - minimum, delta)
|
|
5059
|
+
);
|
|
5060
|
+
widths[i] += change;
|
|
5061
|
+
widths[i + 1] -= change;
|
|
5062
|
+
let index = 0;
|
|
5063
|
+
const map = (columns) => columns.map((column) => {
|
|
5064
|
+
if (column.hidden) return column;
|
|
5065
|
+
if (column.children?.length)
|
|
5066
|
+
return { ...column, children: map(column.children) };
|
|
5067
|
+
const width = widths[index++];
|
|
5068
|
+
return width == null ? column : {
|
|
5069
|
+
...column,
|
|
5070
|
+
width,
|
|
5071
|
+
minWidth: Math.min(column.minWidth ?? 60, width),
|
|
5072
|
+
maxWidth: Math.max(column.maxWidth ?? 480, width)
|
|
5073
|
+
};
|
|
5074
|
+
});
|
|
5075
|
+
return map(session.columns);
|
|
4270
5076
|
}
|
|
4271
5077
|
|
|
4272
5078
|
// src/helper/group-resize.ts
|
|
@@ -4449,6 +5255,94 @@ function resolvePrintDesignDebugOptions(debug) {
|
|
|
4449
5255
|
return { ...DEFAULT_PRINT_DESIGN_DEBUG_OPTIONS, ...debug };
|
|
4450
5256
|
}
|
|
4451
5257
|
|
|
5258
|
+
// src/interaction/table-selectors.ts
|
|
5259
|
+
function tableSelectors(element, data = {}) {
|
|
5260
|
+
const leaves = tableLeafColumns(element.columns).filter(
|
|
5261
|
+
(column) => !column.hidden
|
|
5262
|
+
);
|
|
5263
|
+
if (!leaves.length) return [];
|
|
5264
|
+
const widths = leaves.map((column) => Math.max(1, column.width ?? 100));
|
|
5265
|
+
const total = widths.reduce((sum, value) => sum + value, 0);
|
|
5266
|
+
const headerCount = element.showHeader === false ? 0 : tableHeaderDepth(element.columns);
|
|
5267
|
+
const rowLimit = Math.max(0, Math.floor(element.printRowCount ?? 0));
|
|
5268
|
+
const bodyCount = rowLimit ? Math.min(resolveTableRows(element, data).length, rowLimit) : resolveTableRows(element, data).length;
|
|
5269
|
+
const strip = 6;
|
|
5270
|
+
const selectors = [
|
|
5271
|
+
{
|
|
5272
|
+
kind: "all",
|
|
5273
|
+
index: 0,
|
|
5274
|
+
x: element.x - strip,
|
|
5275
|
+
y: element.y - strip,
|
|
5276
|
+
width: strip,
|
|
5277
|
+
height: strip,
|
|
5278
|
+
label: "\u25E2"
|
|
5279
|
+
}
|
|
5280
|
+
];
|
|
5281
|
+
let left = element.x;
|
|
5282
|
+
for (const [index, width] of widths.entries()) {
|
|
5283
|
+
const actualWidth = element.width * width / total;
|
|
5284
|
+
let number = index + 1;
|
|
5285
|
+
let label = "";
|
|
5286
|
+
while (number > 0) {
|
|
5287
|
+
number--;
|
|
5288
|
+
label = String.fromCharCode(65 + number % 26) + label;
|
|
5289
|
+
number = Math.floor(number / 26);
|
|
5290
|
+
}
|
|
5291
|
+
selectors.push({
|
|
5292
|
+
kind: "column",
|
|
5293
|
+
index,
|
|
5294
|
+
x: left,
|
|
5295
|
+
y: element.y - strip,
|
|
5296
|
+
width: actualWidth,
|
|
5297
|
+
height: strip,
|
|
5298
|
+
label
|
|
5299
|
+
});
|
|
5300
|
+
left += actualWidth;
|
|
5301
|
+
}
|
|
5302
|
+
let top = element.y;
|
|
5303
|
+
for (let index = 0; index < headerCount; index++) {
|
|
5304
|
+
selectors.push({
|
|
5305
|
+
kind: "row",
|
|
5306
|
+
area: "header",
|
|
5307
|
+
index,
|
|
5308
|
+
x: element.x - strip,
|
|
5309
|
+
y: top,
|
|
5310
|
+
width: strip,
|
|
5311
|
+
height: element.headerRowHeight ?? 9,
|
|
5312
|
+
label: `H${index + 1}`
|
|
5313
|
+
});
|
|
5314
|
+
top += element.headerRowHeight ?? 9;
|
|
5315
|
+
}
|
|
5316
|
+
for (let index = 0; index < bodyCount; index++) {
|
|
5317
|
+
selectors.push({
|
|
5318
|
+
kind: "row",
|
|
5319
|
+
area: "body",
|
|
5320
|
+
index,
|
|
5321
|
+
x: element.x - strip,
|
|
5322
|
+
y: top,
|
|
5323
|
+
width: strip,
|
|
5324
|
+
height: element.rowHeight ?? 8,
|
|
5325
|
+
label: String(index + 1)
|
|
5326
|
+
});
|
|
5327
|
+
top += element.rowHeight ?? 8;
|
|
5328
|
+
}
|
|
5329
|
+
return selectors;
|
|
5330
|
+
}
|
|
5331
|
+
function hitTableSelector(element, point, data = {}) {
|
|
5332
|
+
const center = {
|
|
5333
|
+
x: element.x + element.width / 2,
|
|
5334
|
+
y: element.y + resolvedTableHeight(element, data) / 2
|
|
5335
|
+
};
|
|
5336
|
+
const local = rotatePoint2(
|
|
5337
|
+
point,
|
|
5338
|
+
center,
|
|
5339
|
+
-(element.rotation ?? 0) * Math.PI / 180
|
|
5340
|
+
);
|
|
5341
|
+
return tableSelectors(element, data).find(
|
|
5342
|
+
(selector) => local.x >= selector.x && local.x < selector.x + selector.width && local.y >= selector.y && local.y < selector.y + selector.height
|
|
5343
|
+
);
|
|
5344
|
+
}
|
|
5345
|
+
|
|
4452
5346
|
// src/interaction/selection.ts
|
|
4453
5347
|
function shouldPrioritizeSelectionHandle(hitElementId, selectedElementIds) {
|
|
4454
5348
|
return hitElementId === void 0 || selectedElementIds.includes(hitElementId);
|
|
@@ -4950,13 +5844,16 @@ var PrintDesignTextEditor = class {
|
|
|
4950
5844
|
function canEditTable(element) {
|
|
4951
5845
|
return element.type === "table" && element.dataMode !== "binding" && !element.locked && element.visible !== false;
|
|
4952
5846
|
}
|
|
4953
|
-
function hitTableCell(element, point, document) {
|
|
5847
|
+
function hitTableCell(element, point, document, data = {}) {
|
|
4954
5848
|
const ctx = document.createElement("canvas").getContext("2d");
|
|
4955
5849
|
if (!ctx) return;
|
|
4956
5850
|
const scale = 96 / 25.4;
|
|
4957
5851
|
const local = rotatePoint2(
|
|
4958
5852
|
point,
|
|
4959
|
-
{
|
|
5853
|
+
{
|
|
5854
|
+
x: element.x + element.width / 2,
|
|
5855
|
+
y: element.y + resolvedTableHeight(element, data) / 2
|
|
5856
|
+
},
|
|
4960
5857
|
-(element.rotation ?? 0) * Math.PI / 180
|
|
4961
5858
|
);
|
|
4962
5859
|
const x = (local.x - element.x) * scale;
|
|
@@ -4966,14 +5863,14 @@ function hitTableCell(element, point, document) {
|
|
|
4966
5863
|
x: 0,
|
|
4967
5864
|
y: 0,
|
|
4968
5865
|
width: element.width * scale,
|
|
4969
|
-
height: element
|
|
5866
|
+
height: resolvedTableHeight(element, data) * scale,
|
|
4970
5867
|
scale,
|
|
4971
|
-
data
|
|
5868
|
+
data
|
|
4972
5869
|
}).find(
|
|
4973
5870
|
({ rect }) => x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height
|
|
4974
5871
|
);
|
|
4975
5872
|
}
|
|
4976
|
-
function tableCellText(element, cell, text) {
|
|
5873
|
+
function tableCellText(element, cell, text, data = {}) {
|
|
4977
5874
|
const scale = 96 / 25.4;
|
|
4978
5875
|
const { rect, column } = cell;
|
|
4979
5876
|
const width = rect.width / scale;
|
|
@@ -4983,7 +5880,10 @@ function tableCellText(element, cell, text) {
|
|
|
4983
5880
|
x: element.x + rect.x / scale + width / 2,
|
|
4984
5881
|
y: element.y + rect.y / scale + height / 2
|
|
4985
5882
|
},
|
|
4986
|
-
{
|
|
5883
|
+
{
|
|
5884
|
+
x: element.x + element.width / 2,
|
|
5885
|
+
y: element.y + resolvedTableHeight(element, data) / 2
|
|
5886
|
+
},
|
|
4987
5887
|
(element.rotation ?? 0) * Math.PI / 180
|
|
4988
5888
|
);
|
|
4989
5889
|
return {
|
|
@@ -4996,7 +5896,7 @@ function tableCellText(element, cell, text) {
|
|
|
4996
5896
|
height,
|
|
4997
5897
|
rotation: element.rotation,
|
|
4998
5898
|
fontSize: element.fontSize ?? 10,
|
|
4999
|
-
textAlign: column.align === "right" ? "right" : column.align === "center" ? "center" : "left",
|
|
5899
|
+
textAlign: (column.align ?? column.cellStyle?.textAlign ?? element.cellAlign) === "right" ? "right" : (column.align ?? column.cellStyle?.textAlign ?? element.cellAlign) === "center" ? "center" : "left",
|
|
5000
5900
|
verticalAlign: column.cellStyle?.verticalAlign ?? element.cellVerticalAlign ?? "middle",
|
|
5001
5901
|
color: element.colors?.body?.color
|
|
5002
5902
|
};
|
|
@@ -5025,11 +5925,70 @@ function parseTableCell(text, initial) {
|
|
|
5025
5925
|
var PrintDesignTableEditing = class extends PrintDesignBase {
|
|
5026
5926
|
constructor() {
|
|
5027
5927
|
super(...arguments);
|
|
5928
|
+
__publicField(this, "tableCellSelection", null);
|
|
5028
5929
|
__publicField(this, "tableEditing", null);
|
|
5029
5930
|
}
|
|
5931
|
+
/** 返回表格单元格选区,供右键菜单与选区绘制使用。 */
|
|
5932
|
+
getTableCellSelection() {
|
|
5933
|
+
return this.tableCellSelection && { ...this.tableCellSelection };
|
|
5934
|
+
}
|
|
5935
|
+
/** 选择表格整行、整列或全部单元格。 */
|
|
5936
|
+
selectTableSelector(elementId, kind, index = 0, area = "body") {
|
|
5937
|
+
const element = this.getActivePage().elements.find(
|
|
5938
|
+
(item) => item.id === elementId
|
|
5939
|
+
);
|
|
5940
|
+
if (element?.type !== "table") return this;
|
|
5941
|
+
const columns = tableLeafColumns(element.columns).filter(
|
|
5942
|
+
(item) => !item.hidden
|
|
5943
|
+
).length;
|
|
5944
|
+
const rows = resolveTableRows(element, this.options.data).length;
|
|
5945
|
+
const headerRows = element.showHeader === false ? 0 : tableHeaderDepth(element.columns);
|
|
5946
|
+
if (!columns || kind === "column" && (index < 0 || index >= columns) || kind === "row" && (index < 0 || index >= (area === "header" ? headerRows : rows)))
|
|
5947
|
+
return this;
|
|
5948
|
+
this.tableCellSelection = {
|
|
5949
|
+
elementId,
|
|
5950
|
+
area: kind === "row" ? area : "body",
|
|
5951
|
+
selectorKind: kind,
|
|
5952
|
+
startRow: kind === "row" ? index : 0,
|
|
5953
|
+
endRow: kind === "row" ? index : Math.max(0, rows - 1),
|
|
5954
|
+
startColumn: kind === "column" ? index : 0,
|
|
5955
|
+
endColumn: kind === "column" ? index : columns - 1
|
|
5956
|
+
};
|
|
5957
|
+
this.selectElements([elementId]);
|
|
5958
|
+
return this;
|
|
5959
|
+
}
|
|
5960
|
+
/** 选中一个单元格,按 Shift 扩展为矩形区域。 */
|
|
5961
|
+
selectTableCellAtPoint(element, point, extend = false) {
|
|
5962
|
+
const cell = hitTableCell(
|
|
5963
|
+
element,
|
|
5964
|
+
point,
|
|
5965
|
+
this.host.ownerDocument,
|
|
5966
|
+
this.options.data
|
|
5967
|
+
);
|
|
5968
|
+
if (!cell) return false;
|
|
5969
|
+
const current = this.tableCellSelection;
|
|
5970
|
+
if (extend && current?.elementId === element.id && current.area === cell.area) {
|
|
5971
|
+
this.tableCellSelection = {
|
|
5972
|
+
...current,
|
|
5973
|
+
endRow: cell.rowIndex,
|
|
5974
|
+
endColumn: cell.columnIndex
|
|
5975
|
+
};
|
|
5976
|
+
} else {
|
|
5977
|
+
this.tableCellSelection = {
|
|
5978
|
+
elementId: element.id,
|
|
5979
|
+
area: cell.area,
|
|
5980
|
+
startRow: cell.rowIndex,
|
|
5981
|
+
endRow: cell.rowIndex,
|
|
5982
|
+
startColumn: cell.columnIndex,
|
|
5983
|
+
endColumn: cell.columnIndex
|
|
5984
|
+
};
|
|
5985
|
+
}
|
|
5986
|
+
return true;
|
|
5987
|
+
}
|
|
5030
5988
|
beginTableEditing(element, point) {
|
|
5031
5989
|
const cell = hitTableCell(element, point, this.host.ownerDocument);
|
|
5032
|
-
if (!cell || !element.dataSource[cell.rowIndex])
|
|
5990
|
+
if (!cell || cell.area !== "body" || !element.dataSource[cell.rowIndex])
|
|
5991
|
+
return;
|
|
5033
5992
|
this.tableEditing?.editor.finish(false);
|
|
5034
5993
|
this.selectElements([element.id]);
|
|
5035
5994
|
const initial = readTableCell(
|
|
@@ -5074,7 +6033,10 @@ var PrintDesignTableEditing = class extends PrintDesignBase {
|
|
|
5074
6033
|
}
|
|
5075
6034
|
);
|
|
5076
6035
|
this.tableEditing = { editor, cell, snapshot };
|
|
5077
|
-
editor.mount(
|
|
6036
|
+
editor.mount(
|
|
6037
|
+
tableCellText(element, cell, text, this.options.data),
|
|
6038
|
+
this.pageOrigin()
|
|
6039
|
+
);
|
|
5078
6040
|
this.render();
|
|
5079
6041
|
}
|
|
5080
6042
|
/** 外部变更和选中状态变化使草稿失效;缩放、平移则同步浮层位置。 */
|
|
@@ -5089,7 +6051,12 @@ var PrintDesignTableEditing = class extends PrintDesignBase {
|
|
|
5089
6051
|
return;
|
|
5090
6052
|
}
|
|
5091
6053
|
session.editor.update(
|
|
5092
|
-
tableCellText(
|
|
6054
|
+
tableCellText(
|
|
6055
|
+
element,
|
|
6056
|
+
session.cell,
|
|
6057
|
+
session.editor.initialText,
|
|
6058
|
+
this.options.data
|
|
6059
|
+
),
|
|
5093
6060
|
this.pageOrigin()
|
|
5094
6061
|
);
|
|
5095
6062
|
}
|
|
@@ -5367,6 +6334,48 @@ var PrintDesignRenderer = class extends PrintDesignTextEditing {
|
|
|
5367
6334
|
drawPrintDesignBindingIndicator(ctx, element, scale, this.options);
|
|
5368
6335
|
}
|
|
5369
6336
|
ctx.restore();
|
|
6337
|
+
if (!preview && !this.options.readonly && this.selectedElementIds.length === 1) {
|
|
6338
|
+
const table = page.elements.find(
|
|
6339
|
+
(item) => item.id === this.selectedElementIds[0]
|
|
6340
|
+
);
|
|
6341
|
+
if (table?.type === "table" && table.visible !== false) {
|
|
6342
|
+
const active = this.tableCellSelection?.elementId === table.id ? this.tableCellSelection : null;
|
|
6343
|
+
ctx.save();
|
|
6344
|
+
const centerX = (table.x + table.width / 2) * scale;
|
|
6345
|
+
const centerY = (table.y + resolvedTableHeight(table, this.options.data) / 2) * scale;
|
|
6346
|
+
ctx.translate(centerX, centerY);
|
|
6347
|
+
ctx.rotate((table.rotation ?? 0) * Math.PI / 180);
|
|
6348
|
+
ctx.translate(-centerX, -centerY);
|
|
6349
|
+
ctx.textAlign = "center";
|
|
6350
|
+
ctx.textBaseline = "middle";
|
|
6351
|
+
ctx.font = `${Math.max(8, Math.min(11, 9 * this.zoom))}px sans-serif`;
|
|
6352
|
+
for (const selector of tableSelectors(table, this.options.data)) {
|
|
6353
|
+
const selected = active && (active.selectorKind === "all" || selector.kind === "column" && active.selectorKind === "column" && selector.index === active.startColumn || selector.kind === "row" && active.selectorKind === "row" && selector.area === active.area && selector.index === active.startRow);
|
|
6354
|
+
ctx.fillStyle = selected ? "#dbeafe" : "#f1f5f9";
|
|
6355
|
+
ctx.strokeStyle = "#94a3b8";
|
|
6356
|
+
ctx.lineWidth = 1;
|
|
6357
|
+
ctx.fillRect(
|
|
6358
|
+
selector.x * scale,
|
|
6359
|
+
selector.y * scale,
|
|
6360
|
+
selector.width * scale,
|
|
6361
|
+
selector.height * scale
|
|
6362
|
+
);
|
|
6363
|
+
ctx.strokeRect(
|
|
6364
|
+
selector.x * scale,
|
|
6365
|
+
selector.y * scale,
|
|
6366
|
+
selector.width * scale,
|
|
6367
|
+
selector.height * scale
|
|
6368
|
+
);
|
|
6369
|
+
ctx.fillStyle = selected ? "#1677ff" : "#475569";
|
|
6370
|
+
ctx.fillText(
|
|
6371
|
+
selector.label,
|
|
6372
|
+
(selector.x + selector.width / 2) * scale,
|
|
6373
|
+
(selector.y + selector.height / 2) * scale
|
|
6374
|
+
);
|
|
6375
|
+
}
|
|
6376
|
+
ctx.restore();
|
|
6377
|
+
}
|
|
6378
|
+
}
|
|
5370
6379
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
5371
6380
|
drawPrintDesignGuideExtensions({
|
|
5372
6381
|
guideColor: this.options.guideColor,
|
|
@@ -5482,7 +6491,7 @@ var PrintDesignRenderer = class extends PrintDesignTextEditing {
|
|
|
5482
6491
|
if (!element || !resolvePrintDesignElementVisible(element, this.options.data))
|
|
5483
6492
|
continue;
|
|
5484
6493
|
const rotation = (element.rotation ?? 0) * Math.PI / 180;
|
|
5485
|
-
const selectionRect = getSelectionRect(element, scale);
|
|
6494
|
+
const selectionRect = getSelectionRect(element, scale, this.options.data);
|
|
5486
6495
|
const x = selectionRect.x * scale;
|
|
5487
6496
|
const y = selectionRect.y * scale;
|
|
5488
6497
|
const width = selectionRect.width * scale;
|
|
@@ -5498,6 +6507,7 @@ var PrintDesignRenderer = class extends PrintDesignTextEditing {
|
|
|
5498
6507
|
ctx.setLineDash([2, 1.5]);
|
|
5499
6508
|
ctx.strokeRect(x, y, width, height);
|
|
5500
6509
|
ctx.setLineDash([]);
|
|
6510
|
+
if (element.type === "table") this.drawTableCellSelection(element, scale);
|
|
5501
6511
|
const rotateHandleY = y - 17;
|
|
5502
6512
|
ctx.beginPath();
|
|
5503
6513
|
ctx.moveTo(cx, y);
|
|
@@ -5539,6 +6549,69 @@ var PrintDesignRenderer = class extends PrintDesignTextEditing {
|
|
|
5539
6549
|
ctx.restore();
|
|
5540
6550
|
}
|
|
5541
6551
|
}
|
|
6552
|
+
drawTableCellSelection(element, scale) {
|
|
6553
|
+
const selection = this.tableCellSelection;
|
|
6554
|
+
if (!selection || selection.elementId !== element.id) return;
|
|
6555
|
+
const visible = tableLeafColumns(
|
|
6556
|
+
element.columns.filter((column) => !column.hidden)
|
|
6557
|
+
).filter((column) => !column.hidden);
|
|
6558
|
+
const weights = visible.map((column) => Math.max(1, column.width ?? 100));
|
|
6559
|
+
const total = weights.reduce((sum, value) => sum + value, 0);
|
|
6560
|
+
if (selection.selectorKind === "all" || selection.selectorKind === "column") {
|
|
6561
|
+
if (total <= 0) return;
|
|
6562
|
+
const left2 = selection.selectorKind === "all" ? element.x : element.x + element.width * weights.slice(0, selection.startColumn).reduce((sum, value) => sum + value, 0) / total;
|
|
6563
|
+
const width = selection.selectorKind === "all" ? element.width : element.width * (weights[selection.startColumn] ?? 0) / total;
|
|
6564
|
+
const ctx2 = this.context;
|
|
6565
|
+
ctx2.fillStyle = "rgba(22,119,255,0.12)";
|
|
6566
|
+
ctx2.strokeStyle = "#1677ff";
|
|
6567
|
+
ctx2.fillRect(
|
|
6568
|
+
left2 * scale,
|
|
6569
|
+
element.y * scale,
|
|
6570
|
+
width * scale,
|
|
6571
|
+
resolvedTableHeight(element, this.options.data) * scale
|
|
6572
|
+
);
|
|
6573
|
+
ctx2.strokeRect(
|
|
6574
|
+
left2 * scale,
|
|
6575
|
+
element.y * scale,
|
|
6576
|
+
width * scale,
|
|
6577
|
+
resolvedTableHeight(element, this.options.data) * scale
|
|
6578
|
+
);
|
|
6579
|
+
return;
|
|
6580
|
+
}
|
|
6581
|
+
const isHeader = selection.area === "header";
|
|
6582
|
+
const rows = resolveTableRows(element, this.options.data);
|
|
6583
|
+
const limit = Math.max(0, Math.floor(element.printRowCount ?? 0));
|
|
6584
|
+
const resolvedCells = isHeader ? tableHeaderCells(element) : resolveTableCells(
|
|
6585
|
+
element,
|
|
6586
|
+
limit ? rows.slice(0, limit) : rows,
|
|
6587
|
+
visible
|
|
6588
|
+
);
|
|
6589
|
+
const bounds = expandTableCellSelection(resolvedCells, selection);
|
|
6590
|
+
const firstColumn = Math.max(0, bounds.firstColumn);
|
|
6591
|
+
const lastColumn = Math.min(visible.length - 1, bounds.lastColumn);
|
|
6592
|
+
if (total <= 0 || lastColumn < firstColumn) return;
|
|
6593
|
+
const firstRow = Math.max(0, bounds.firstRow);
|
|
6594
|
+
const lastRow = bounds.lastRow;
|
|
6595
|
+
const left = element.x + element.width * weights.slice(0, firstColumn).reduce((sum, value) => sum + value, 0) / total;
|
|
6596
|
+
const right = element.x + element.width * weights.slice(0, lastColumn + 1).reduce((sum, value) => sum + value, 0) / total;
|
|
6597
|
+
const top = element.y + (isHeader || element.showHeader === false ? 0 : tableHeaderDepth(element.columns) * (element.headerRowHeight ?? 9)) + firstRow * (isHeader ? element.headerRowHeight ?? 9 : element.rowHeight ?? 8);
|
|
6598
|
+
const height = (lastRow - firstRow + 1) * (isHeader ? element.headerRowHeight ?? 9 : element.rowHeight ?? 8);
|
|
6599
|
+
const ctx = this.context;
|
|
6600
|
+
ctx.fillStyle = "rgba(22,119,255,0.12)";
|
|
6601
|
+
ctx.strokeStyle = "#1677ff";
|
|
6602
|
+
ctx.fillRect(
|
|
6603
|
+
left * scale,
|
|
6604
|
+
top * scale,
|
|
6605
|
+
(right - left) * scale,
|
|
6606
|
+
height * scale
|
|
6607
|
+
);
|
|
6608
|
+
ctx.strokeRect(
|
|
6609
|
+
left * scale,
|
|
6610
|
+
top * scale,
|
|
6611
|
+
(right - left) * scale,
|
|
6612
|
+
height * scale
|
|
6613
|
+
);
|
|
6614
|
+
}
|
|
5542
6615
|
/** 组合四边控制柄与外部图层重叠时,优先保留其它图层的选择。 */
|
|
5543
6616
|
hitTestGroupResizeHandle(point, page, scale) {
|
|
5544
6617
|
if (this.options.readonly || page.elements.some(
|
|
@@ -5560,7 +6633,9 @@ var PrintDesignRenderer = class extends PrintDesignTextEditing {
|
|
|
5560
6633
|
if (!element || element.groupPath?.length || element.locked || !resolvePrintDesignElementVisible(element, this.options.data))
|
|
5561
6634
|
return void 0;
|
|
5562
6635
|
const tolerance = 8 / scale;
|
|
5563
|
-
const selectionRect = getSelectionRect(element, scale);
|
|
6636
|
+
const selectionRect = getSelectionRect(element, scale, this.options.data);
|
|
6637
|
+
if (element.type === "table" && point.y > selectionRect.y + 2 / scale && point.y < selectionRect.y + selectionRect.height - 2 / scale && hitTableColumnBoundary(element, point, scale, this.host.ownerDocument))
|
|
6638
|
+
return void 0;
|
|
5564
6639
|
for (const handle of RESIZE_HANDLES) {
|
|
5565
6640
|
const corner = getRotatedRectangleCorner(
|
|
5566
6641
|
selectionRect,
|
|
@@ -5579,7 +6654,7 @@ var PrintDesignRenderer = class extends PrintDesignTextEditing {
|
|
|
5579
6654
|
);
|
|
5580
6655
|
if (!element || element.groupPath?.length || element.locked || !resolvePrintDesignElementVisible(element, this.options.data))
|
|
5581
6656
|
return void 0;
|
|
5582
|
-
const selectionRect = getSelectionRect(element, scale);
|
|
6657
|
+
const selectionRect = getSelectionRect(element, scale, this.options.data);
|
|
5583
6658
|
const center = {
|
|
5584
6659
|
x: selectionRect.x + selectionRect.width / 2,
|
|
5585
6660
|
y: selectionRect.y + selectionRect.height / 2
|
|
@@ -5593,7 +6668,7 @@ var PrintDesignRenderer = class extends PrintDesignTextEditing {
|
|
|
5593
6668
|
}
|
|
5594
6669
|
getRotatedCorner(element, handle, scale) {
|
|
5595
6670
|
return getRotatedRectangleCorner(
|
|
5596
|
-
getSelectionRect(element, scale),
|
|
6671
|
+
getSelectionRect(element, scale, this.options.data),
|
|
5597
6672
|
element.rotation ?? 0,
|
|
5598
6673
|
handle
|
|
5599
6674
|
);
|
|
@@ -5699,6 +6774,27 @@ var PrintDesignInteraction = class extends PrintDesignRenderer {
|
|
|
5699
6774
|
return;
|
|
5700
6775
|
}
|
|
5701
6776
|
}
|
|
6777
|
+
if (!this.options.readonly && !event.metaKey && !event.ctrlKey) {
|
|
6778
|
+
const selectedTable = [...page.elements].reverse().find(
|
|
6779
|
+
(item) => item.type === "table" && this.selectedElementIds.includes(item.id)
|
|
6780
|
+
);
|
|
6781
|
+
if (selectedTable?.type === "table") {
|
|
6782
|
+
const selector = hitTableSelector(
|
|
6783
|
+
selectedTable,
|
|
6784
|
+
point,
|
|
6785
|
+
this.options.data
|
|
6786
|
+
);
|
|
6787
|
+
if (selector) {
|
|
6788
|
+
this.selectTableSelector(
|
|
6789
|
+
selectedTable.id,
|
|
6790
|
+
selector.kind,
|
|
6791
|
+
selector.index,
|
|
6792
|
+
selector.area
|
|
6793
|
+
);
|
|
6794
|
+
return;
|
|
6795
|
+
}
|
|
6796
|
+
}
|
|
6797
|
+
}
|
|
5702
6798
|
const hit = hitTestPrintDesignPage(
|
|
5703
6799
|
page,
|
|
5704
6800
|
point,
|
|
@@ -5765,7 +6861,7 @@ var PrintDesignInteraction = class extends PrintDesignRenderer {
|
|
|
5765
6861
|
x: element.x,
|
|
5766
6862
|
y: element.y,
|
|
5767
6863
|
width: element.width,
|
|
5768
|
-
height: element.height
|
|
6864
|
+
height: element.type === "table" ? resolvedTableHeight(element, this.options.data) : element.height
|
|
5769
6865
|
},
|
|
5770
6866
|
anchor,
|
|
5771
6867
|
rotation: element.rotation ?? 0
|
|
@@ -5780,7 +6876,7 @@ var PrintDesignInteraction = class extends PrintDesignRenderer {
|
|
|
5780
6876
|
);
|
|
5781
6877
|
return;
|
|
5782
6878
|
}
|
|
5783
|
-
if (!this.options.readonly && (hit?.type === "table" || hit?.type === "pivotTable") &&
|
|
6879
|
+
if (!this.options.readonly && (hit?.type === "table" || hit?.type === "pivotTable") && !event.shiftKey && !event.metaKey && !event.ctrlKey) {
|
|
5784
6880
|
const tableColumn = hitTableColumnBoundary(
|
|
5785
6881
|
hit.type === "pivotTable" ? materializePivotTable(hit, this.options.data) : hit,
|
|
5786
6882
|
point,
|
|
@@ -5788,6 +6884,11 @@ var PrintDesignInteraction = class extends PrintDesignRenderer {
|
|
|
5788
6884
|
this.container.ownerDocument
|
|
5789
6885
|
);
|
|
5790
6886
|
if (tableColumn) {
|
|
6887
|
+
if (this.selectedElementIds.length !== 1 || this.selectedElementIds[0] !== hit.id) {
|
|
6888
|
+
this.selectedElementIds = [hit.id];
|
|
6889
|
+
this.emitSelection();
|
|
6890
|
+
this.render();
|
|
6891
|
+
}
|
|
5791
6892
|
this.canvas.setPointerCapture?.(event.pointerId);
|
|
5792
6893
|
this.dragSession = {
|
|
5793
6894
|
mode: "table-column",
|
|
@@ -5803,6 +6904,13 @@ var PrintDesignInteraction = class extends PrintDesignRenderer {
|
|
|
5803
6904
|
return;
|
|
5804
6905
|
}
|
|
5805
6906
|
}
|
|
6907
|
+
if (hit?.type === "table" && !this.options.readonly && !hit.locked && !event.metaKey && !event.ctrlKey) {
|
|
6908
|
+
if (this.selectTableCellAtPoint(hit, point, event.shiftKey) && event.shiftKey) {
|
|
6909
|
+
this.selectElements([hit.id]);
|
|
6910
|
+
this.render();
|
|
6911
|
+
return;
|
|
6912
|
+
}
|
|
6913
|
+
}
|
|
5806
6914
|
if (!hit) {
|
|
5807
6915
|
const initialIds = event.shiftKey || event.metaKey || event.ctrlKey ? [...this.selectedElementIds] : [];
|
|
5808
6916
|
this.selectedElementIds = initialIds;
|
|
@@ -6273,6 +7381,15 @@ var PrintDesignInteraction = class extends PrintDesignRenderer {
|
|
|
6273
7381
|
return;
|
|
6274
7382
|
}
|
|
6275
7383
|
const insidePage = cursorPoint.x >= 0 && cursorPoint.y >= 0 && cursorPoint.x <= page.width && cursorPoint.y <= page.height;
|
|
7384
|
+
if (!this.spacePressed && !this.options.readonly && this.selectedElementIds.length === 1) {
|
|
7385
|
+
const table = page.elements.find(
|
|
7386
|
+
(item) => item.id === this.selectedElementIds[0]
|
|
7387
|
+
);
|
|
7388
|
+
if (table?.type === "table" && hitTableSelector(table, cursorPoint, this.options.data)) {
|
|
7389
|
+
this.canvas.style.cursor = "pointer";
|
|
7390
|
+
return;
|
|
7391
|
+
}
|
|
7392
|
+
}
|
|
6276
7393
|
if (this.spacePressed || !insidePage) {
|
|
6277
7394
|
this.canvas.style.cursor = "grab";
|
|
6278
7395
|
return;
|
|
@@ -6318,7 +7435,7 @@ var PrintDesignInteraction = class extends PrintDesignRenderer {
|
|
|
6318
7435
|
return;
|
|
6319
7436
|
}
|
|
6320
7437
|
}
|
|
6321
|
-
if (!this.options.readonly && (hit?.type === "table" || hit?.type === "pivotTable") &&
|
|
7438
|
+
if (!this.options.readonly && (hit?.type === "table" || hit?.type === "pivotTable") && !event.shiftKey && !event.metaKey && !event.ctrlKey && hitTableColumnBoundary(
|
|
6322
7439
|
hit.type === "pivotTable" ? materializePivotTable(hit, this.options.data) : hit,
|
|
6323
7440
|
cursorPoint,
|
|
6324
7441
|
origin.scale,
|
|
@@ -6380,6 +7497,24 @@ var PrintDesignInteraction = class extends PrintDesignRenderer {
|
|
|
6380
7497
|
element.y = Math.round((center.y - height / 2) * 100) / 100;
|
|
6381
7498
|
element.width = Math.round(width * 100) / 100;
|
|
6382
7499
|
element.height = Math.round(height * 100) / 100;
|
|
7500
|
+
if (element.type === "table" && vertical) {
|
|
7501
|
+
const totalRows = resolveTableRows(element, this.options.data).length;
|
|
7502
|
+
const limit = Math.max(0, Math.floor(element.printRowCount ?? 0));
|
|
7503
|
+
const count = Math.max(
|
|
7504
|
+
limit ? Math.min(totalRows, limit) : totalRows,
|
|
7505
|
+
element.fillEmptyRows ? limit : 0,
|
|
7506
|
+
1
|
|
7507
|
+
);
|
|
7508
|
+
const header = element.showHeader === false ? 0 : tableHeaderDepth(element.columns) * (element.headerRowHeight ?? 9);
|
|
7509
|
+
const summary = tableContentHeight(
|
|
7510
|
+
{ ...element, fillEmptyRows: false, printRowCount: 0 },
|
|
7511
|
+
0
|
|
7512
|
+
) - header;
|
|
7513
|
+
element.rowHeight = Math.max(
|
|
7514
|
+
1,
|
|
7515
|
+
Math.round((height - header - summary) / count * 100) / 100
|
|
7516
|
+
);
|
|
7517
|
+
}
|
|
6383
7518
|
}
|
|
6384
7519
|
};
|
|
6385
7520
|
function oppositeResizeHandle(handle) {
|
|
@@ -6571,12 +7706,244 @@ function alignPrintDesignLayers(page, ids, align) {
|
|
|
6571
7706
|
});
|
|
6572
7707
|
}
|
|
6573
7708
|
|
|
7709
|
+
// src/model/table-structure.ts
|
|
7710
|
+
function insertTableColumn(columns, index, column) {
|
|
7711
|
+
const copy = structuredClone(columns);
|
|
7712
|
+
let position = 0;
|
|
7713
|
+
const walk = (items) => {
|
|
7714
|
+
for (let i = 0; i < items.length; i++) {
|
|
7715
|
+
const item = items[i];
|
|
7716
|
+
if (item.hidden) continue;
|
|
7717
|
+
const children = item.children?.filter((child) => !child.hidden);
|
|
7718
|
+
if (children?.length) {
|
|
7719
|
+
if (walk(item.children)) return true;
|
|
7720
|
+
} else {
|
|
7721
|
+
if (position === index) {
|
|
7722
|
+
items.splice(i, 0, column);
|
|
7723
|
+
return true;
|
|
7724
|
+
}
|
|
7725
|
+
position++;
|
|
7726
|
+
}
|
|
7727
|
+
}
|
|
7728
|
+
if (position === index && items === copy) {
|
|
7729
|
+
items.push(column);
|
|
7730
|
+
return true;
|
|
7731
|
+
}
|
|
7732
|
+
return false;
|
|
7733
|
+
};
|
|
7734
|
+
walk(copy);
|
|
7735
|
+
return copy;
|
|
7736
|
+
}
|
|
7737
|
+
function shiftTableCells(cells, axis, index) {
|
|
7738
|
+
return cells?.map((cell) => {
|
|
7739
|
+
const start = axis === "row" ? cell.rowIndex : cell.columnIndex;
|
|
7740
|
+
const span = axis === "row" ? cell.rowSpan ?? 1 : cell.colSpan ?? 1;
|
|
7741
|
+
if (start >= index)
|
|
7742
|
+
return {
|
|
7743
|
+
...cell,
|
|
7744
|
+
[axis === "row" ? "rowIndex" : "columnIndex"]: start + 1
|
|
7745
|
+
};
|
|
7746
|
+
if (start + span > index)
|
|
7747
|
+
return { ...cell, [axis === "row" ? "rowSpan" : "colSpan"]: span + 1 };
|
|
7748
|
+
return cell;
|
|
7749
|
+
});
|
|
7750
|
+
}
|
|
7751
|
+
function emptyTableRow(element) {
|
|
7752
|
+
return tableLeafColumns(element.columns).filter((column) => !column.hidden).reduce(
|
|
7753
|
+
(row, column) => writeTableCell(
|
|
7754
|
+
row,
|
|
7755
|
+
column.dataIndex,
|
|
7756
|
+
["money", "progress", "rate"].includes(column.cellType ?? "") ? 0 : ["checkbox", "radio", "switch"].includes(column.cellType ?? "") ? false : ""
|
|
7757
|
+
),
|
|
7758
|
+
{}
|
|
7759
|
+
);
|
|
7760
|
+
}
|
|
7761
|
+
|
|
6574
7762
|
// src/engine/print-design-actions.ts
|
|
6575
7763
|
var PrintDesignActions = class extends PrintDesignGrouping {
|
|
6576
7764
|
constructor() {
|
|
6577
7765
|
super(...arguments);
|
|
6578
7766
|
__publicField(this, "elementClipboard", []);
|
|
6579
7767
|
}
|
|
7768
|
+
/** 定位画布中的行、列或全选选择器。 */
|
|
7769
|
+
tableSelectorAtClientPoint(clientX, clientY) {
|
|
7770
|
+
if (this.selectedElementIds.length !== 1 || this.options.readonly)
|
|
7771
|
+
return null;
|
|
7772
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
7773
|
+
const origin = this.pageOrigin();
|
|
7774
|
+
const point = {
|
|
7775
|
+
x: (clientX - rect.left - origin.x) / origin.scale,
|
|
7776
|
+
y: (clientY - rect.top - origin.y) / origin.scale
|
|
7777
|
+
};
|
|
7778
|
+
for (const item of [...this.getActivePage().elements].reverse()) {
|
|
7779
|
+
if (item.type !== "table" || item.visible === false || !this.selectedElementIds.includes(item.id))
|
|
7780
|
+
continue;
|
|
7781
|
+
const selector = hitTableSelector(item, point, this.options.data);
|
|
7782
|
+
if (selector)
|
|
7783
|
+
return {
|
|
7784
|
+
elementId: item.id,
|
|
7785
|
+
kind: selector.kind,
|
|
7786
|
+
index: selector.index,
|
|
7787
|
+
area: selector.area
|
|
7788
|
+
};
|
|
7789
|
+
}
|
|
7790
|
+
return null;
|
|
7791
|
+
}
|
|
7792
|
+
/** 定位画布右键所指的表头或表体单元格。 */
|
|
7793
|
+
tableCellAtClientPoint(clientX, clientY) {
|
|
7794
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
7795
|
+
const origin = this.pageOrigin();
|
|
7796
|
+
const point = {
|
|
7797
|
+
x: (clientX - rect.left - origin.x) / origin.scale,
|
|
7798
|
+
y: (clientY - rect.top - origin.y) / origin.scale
|
|
7799
|
+
};
|
|
7800
|
+
const hit = hitTestPrintDesignPage(
|
|
7801
|
+
this.getActivePage(),
|
|
7802
|
+
point,
|
|
7803
|
+
0,
|
|
7804
|
+
this.options.data
|
|
7805
|
+
);
|
|
7806
|
+
if (hit?.type !== "table") return null;
|
|
7807
|
+
const cell = hitTableCell(
|
|
7808
|
+
hit,
|
|
7809
|
+
point,
|
|
7810
|
+
this.host.ownerDocument,
|
|
7811
|
+
this.options.data
|
|
7812
|
+
);
|
|
7813
|
+
return cell ? {
|
|
7814
|
+
elementId: hit.id,
|
|
7815
|
+
area: cell.area,
|
|
7816
|
+
rowIndex: cell.rowIndex,
|
|
7817
|
+
columnIndex: cell.columnIndex
|
|
7818
|
+
} : null;
|
|
7819
|
+
}
|
|
7820
|
+
/** 合并右键单元格与相邻单元格;变更纳入撤销历史。 */
|
|
7821
|
+
mergeTableCell(elementId, rowIndex, columnIndex, rowSpan, colSpan) {
|
|
7822
|
+
if (this.options.readonly) return this;
|
|
7823
|
+
const element = this.getActivePage().elements.find(
|
|
7824
|
+
(item) => item.id === elementId
|
|
7825
|
+
);
|
|
7826
|
+
if (element?.type !== "table" || element.locked) return this;
|
|
7827
|
+
const rows = resolveTableRows(element, this.options.data);
|
|
7828
|
+
const columns = tableLeafColumns(element.columns).filter(
|
|
7829
|
+
(item) => !item.hidden
|
|
7830
|
+
);
|
|
7831
|
+
if (rowIndex < 0 || columnIndex < 0 || rowIndex + rowSpan > rows.length || columnIndex + colSpan > columns.length)
|
|
7832
|
+
return this;
|
|
7833
|
+
if (Array.from(
|
|
7834
|
+
{ length: rowSpan },
|
|
7835
|
+
(_, r) => Array.from(
|
|
7836
|
+
{ length: colSpan },
|
|
7837
|
+
(_2, c) => coveringTableCell(element.cells, rowIndex + r, columnIndex + c)
|
|
7838
|
+
)
|
|
7839
|
+
).flat().some(
|
|
7840
|
+
(cell) => cell && (cell.rowIndex !== rowIndex || cell.columnIndex !== columnIndex) && ((cell.rowSpan ?? 1) > 1 || (cell.colSpan ?? 1) > 1)
|
|
7841
|
+
))
|
|
7842
|
+
return this;
|
|
7843
|
+
this.commitMutation((document) => {
|
|
7844
|
+
const target = this.getPageIn(document).elements.find(
|
|
7845
|
+
(item) => item.id === elementId
|
|
7846
|
+
);
|
|
7847
|
+
if (target?.type !== "table") return;
|
|
7848
|
+
const previous = target.cells?.find(
|
|
7849
|
+
(cell) => cell.rowIndex === rowIndex && cell.columnIndex === columnIndex
|
|
7850
|
+
);
|
|
7851
|
+
target.cells = [
|
|
7852
|
+
...(target.cells ?? []).filter((cell) => cell !== previous),
|
|
7853
|
+
{ ...previous, rowIndex, columnIndex, rowSpan, colSpan }
|
|
7854
|
+
];
|
|
7855
|
+
});
|
|
7856
|
+
return this;
|
|
7857
|
+
}
|
|
7858
|
+
/** 合并表头选区,保留左上角单元格标题。 */
|
|
7859
|
+
mergeTableHeaderCell(elementId, rowIndex, columnIndex, rowSpan, colSpan) {
|
|
7860
|
+
if (this.options.readonly) return this;
|
|
7861
|
+
const element = this.getActivePage().elements.find(
|
|
7862
|
+
(item) => item.id === elementId
|
|
7863
|
+
);
|
|
7864
|
+
if (element?.type !== "table" || element.locked || element.showHeader === false)
|
|
7865
|
+
return this;
|
|
7866
|
+
const depth = tableHeaderDepth(element.columns);
|
|
7867
|
+
const columns = tableLeafColumns(element.columns).filter(
|
|
7868
|
+
(item) => !item.hidden
|
|
7869
|
+
).length;
|
|
7870
|
+
if (rowIndex < 0 || columnIndex < 0 || rowSpan < 1 || colSpan < 1 || rowIndex + rowSpan > depth || columnIndex + colSpan > columns)
|
|
7871
|
+
return this;
|
|
7872
|
+
if (rowSpan * colSpan > 1) {
|
|
7873
|
+
const cells = tableHeaderCells(element);
|
|
7874
|
+
const intersects = (cell) => cell.rowIndex < rowIndex + rowSpan && cell.rowIndex + cell.rowSpan > rowIndex && cell.columnIndex < columnIndex + colSpan && cell.columnIndex + cell.colSpan > columnIndex;
|
|
7875
|
+
if (!cells.some(
|
|
7876
|
+
(cell) => cell.rowIndex === rowIndex && cell.columnIndex === columnIndex
|
|
7877
|
+
) || cells.some(
|
|
7878
|
+
(cell) => intersects(cell) && (cell.rowIndex < rowIndex || cell.columnIndex < columnIndex || cell.rowIndex + cell.rowSpan > rowIndex + rowSpan || cell.columnIndex + cell.colSpan > columnIndex + colSpan)
|
|
7879
|
+
))
|
|
7880
|
+
return this;
|
|
7881
|
+
}
|
|
7882
|
+
this.commitMutation((document) => {
|
|
7883
|
+
const target = this.getPageIn(document).elements.find(
|
|
7884
|
+
(item) => item.id === elementId
|
|
7885
|
+
);
|
|
7886
|
+
if (target?.type !== "table") return;
|
|
7887
|
+
target.headerCells = [
|
|
7888
|
+
...(target.headerCells ?? []).filter(
|
|
7889
|
+
(cell) => rowSpan * colSpan === 1 ? cell.rowIndex !== rowIndex || cell.columnIndex !== columnIndex : cell.rowIndex < rowIndex || cell.columnIndex < columnIndex || cell.rowIndex + (cell.rowSpan ?? 1) > rowIndex + rowSpan || cell.columnIndex + (cell.colSpan ?? 1) > columnIndex + colSpan
|
|
7890
|
+
),
|
|
7891
|
+
...rowSpan * colSpan > 1 ? [{ rowIndex, columnIndex, rowSpan, colSpan }] : []
|
|
7892
|
+
];
|
|
7893
|
+
});
|
|
7894
|
+
return this;
|
|
7895
|
+
}
|
|
7896
|
+
/** 在静态表格指定数据行的上方或下方插入空行。 */
|
|
7897
|
+
insertTableRow(elementId, rowIndex, after = true) {
|
|
7898
|
+
if (this.options.readonly) return this;
|
|
7899
|
+
const element = this.getActivePage().elements.find(
|
|
7900
|
+
(item) => item.id === elementId
|
|
7901
|
+
);
|
|
7902
|
+
if (element?.type !== "table" || element.locked || element.dataMode === "binding")
|
|
7903
|
+
return this;
|
|
7904
|
+
const index = Math.max(
|
|
7905
|
+
0,
|
|
7906
|
+
Math.min(element.dataSource.length, rowIndex + (after ? 1 : 0))
|
|
7907
|
+
);
|
|
7908
|
+
this.commitMutation((document) => {
|
|
7909
|
+
const target = this.getPageIn(document).elements.find(
|
|
7910
|
+
(item) => item.id === elementId
|
|
7911
|
+
);
|
|
7912
|
+
if (target?.type !== "table") return;
|
|
7913
|
+
target.dataSource.splice(index, 0, emptyTableRow(target));
|
|
7914
|
+
target.cells = shiftTableCells(target.cells, "row", index);
|
|
7915
|
+
});
|
|
7916
|
+
return this;
|
|
7917
|
+
}
|
|
7918
|
+
/** 在可见叶列的左侧或右侧插入空白列。 */
|
|
7919
|
+
insertTableColumn(elementId, columnIndex, after = true) {
|
|
7920
|
+
if (this.options.readonly) return this;
|
|
7921
|
+
const element = this.getActivePage().elements.find(
|
|
7922
|
+
(item) => item.id === elementId
|
|
7923
|
+
);
|
|
7924
|
+
if (element?.type !== "table" || element.locked) return this;
|
|
7925
|
+
const leaves = tableLeafColumns(element.columns).filter(
|
|
7926
|
+
(item) => !item.hidden
|
|
7927
|
+
);
|
|
7928
|
+
if (columnIndex < 0 || columnIndex >= leaves.length) return this;
|
|
7929
|
+
const index = columnIndex + (after ? 1 : 0);
|
|
7930
|
+
const key = createPrintDesignId("column");
|
|
7931
|
+
this.commitMutation((document) => {
|
|
7932
|
+
const target = this.getPageIn(document).elements.find(
|
|
7933
|
+
(item) => item.id === elementId
|
|
7934
|
+
);
|
|
7935
|
+
if (target?.type !== "table") return;
|
|
7936
|
+
target.columns = insertTableColumn(target.columns, index, {
|
|
7937
|
+
key,
|
|
7938
|
+
dataIndex: key,
|
|
7939
|
+
title: "\u65B0\u5217",
|
|
7940
|
+
width: leaves[columnIndex]?.width ?? 100
|
|
7941
|
+
});
|
|
7942
|
+
target.cells = shiftTableCells(target.cells, "column", index);
|
|
7943
|
+
target.headerCells = shiftTableCells(target.headerCells, "column", index);
|
|
7944
|
+
});
|
|
7945
|
+
return this;
|
|
7946
|
+
}
|
|
6580
7947
|
/** 画布右键命中选区;点中已选项保留多选,空白清空选区。 */
|
|
6581
7948
|
selectAtClientPoint(clientX, clientY) {
|
|
6582
7949
|
const rect = this.canvas.getBoundingClientRect(), origin = this.pageOrigin();
|
|
@@ -6592,10 +7959,24 @@ var PrintDesignActions = class extends PrintDesignGrouping {
|
|
|
6592
7959
|
this.options.data
|
|
6593
7960
|
);
|
|
6594
7961
|
if (hit) {
|
|
7962
|
+
if (hit.type === "table") {
|
|
7963
|
+
const cell = hitTableCell(
|
|
7964
|
+
hit,
|
|
7965
|
+
point,
|
|
7966
|
+
this.host.ownerDocument,
|
|
7967
|
+
this.options.data
|
|
7968
|
+
);
|
|
7969
|
+
const selected = this.tableCellSelection;
|
|
7970
|
+
if (cell && (!selected || selected.elementId !== hit.id || selected.area !== cell.area || cell.rowIndex < Math.min(selected.startRow, selected.endRow) || cell.rowIndex > Math.max(selected.startRow, selected.endRow) || cell.columnIndex < Math.min(selected.startColumn, selected.endColumn) || cell.columnIndex > Math.max(selected.startColumn, selected.endColumn)))
|
|
7971
|
+
this.selectTableCellAtPoint(hit, point);
|
|
7972
|
+
} else this.tableCellSelection = null;
|
|
6595
7973
|
this.selectElements(
|
|
6596
7974
|
this.selectedElementIds.includes(hit.id) ? this.selectedElementIds : [hit.id]
|
|
6597
7975
|
);
|
|
6598
|
-
} else
|
|
7976
|
+
} else {
|
|
7977
|
+
this.tableCellSelection = null;
|
|
7978
|
+
this.selectElements([]);
|
|
7979
|
+
}
|
|
6599
7980
|
return this;
|
|
6600
7981
|
}
|
|
6601
7982
|
/** 复制选中元素,保留组合、数据及样式,不使用系统剪贴板。 */
|
|
@@ -6736,12 +8117,50 @@ var PrintDesignActions = class extends PrintDesignGrouping {
|
|
|
6736
8117
|
|
|
6737
8118
|
// src/engine/print-design.ts
|
|
6738
8119
|
var PrintDesign = class extends PrintDesignActions {
|
|
8120
|
+
constructor() {
|
|
8121
|
+
super(...arguments);
|
|
8122
|
+
__publicField(this, "temporaryDocumentSnapshot", null);
|
|
8123
|
+
}
|
|
8124
|
+
/** 临时显示演示文档;原文档、选区与撤销记录保留在实例中。 */
|
|
8125
|
+
showTemporaryDocument(document, pageId, elementId) {
|
|
8126
|
+
this.temporaryDocumentSnapshot ?? (this.temporaryDocumentSnapshot = {
|
|
8127
|
+
document: this.getDocument(),
|
|
8128
|
+
activePageId: this.activePageId,
|
|
8129
|
+
elementIds: [...this.selectedElementIds],
|
|
8130
|
+
guide: this.selectedGuide ? { ...this.selectedGuide } : null
|
|
8131
|
+
});
|
|
8132
|
+
this.document = parsePrintDesignDocument(document);
|
|
8133
|
+
this.activePageId = pageId && this.document.pages.some((page) => page.id === pageId) ? pageId : this.document.pages[0].id;
|
|
8134
|
+
this.selectedElementIds = elementId && this.document.pages.find((page) => page.id === this.activePageId)?.elements.some((item) => item.id === elementId) ? [elementId] : [];
|
|
8135
|
+
this.selectedGuide = null;
|
|
8136
|
+
this.options.onActivePageChange?.(this.activePageId);
|
|
8137
|
+
this.emitSelection();
|
|
8138
|
+
this.emitChange();
|
|
8139
|
+
this.render();
|
|
8140
|
+
return this;
|
|
8141
|
+
}
|
|
8142
|
+
/** 恢复临时演示前的文档和选区,保留原有撤销记录。 */
|
|
8143
|
+
restoreTemporaryDocument() {
|
|
8144
|
+
const saved = this.temporaryDocumentSnapshot;
|
|
8145
|
+
if (!saved) return this;
|
|
8146
|
+
this.temporaryDocumentSnapshot = null;
|
|
8147
|
+
this.document = saved.document;
|
|
8148
|
+
this.activePageId = saved.activePageId;
|
|
8149
|
+
this.selectedElementIds = saved.elementIds;
|
|
8150
|
+
this.selectedGuide = saved.guide;
|
|
8151
|
+
this.options.onActivePageChange?.(this.activePageId);
|
|
8152
|
+
this.emitSelection();
|
|
8153
|
+
this.emitChange();
|
|
8154
|
+
this.render();
|
|
8155
|
+
return this;
|
|
8156
|
+
}
|
|
6739
8157
|
/** 获取文档副本。 */
|
|
6740
8158
|
getDocument() {
|
|
6741
8159
|
return clonePrintDesignDocument(this.document);
|
|
6742
8160
|
}
|
|
6743
8161
|
/** 替换当前文档并清空撤销历史。 */
|
|
6744
8162
|
setDocument(document) {
|
|
8163
|
+
this.temporaryDocumentSnapshot = null;
|
|
6745
8164
|
this.document = parsePrintDesignDocument(document);
|
|
6746
8165
|
this.activePageId = this.document.pages[0].id;
|
|
6747
8166
|
this.selectedElementIds = [];
|
|
@@ -6869,6 +8288,22 @@ var PrintDesign = class extends PrintDesignActions {
|
|
|
6869
8288
|
y: (y - origin.y) / origin.scale
|
|
6870
8289
|
};
|
|
6871
8290
|
}
|
|
8291
|
+
/** 获取当前页元素在浏览器视口中的包围盒,包含旋转后的占用范围。 */
|
|
8292
|
+
getElementClientRect(elementId) {
|
|
8293
|
+
const element = this.getActivePage().elements.find(
|
|
8294
|
+
(item) => item.id === elementId
|
|
8295
|
+
);
|
|
8296
|
+
if (!element || element.visible === false) return null;
|
|
8297
|
+
const bounds = elementBounds(element);
|
|
8298
|
+
const origin = this.pageOrigin();
|
|
8299
|
+
const canvas = this.canvas.getBoundingClientRect();
|
|
8300
|
+
return {
|
|
8301
|
+
left: canvas.left + origin.x + bounds.x * origin.scale,
|
|
8302
|
+
top: canvas.top + origin.y + bounds.y * origin.scale,
|
|
8303
|
+
width: bounds.width * origin.scale,
|
|
8304
|
+
height: bounds.height * origin.scale
|
|
8305
|
+
};
|
|
8306
|
+
}
|
|
6872
8307
|
/** 新增元素并选中。 */
|
|
6873
8308
|
addElement(element) {
|
|
6874
8309
|
const next = { ...element, id: element.id ?? createPrintDesignId() };
|
|
@@ -7094,4 +8529,4 @@ function getPrintDesignPageSize(page) {
|
|
|
7094
8529
|
return { width: page.width, height: page.height };
|
|
7095
8530
|
}
|
|
7096
8531
|
|
|
7097
|
-
export { DEFAULT_PRINT_DESIGN_DEBUG_OPTIONS, PRINT_DESIGN_CSS_DPI, PRINT_DESIGN_MM_PER_INCH, PRINT_DESIGN_SCHEMA_VERSION, PRINT_DESIGN_UNIT_MM, PrintDesign, buildPrintDesignLayerTree, canvasPointToPageMillimeters, computePrintTableSummaryValues, createPrintDesignDocument, createPrintDesignId, createPrintDesignPage, drawPrintDesignElement, drawPrintDesignPage, findPrintPivotFieldArea, formatDisplayUnit, fromDisplayUnit, getPrintDesignAlignmentUnits, getPrintDesignDataFields, getPrintDesignElementDataConfig, getPrintDesignPageSize, hitTestPrintDesignPage, isGanttTasks, isPrintDesignChartDataSource, isPrintDesignTableDataSource, materializePivotTable, millimetersToPixels, movePrintPivotField, normalizeGridCount, paginatePrintDesignDocument, parsePrintDesignDocument, pixelsToMillimeters, printPivotFieldHeaderTitle, printPivotFieldTitle, printPivotValueTitle, printPrintDesignHtml, readChartData, readTableCell, removePrintPivotField, renderPrintDesignPageToCanvas, resizeGridCells, resolveChartOption, resolveDesignText, resolveGanttDependencies, resolveGanttTasks, resolveGridCells, resolvePivotRows, resolvePrintDesignBinding, resolvePrintDesignDataPath, resolvePrintDesignDebugOptions, resolvePrintDesignElementData, resolvePrintDesignElementVisible, resolveTableDataSource, resolveTableRows, serializePrintDesignDocument, tableLeafColumns, toDisplayUnit, transformPrintDesignToHtml, writeTableCell };
|
|
8532
|
+
export { DEFAULT_PRINT_DESIGN_DEBUG_OPTIONS, PRINT_DESIGN_CSS_DPI, PRINT_DESIGN_MM_PER_INCH, PRINT_DESIGN_SCHEMA_VERSION, PRINT_DESIGN_UNIT_MM, PrintDesign, buildPrintDesignLayerTree, canvasPointToPageMillimeters, computePrintTableSummaryValues, createPrintDesignDocument, createPrintDesignId, createPrintDesignPage, drawPrintDesignElement, drawPrintDesignPage, findPrintPivotFieldArea, formatDisplayUnit, fromDisplayUnit, getPrintDesignAlignmentUnits, getPrintDesignDataFields, getPrintDesignElementDataConfig, getPrintDesignPageSize, hitTestPrintDesignPage, isGanttTasks, isPrintDesignChartDataSource, isPrintDesignTableDataSource, materializePivotTable, millimetersToPixels, movePrintPivotField, normalizeGridCount, paginatePrintDesignDocument, parsePrintDesignDocument, pixelsToMillimeters, printPivotFieldHeaderTitle, printPivotFieldTitle, printPivotValueTitle, printPrintDesignHtml, readChartData, readTableCell, removePrintPivotField, renderPrintDesignPageToCanvas, resizeGridCells, resolveChartOption, resolveDesignText, resolveGanttDependencies, resolveGanttTasks, resolveGridCells, resolvePivotRows, resolvePrintDesignBinding, resolvePrintDesignDataPath, resolvePrintDesignDebugOptions, resolvePrintDesignElementData, resolvePrintDesignElementVisible, resolveTableDataSource, resolveTableRows, serializePrintDesignDocument, tableLeafColumns, toDisplayUnit, transformPrintDesignToHtml, transformPrintDesignToHtmlAsync, transformPrintDesignToHtmlBatches, writeTableCell };
|