表格提取
大约 4 分钟
表格提取
从 CAD 图纸中自动识别并提取表格数据。
概念
extractTables() 函数可以自动识别图纸中由直线和文字构成的表格,提取表格结构和单元格数据。
支持识别:
- 由 Line/Polyline 构成的表格边框
- 单元格中的 Text/MText 内容
- 合并单元格
基本用法
全图提取
const { extractTables } = vjcad;
// 全图提取(最简单)
const result = extractTables();
if (result.error) {
console.error("提取失败:", result.error);
} else if (result.tables.length === 0) {
console.log("未识别到表格数据");
} else {
console.log(`识别到 ${result.tables.length} 个表格`);
result.tables.forEach((table, index) => {
console.log(`=== 表格 ${index + 1} ===`);
console.log(`行数: ${table.rowCount}, 列数: ${table.colCount}`);
// 打印表格数据
for (let r = 0; r < table.rowCount; r++) {
const row = table.datas[r] || [];
console.log(`第${r + 1}行:`, row.join(' | '));
}
});
}指定区域提取
const result = extractTables({
bounds: {
minX: 0,
minY: -200,
maxX: 500,
maxY: 100
}
});指定图层提取
const result = extractTables({
layers: ['表格图层', '标注层']
});完整参数
const result = extractTables({
// 提取范围(可选)
bounds: { minX: 0, minY: -200, maxX: 500, maxY: 100 },
// 指定图层(可选)
layers: ['图层1', '图层2'],
// 包含的实体类型
includeLine: true, // 包含直线(默认 true)
includePolyline: true, // 包含多段线(默认 true)
includeText: true, // 包含单行文字(默认 true)
includeMText: true, // 包含多行文字(默认 true)
// 识别参数
digit: 2, // 小数精度(默认 2)
tol: 0, // 误差值(0 为自动)
tableEdgeMinPoint: 8, // 表格边线最少端点数
tableTextMinCount: 2, // 表格最少文字数
// 调试
debug: false // 调试模式
});返回数据结构
返回值
interface ExtractTablesResult {
error?: string; // 错误信息
tables: TableData[]; // 表格数组
}表格数据
interface TableData {
rowCount: number; // 行数
colCount: number; // 列数
rect: { // 表格范围
minX: number;
minY: number;
maxX: number;
maxY: number;
};
datas: string[][]; // 单元格数据 [行][列]
spans?: { // 合并单元格信息
[key: string]: {
rowSpan: number;
colSpan: number;
}
};
}示例:绘制并提取表格
const {
MainView, initCadContainer,
LineEnt, TextEnt, TextAlignmentEnum,
Engine, extractTables, message
} = vjcad;
// 初始化
const cadView = new MainView({
appname: "唯杰CAD",
version: "v1.0.0",
serviceUrl: env.serviceUrl,
accessToken: env.accessToken,
sidebarStyle: "none"
});
initCadContainer("map", cadView);
await cadView.onLoad();
// === 1. 绘制表格 ===
const tableStartX = 0;
const tableStartY = 0;
const cellWidth = 100;
const cellHeight = 40;
const rows = 3;
const cols = 4;
// 表格数据
const tableData = [
['序号', '名称', '数量', '单位'],
['1', '钢筋', '100', '吨'],
['2', '混凝土', '500', '立方米']
];
// 绘制水平线
for (let r = 0; r <= rows; r++) {
const y = tableStartY - r * cellHeight;
const line = new LineEnt(
[tableStartX, y],
[tableStartX + cols * cellWidth, y]
);
line.setDefaults();
Engine.addEntities(line);
}
// 绘制垂直线
for (let c = 0; c <= cols; c++) {
const x = tableStartX + c * cellWidth;
const line = new LineEnt(
[x, tableStartY],
[x, tableStartY - rows * cellHeight]
);
line.setDefaults();
Engine.addEntities(line);
}
// 填充文字内容
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const text = new TextEnt();
text.text = tableData[r][c];
text.insertionPoint = [
tableStartX + c * cellWidth + cellWidth / 2,
tableStartY - r * cellHeight - cellHeight / 2
];
text.height = 15;
text.textAlignment = TextAlignmentEnum.MidCenter;
text.setDefaults();
Engine.addEntities(text);
}
}
Engine.zoomExtents();
message.info("表格已绘制完成");
// === 2. 提取表格 ===
const result = extractTables();
if (result.tables.length > 0) {
const table = result.tables[0];
message.info(`识别到表格: ${table.rowCount}行 x ${table.colCount}列`);
// 打印表头
if (table.datas && table.datas[0]) {
message.info("表头: " + table.datas[0].join(', '));
}
// 遍历数据
for (let r = 0; r < table.rowCount; r++) {
const row = table.datas[r] || [];
console.log(`第${r + 1}行:`, row);
}
}处理合并单元格
const result = extractTables();
result.tables.forEach(table => {
// 检查合并单元格
if (table.spans && Object.keys(table.spans).length > 0) {
console.log("合并单元格信息:", table.spans);
// spans 格式: { "row_col": { rowSpan: 2, colSpan: 1 } }
for (const [key, span] of Object.entries(table.spans)) {
const [row, col] = key.split('_').map(Number);
console.log(`单元格 [${row},${col}] 合并: ${span.rowSpan}行 x ${span.colSpan}列`);
}
}
});导出为 JSON/CSV
导出为 JSON
const result = extractTables();
if (result.tables.length > 0) {
const table = result.tables[0];
const json = JSON.stringify(table.datas, null, 2);
console.log(json);
}导出为 CSV
const result = extractTables();
if (result.tables.length > 0) {
const table = result.tables[0];
const csv = table.datas.map(row => row.join(',')).join('\n');
console.log(csv);
// 下载 CSV 文件
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'table.csv';
a.click();
URL.revokeObjectURL(url);
}注意事项
- 表格结构:函数只能识别由直线/多段线构成的规则表格
- 文字位置:文字必须在单元格范围内才能被正确归类
- 误差容限:复杂图纸可能需要调整
tol参数 - 性能:大型图纸建议使用
bounds或layers限制范围
API 参考
extractTables(options?)
| 参数 | 类型 | 说明 |
|---|---|---|
bounds | object | 提取范围 {minX, minY, maxX, maxY} |
layers | string[] | 指定图层 |
includeLine | boolean | 包含直线(默认 true) |
includePolyline | boolean | 包含多段线(默认 true) |
includeText | boolean | 包含单行文字(默认 true) |
includeMText | boolean | 包含多行文字(默认 true) |
digit | number | 小数精度(默认 2) |
tol | number | 误差值(0 为自动) |
tableEdgeMinPoint | number | 表格边线最少端点数(默认 8) |
tableTextMinCount | number | 表格最少文字数(默认 2) |
debug | boolean | 调试模式 |
返回值
| 字段 | 类型 | 说明 |
|---|---|---|
error | string | 错误信息(可选) |
tables | TableData[] | 表格数据数组 |
TableData
| 字段 | 类型 | 说明 |
|---|---|---|
rowCount | number | 行数 |
colCount | number | 列数 |
rect | object | 表格范围 |
datas | string[][] | 单元格数据 [行][列] |
spans | object | 合并单元格信息 |