- 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>
244 lines
7.8 KiB
JavaScript
244 lines
7.8 KiB
JavaScript
// ============================================
|
|
// LEGEND - Legenden-Funktionen
|
|
// ============================================
|
|
|
|
// ========== LEGENDE AUSWAHL ==========
|
|
function toggleLegendSelection(id) {
|
|
if (selectedSymbols.has(id)) {
|
|
selectedSymbols.delete(id);
|
|
} else {
|
|
selectedSymbols.add(id);
|
|
|
|
const item = findSymbol(id);
|
|
if (item && !legendItems.find(l => l.id === id)) {
|
|
legendItems.push({
|
|
id: item.id,
|
|
name: item.name,
|
|
svg: item.svg,
|
|
description: ''
|
|
});
|
|
}
|
|
}
|
|
|
|
renderSymbols();
|
|
updateLegendCount();
|
|
saveLegendToStorage();
|
|
}
|
|
|
|
function updateLegendCount() {
|
|
const countEl = document.getElementById('legendCount');
|
|
if (countEl) {
|
|
countEl.textContent = legendItems.length;
|
|
}
|
|
}
|
|
|
|
// ========== LEGENDE MODAL ==========
|
|
function openLegendModal() {
|
|
const modal = document.getElementById('legendModal');
|
|
modal.classList.add('active');
|
|
renderLegendEditor();
|
|
updateLegendPreview();
|
|
}
|
|
|
|
function closeLegendModal() {
|
|
const modal = document.getElementById('legendModal');
|
|
modal.classList.remove('active');
|
|
}
|
|
|
|
function renderLegendEditor() {
|
|
const container = document.getElementById('legendItems');
|
|
|
|
if (legendItems.length === 0) {
|
|
container.innerHTML = '<div class="legend-empty">Keine Symbole in der Legende. Klicken Sie auf 📑 bei einem Symbol, um es hinzuzufügen.</div>';
|
|
updateLegendPreview();
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = legendItems.map((item, index) => `
|
|
<div class="legend-item" data-index="${index}">
|
|
<div class="legend-item-preview">${item.svg}</div>
|
|
<div class="legend-item-content">
|
|
<input type="text" class="legend-item-name" value="${item.name}"
|
|
oninput="updateLegendItem(${index}, 'name', this.value)" placeholder="Name">
|
|
<input type="text" class="legend-item-desc" value="${item.description || ''}"
|
|
oninput="updateLegendItem(${index}, 'description', this.value)" placeholder="Beschreibung (optional)">
|
|
</div>
|
|
<div class="legend-item-actions">
|
|
<button type="button" onclick="moveLegendItem(${index}, -1)" title="Nach oben" ${index === 0 ? 'disabled' : ''}>▲</button>
|
|
<button type="button" onclick="moveLegendItem(${index}, 1)" title="Nach unten" ${index === legendItems.length - 1 ? 'disabled' : ''}>▼</button>
|
|
<button type="button" onclick="removeLegendItem(${index})" title="Entfernen" class="btn-remove">✕</button>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
|
|
updateLegendPreview();
|
|
}
|
|
|
|
function updateLegendItem(index, field, value) {
|
|
if (legendItems[index]) {
|
|
legendItems[index][field] = value;
|
|
saveLegendToStorage();
|
|
updateLegendPreview();
|
|
}
|
|
}
|
|
|
|
function moveLegendItem(index, direction) {
|
|
const newIndex = index + direction;
|
|
if (newIndex >= 0 && newIndex < legendItems.length) {
|
|
const temp = legendItems[index];
|
|
legendItems[index] = legendItems[newIndex];
|
|
legendItems[newIndex] = temp;
|
|
renderLegendEditor();
|
|
saveLegendToStorage();
|
|
}
|
|
}
|
|
|
|
function removeLegendItem(index) {
|
|
const item = legendItems[index];
|
|
if (item) {
|
|
selectedSymbols.delete(item.id);
|
|
}
|
|
legendItems.splice(index, 1);
|
|
renderLegendEditor();
|
|
renderSymbols();
|
|
updateLegendCount();
|
|
saveLegendToStorage();
|
|
}
|
|
|
|
function clearLegend() {
|
|
if (confirm('Möchten Sie die Legende wirklich leeren?')) {
|
|
legendItems = [];
|
|
selectedSymbols.clear();
|
|
renderLegendEditor();
|
|
renderSymbols();
|
|
updateLegendCount();
|
|
saveLegendToStorage();
|
|
}
|
|
}
|
|
|
|
// ========== LEGENDE SPEICHERN/LADEN ==========
|
|
function saveLegendToStorage() {
|
|
try {
|
|
localStorage.setItem('gutachter_legende', JSON.stringify(legendItems));
|
|
localStorage.setItem('gutachter_selected', JSON.stringify([...selectedSymbols]));
|
|
} catch (e) {
|
|
console.warn('LocalStorage nicht verfügbar');
|
|
}
|
|
}
|
|
|
|
function loadLegendFromStorage() {
|
|
try {
|
|
const saved = localStorage.getItem('gutachter_legende');
|
|
const savedSelected = localStorage.getItem('gutachter_selected');
|
|
|
|
if (saved) {
|
|
legendItems = JSON.parse(saved);
|
|
}
|
|
if (savedSelected) {
|
|
selectedSymbols = new Set(JSON.parse(savedSelected));
|
|
}
|
|
|
|
updateLegendCount();
|
|
} catch (e) {
|
|
console.warn('Fehler beim Laden der Legende');
|
|
}
|
|
}
|
|
|
|
// ========== LEGENDE VORSCHAU ==========
|
|
function generateLegendSVG() {
|
|
if (legendItems.length === 0) return null;
|
|
|
|
const itemHeight = 50;
|
|
const width = 320;
|
|
const height = legendItems.length * itemHeight + 60;
|
|
|
|
let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}">
|
|
<rect width="${width}" height="${height}" fill="white"/>
|
|
<text x="20" y="30" font-family="Arial" font-size="18" font-weight="bold">Legende</text>
|
|
<line x1="20" y1="40" x2="${width - 20}" y2="40" stroke="#ccc" stroke-width="1"/>`;
|
|
|
|
legendItems.forEach((item, index) => {
|
|
const y = 60 + index * itemHeight;
|
|
svg += `<g transform="translate(20, ${y})">
|
|
<g transform="scale(0.5)">${item.svg.replace(/<svg[^>]*>/, '').replace('</svg>', '')}</g>
|
|
<text x="50" y="20" font-family="Arial" font-size="14" font-weight="bold">${escapeHtml(item.name)}</text>
|
|
${item.description ? `<text x="50" y="35" font-family="Arial" font-size="11" fill="#666">${escapeHtml(item.description)}</text>` : ''}
|
|
</g>`;
|
|
});
|
|
|
|
svg += '</svg>';
|
|
return svg;
|
|
}
|
|
|
|
function updateLegendPreview() {
|
|
const previewBox = document.getElementById('legendPreviewBox');
|
|
if (!previewBox) return;
|
|
|
|
if (legendItems.length === 0) {
|
|
previewBox.innerHTML = '<div class="legend-preview-empty">Keine Eintraege vorhanden</div>';
|
|
return;
|
|
}
|
|
|
|
const svg = generateLegendSVG();
|
|
if (svg) {
|
|
previewBox.innerHTML = svg;
|
|
}
|
|
}
|
|
|
|
async function copyLegendAsImage() {
|
|
if (legendItems.length === 0) {
|
|
showNotification('Legende ist leer', 'error');
|
|
return;
|
|
}
|
|
|
|
const svg = generateLegendSVG();
|
|
if (!svg) return;
|
|
|
|
try {
|
|
const canvas = document.createElement('canvas');
|
|
const ctx = canvas.getContext('2d');
|
|
const itemHeight = 50;
|
|
const width = 320;
|
|
const height = legendItems.length * itemHeight + 60;
|
|
|
|
canvas.width = width * 2;
|
|
canvas.height = height * 2;
|
|
ctx.scale(2, 2);
|
|
ctx.fillStyle = 'white';
|
|
ctx.fillRect(0, 0, width, height);
|
|
|
|
const img = new Image();
|
|
const svgBlob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' });
|
|
const url = URL.createObjectURL(svgBlob);
|
|
|
|
await new Promise((resolve, reject) => {
|
|
img.onload = resolve;
|
|
img.onerror = reject;
|
|
img.src = url;
|
|
});
|
|
|
|
ctx.drawImage(img, 0, 0, width, height);
|
|
URL.revokeObjectURL(url);
|
|
|
|
canvas.toBlob(async (blob) => {
|
|
try {
|
|
await navigator.clipboard.write([
|
|
new ClipboardItem({ 'image/png': blob })
|
|
]);
|
|
showNotification('Legende in Zwischenablage kopiert!');
|
|
} catch (err) {
|
|
const link = document.createElement('a');
|
|
link.href = URL.createObjectURL(blob);
|
|
link.download = 'legende.png';
|
|
link.click();
|
|
showNotification('Legende als PNG heruntergeladen');
|
|
}
|
|
}, 'image/png');
|
|
} catch (err) {
|
|
console.error('Fehler beim Kopieren:', err);
|
|
showNotification('Fehler beim Kopieren', 'error');
|
|
}
|
|
}
|
|
|
|
// Export-Funktionen sind in legend-export.js
|