Table Extraction
About 3 min
Table Extraction
Automatically recognize and extract table data from CAD drawings.
Concepts
The extractTables() function can automatically recognize tables composed of lines and text in a drawing, then extract table structure and cell data.
Supported recognition includes:
- Table borders composed of
Line/Polyline Text/MTextcontent inside cells- Merged cells
Basic Usage
Extract from Entire Drawing
const { extractTables } = vjcad;
// Extract from the entire drawing (simplest case)
const result = extractTables();
if (result.error) {
console.error("Extraction failed:", result.error);
} else if (result.tables.length === 0) {
console.log("No table data recognized");
} else {
console.log(`Recognized ${result.tables.length} tables`);
result.tables.forEach((table, index) => {
console.log(`=== Table ${index + 1} ===`);
console.log(`Rows: ${table.rowCount}, Columns: ${table.colCount}`);
// Print table data
for (let r = 0; r < table.rowCount; r++) {
const row = table.datas[r] || [];
console.log(`Row ${r + 1}:`, row.join(' | '));
}
});
}Extract from Specified Region
const result = extractTables({
bounds: {
minX: 0,
minY: -200,
maxX: 500,
maxY: 100
}
});Extract from Specified Layers
const result = extractTables({
layers: ['TableLayer', 'AnnotationLayer']
});Full Parameters
const result = extractTables({
// Extraction range (optional)
bounds: { minX: 0, minY: -200, maxX: 500, maxY: 100 },
// Specify layers (optional)
layers: ['Layer1', 'Layer2'],
// Included entity types
includeLine: true, // Include lines (default true)
includePolyline: true, // Include polylines (default true)
includeText: true, // Include single-line text (default true)
includeMText: true, // Include multi-line text (default true)
// Recognition parameters
digit: 2, // Decimal precision (default 2)
tol: 0, // Tolerance (0 = auto)
tableEdgeMinPoint: 8, // Minimum endpoint count of table border lines
tableTextMinCount: 2, // Minimum text count in a table
// Debug
debug: false // Debug mode
});Return Data Structure
Return Value
interface ExtractTablesResult {
error?: string; // Error message
tables: TableData[]; // Table array
}Table Data
interface TableData {
rowCount: number; // Row count
colCount: number; // Column count
rect: { // Table bounds
minX: number;
minY: number;
maxX: number;
maxY: number;
};
datas: string[][]; // Cell data [row][column]
spans?: { // Merged cell info
[key: string]: {
rowSpan: number;
colSpan: number;
}
};
}Example: Draw and Extract a Table
const {
MainView, initCadContainer,
LineEnt, TextEnt, TextAlignmentEnum,
Engine, extractTables, message
} = vjcad;
// Initialize
const cadView = new MainView({
appname: "VJ CAD",
version: "v1.0.0",
serviceUrl: env.serviceUrl,
accessToken: env.accessToken,
sidebarStyle: "none"
});
initCadContainer("map", cadView);
await cadView.onLoad();
// === 1. Draw table ===
const tableStartX = 0;
const tableStartY = 0;
const cellWidth = 100;
const cellHeight = 40;
const rows = 3;
const cols = 4;
// Table data
const tableData = [
['No.', 'Name', 'Quantity', 'Unit'],
['1', 'Rebar', '100', 'ton'],
['2', 'Concrete', '500', 'm3']
];
// Draw horizontal lines
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);
}
// Draw vertical lines
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);
}
// Fill in text content
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("Table drawn successfully");
// === 2. Extract table ===
const result = extractTables();
if (result.tables.length > 0) {
const table = result.tables[0];
message.info(`Recognized table: ${table.rowCount} rows x ${table.colCount} columns`);
// Print header
if (table.datas && table.datas[0]) {
message.info("Header: " + table.datas[0].join(', '));
}
// Iterate data
for (let r = 0; r < table.rowCount; r++) {
const row = table.datas[r] || [];
console.log(`Row ${r + 1}:`, row);
}
}Handle Merged Cells
const result = extractTables();
result.tables.forEach(table => {
// Check merged cells
if (table.spans && Object.keys(table.spans).length > 0) {
console.log("Merged cell info:", table.spans);
// spans format: { "row_col": { rowSpan: 2, colSpan: 1 } }
for (const [key, span] of Object.entries(table.spans)) {
const [row, col] = key.split('_').map(Number);
console.log(`Cell [${row},${col}] merged: ${span.rowSpan} rows x ${span.colSpan} cols`);
}
}
});Export to JSON / CSV
Export to 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);
}Export to 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);
// Download CSV file
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);
}Notes
- Table structure: the function only recognizes regular tables composed of lines/polylines
- Text position: text must be inside the cell bounds to be classified correctly
- Tolerance: for complex drawings, you may need to adjust the
tolparameter - Performance: for large drawings, use
boundsorlayersto limit the scope
API Reference
extractTables(options?)
| Parameter | Type | Description |
|---|---|---|
bounds | object | Extraction range {minX, minY, maxX, maxY} |
layers | string[] | Specify layers |
includeLine | boolean | Include lines (default true) |
includePolyline | boolean | Include polylines (default true) |
includeText | boolean | Include single-line text (default true) |
includeMText | boolean | Include multi-line text (default true) |
digit | number | Decimal precision (default 2) |
tol | number | Tolerance (0 = auto) |
tableEdgeMinPoint | number | Minimum endpoint count of table border lines (default 8) |
tableTextMinCount | number | Minimum text count in a table (default 2) |
debug | boolean | Debug mode |
Return Value
| Field | Type | Description |
|---|---|---|
error | string | Error message (optional) |
tables | TableData[] | Table data array |
TableData
| Field | Type | Description |
|---|---|---|
rowCount | number | Row count |
colCount | number | Column count |
rect | object | Table bounds |
datas | string[][] | Cell data [row][column] |
spans | object | Merged cell info |