- Split styles.css (1319 lines) into 6 CSS modules: - base.css, layout.css, modal.css, text-generator.css, components.css, legend.css - Split app.js (1219 lines) into 8 JS modules: - core.js, custom.js, dxf.js, export.js, legend.js, legend-export.js, path-parser.js, utils.js - Split symbols.js (870 lines) into 10 JS modules: - index.js, schaeden.js, werkzeuge.js, bauteile.js, moebel.js, sanitaer.js, vermessung.js, vermessung-infra.js, vermessung-topo.js, init.js - Updated index.html to load new modular files All files now comply with 300-line maximum rule. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
184 lines
5.8 KiB
JavaScript
184 lines
5.8 KiB
JavaScript
// ============================================
|
|
// DXF - AutoCAD R12 Export
|
|
// ============================================
|
|
|
|
function svgToDxf(svgString, scaleFactor = 1) {
|
|
const parser = new DOMParser();
|
|
const svg = parser.parseFromString(svgString, 'image/svg+xml').documentElement;
|
|
|
|
const viewBox = svg.getAttribute('viewBox')?.split(' ').map(Number) || [0, 0, 64, 64];
|
|
const height = viewBox[3];
|
|
|
|
let entities = '';
|
|
|
|
function flipY(y) {
|
|
return (height - y) * scaleFactor;
|
|
}
|
|
|
|
function scaleX(x) {
|
|
return x * scaleFactor;
|
|
}
|
|
|
|
function processElement(el) {
|
|
const tag = el.tagName?.toLowerCase();
|
|
if (!tag) return;
|
|
|
|
switch(tag) {
|
|
case 'line':
|
|
const x1 = parseFloat(el.getAttribute('x1') || 0);
|
|
const y1 = parseFloat(el.getAttribute('y1') || 0);
|
|
const x2 = parseFloat(el.getAttribute('x2') || 0);
|
|
const y2 = parseFloat(el.getAttribute('y2') || 0);
|
|
entities += createDxfLine(scaleX(x1), flipY(y1), scaleX(x2), flipY(y2));
|
|
break;
|
|
|
|
case 'rect':
|
|
const rx = parseFloat(el.getAttribute('x') || 0);
|
|
const ry = parseFloat(el.getAttribute('y') || 0);
|
|
const rw = parseFloat(el.getAttribute('width') || 0);
|
|
const rh = parseFloat(el.getAttribute('height') || 0);
|
|
entities += createDxfLine(scaleX(rx), flipY(ry), scaleX(rx + rw), flipY(ry));
|
|
entities += createDxfLine(scaleX(rx + rw), flipY(ry), scaleX(rx + rw), flipY(ry + rh));
|
|
entities += createDxfLine(scaleX(rx + rw), flipY(ry + rh), scaleX(rx), flipY(ry + rh));
|
|
entities += createDxfLine(scaleX(rx), flipY(ry + rh), scaleX(rx), flipY(ry));
|
|
break;
|
|
|
|
case 'circle':
|
|
const cx = parseFloat(el.getAttribute('cx') || 0);
|
|
const cy = parseFloat(el.getAttribute('cy') || 0);
|
|
const r = parseFloat(el.getAttribute('r') || 0);
|
|
entities += createDxfCircle(scaleX(cx), flipY(cy), r * scaleFactor);
|
|
break;
|
|
|
|
case 'ellipse':
|
|
const ecx = parseFloat(el.getAttribute('cx') || 0);
|
|
const ecy = parseFloat(el.getAttribute('cy') || 0);
|
|
const erx = parseFloat(el.getAttribute('rx') || 0);
|
|
const ery = parseFloat(el.getAttribute('ry') || 0);
|
|
entities += createDxfCircle(scaleX(ecx), flipY(ecy), ((erx + ery) / 2) * scaleFactor);
|
|
break;
|
|
|
|
case 'polygon':
|
|
case 'polyline':
|
|
const points = el.getAttribute('points');
|
|
if (points) {
|
|
const pts = points.trim().split(/[\s,]+/).map(Number);
|
|
for (let i = 0; i < pts.length - 2; i += 2) {
|
|
entities += createDxfLine(
|
|
scaleX(pts[i]), flipY(pts[i+1]),
|
|
scaleX(pts[i+2]), flipY(pts[i+3])
|
|
);
|
|
}
|
|
if (tag === 'polygon' && pts.length >= 4) {
|
|
entities += createDxfLine(
|
|
scaleX(pts[pts.length-2]), flipY(pts[pts.length-1]),
|
|
scaleX(pts[0]), flipY(pts[1])
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'path':
|
|
const d = el.getAttribute('d');
|
|
if (d) {
|
|
const pathEntities = parseSvgPath(d, scaleX, flipY);
|
|
entities += pathEntities;
|
|
}
|
|
break;
|
|
|
|
case 'text':
|
|
const tx = parseFloat(el.getAttribute('x') || 0);
|
|
const ty = parseFloat(el.getAttribute('y') || 0);
|
|
const textContent = el.textContent || '';
|
|
const fontSize = parseFloat(el.getAttribute('font-size') || 10);
|
|
entities += createDxfText(scaleX(tx), flipY(ty), textContent, fontSize * scaleFactor * 0.7);
|
|
break;
|
|
|
|
case 'g':
|
|
case 'svg':
|
|
Array.from(el.children).forEach(child => processElement(child));
|
|
break;
|
|
}
|
|
}
|
|
|
|
processElement(svg);
|
|
|
|
const dxf = [
|
|
'0', 'SECTION',
|
|
'2', 'HEADER',
|
|
'9', '$ACADVER',
|
|
'1', 'AC1009',
|
|
'9', '$INSBASE',
|
|
'10', '0.0',
|
|
'20', '0.0',
|
|
'30', '0.0',
|
|
'9', '$EXTMIN',
|
|
'10', '0.0',
|
|
'20', '0.0',
|
|
'30', '0.0',
|
|
'9', '$EXTMAX',
|
|
'10', String(height * scaleFactor),
|
|
'20', String(height * scaleFactor),
|
|
'30', '0.0',
|
|
'0', 'ENDSEC',
|
|
'0', 'SECTION',
|
|
'2', 'TABLES',
|
|
'0', 'TABLE',
|
|
'2', 'LAYER',
|
|
'70', '1',
|
|
'0', 'LAYER',
|
|
'2', '0',
|
|
'70', '0',
|
|
'62', '7',
|
|
'6', 'CONTINUOUS',
|
|
'0', 'ENDTAB',
|
|
'0', 'ENDSEC',
|
|
'0', 'SECTION',
|
|
'2', 'ENTITIES',
|
|
entities,
|
|
'0', 'ENDSEC',
|
|
'0', 'EOF'
|
|
].join('\r\n');
|
|
|
|
return dxf;
|
|
}
|
|
|
|
function createDxfLine(x1, y1, x2, y2) {
|
|
return [
|
|
'0', 'LINE',
|
|
'8', '0',
|
|
'10', x1.toFixed(4),
|
|
'20', y1.toFixed(4),
|
|
'30', '0.0',
|
|
'11', x2.toFixed(4),
|
|
'21', y2.toFixed(4),
|
|
'31', '0.0',
|
|
''
|
|
].join('\r\n');
|
|
}
|
|
|
|
function createDxfCircle(cx, cy, r) {
|
|
return [
|
|
'0', 'CIRCLE',
|
|
'8', '0',
|
|
'10', cx.toFixed(4),
|
|
'20', cy.toFixed(4),
|
|
'30', '0.0',
|
|
'40', r.toFixed(4),
|
|
''
|
|
].join('\r\n');
|
|
}
|
|
|
|
function createDxfText(x, y, text, height) {
|
|
return [
|
|
'0', 'TEXT',
|
|
'8', '0',
|
|
'10', x.toFixed(4),
|
|
'20', y.toFixed(4),
|
|
'30', '0.0',
|
|
'40', height.toFixed(4),
|
|
'1', text,
|
|
''
|
|
].join('\r\n');
|
|
}
|