Refactor symbols app: split large files (max 300 lines)

- 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>
This commit is contained in:
architeur
2025-12-14 21:34:03 +01:00
parent c0ae55a597
commit d707c5001d
28 changed files with 3514 additions and 3411 deletions

183
symbols/js/app/dxf.js Normal file
View File

@@ -0,0 +1,183 @@
// ============================================
// 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');
}