- Removed duplicate files (index2/3/4.html, symbols.js duplicates) - Kept index4.html as the main index.html (modular version) - Removed old text-generator.js (replaced by modular version) - Fixed ID mismatch in ui-bindings.js to match HTML - Added square and circle shape support in svg-generator.js - Added legend preview with copy functionality - Removed 580 lines of obsolete text-generator v4 code from app.js - Added addTextToLegend and addStandaloneArrowToLegend to export.js Still TODO: Split large files to comply with 300 line limit - app.js: 1219 lines - styles.css: 1319 lines - symbols.js: 870 lines 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
363 lines
12 KiB
JavaScript
363 lines
12 KiB
JavaScript
/**
|
|
* Export-Funktionen fuer Text-Symbole
|
|
*/
|
|
|
|
var TextExport = {
|
|
|
|
// SVG zu Canvas rendern
|
|
svgToCanvas: function(svgString, scale) {
|
|
return new Promise(function(resolve, reject) {
|
|
var img = new Image();
|
|
var canvas = document.createElement('canvas');
|
|
var ctx = canvas.getContext('2d');
|
|
|
|
var parser = new DOMParser();
|
|
var svgDoc = parser.parseFromString(svgString, 'image/svg+xml');
|
|
var svgEl = svgDoc.documentElement;
|
|
|
|
var width = parseFloat(svgEl.getAttribute('width')) || 200;
|
|
var height = parseFloat(svgEl.getAttribute('height')) || 100;
|
|
|
|
canvas.width = width * scale;
|
|
canvas.height = height * scale;
|
|
|
|
var blob = new Blob([svgString], { type: 'image/svg+xml' });
|
|
var url = URL.createObjectURL(blob);
|
|
|
|
img.onload = function() {
|
|
ctx.scale(scale, scale);
|
|
ctx.drawImage(img, 0, 0);
|
|
URL.revokeObjectURL(url);
|
|
resolve(canvas);
|
|
};
|
|
|
|
img.onerror = function(e) {
|
|
URL.revokeObjectURL(url);
|
|
reject(e);
|
|
};
|
|
|
|
img.src = url;
|
|
});
|
|
},
|
|
|
|
// In Zwischenablage kopieren (als PNG)
|
|
copyAsImage: function(svgString, scale) {
|
|
var self = this;
|
|
scale = scale || 3;
|
|
|
|
return this.svgToCanvas(svgString, scale).then(function(canvas) {
|
|
return new Promise(function(resolve, reject) {
|
|
canvas.toBlob(function(blob) {
|
|
if (!blob) {
|
|
reject(new Error('Canvas toBlob failed'));
|
|
return;
|
|
}
|
|
navigator.clipboard.write([
|
|
new ClipboardItem({ 'image/png': blob })
|
|
]).then(resolve).catch(reject);
|
|
}, 'image/png');
|
|
});
|
|
});
|
|
},
|
|
|
|
// SVG in Zwischenablage
|
|
copySvg: function(svgString) {
|
|
return navigator.clipboard.writeText(svgString);
|
|
},
|
|
|
|
// SVG herunterladen
|
|
downloadSvg: function(svgString, filename) {
|
|
var blob = new Blob([svgString], { type: 'image/svg+xml' });
|
|
var url = URL.createObjectURL(blob);
|
|
var a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename || 'symbol.svg';
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(url);
|
|
},
|
|
|
|
// PNG herunterladen
|
|
downloadPng: function(svgString, filename, scale) {
|
|
scale = scale || 3;
|
|
|
|
return this.svgToCanvas(svgString, scale).then(function(canvas) {
|
|
var url = canvas.toDataURL('image/png');
|
|
var a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename || 'symbol.png';
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
});
|
|
},
|
|
|
|
// JPG herunterladen
|
|
downloadJpg: function(svgString, filename, scale, bgColor) {
|
|
scale = scale || 3;
|
|
bgColor = bgColor || '#ffffff';
|
|
|
|
return this.svgToCanvas(svgString, scale).then(function(canvas) {
|
|
// Neues Canvas mit Hintergrund
|
|
var bgCanvas = document.createElement('canvas');
|
|
bgCanvas.width = canvas.width;
|
|
bgCanvas.height = canvas.height;
|
|
var ctx = bgCanvas.getContext('2d');
|
|
ctx.fillStyle = bgColor;
|
|
ctx.fillRect(0, 0, bgCanvas.width, bgCanvas.height);
|
|
ctx.drawImage(canvas, 0, 0);
|
|
|
|
var url = bgCanvas.toDataURL('image/jpeg', 0.95);
|
|
var a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename || 'symbol.jpg';
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
});
|
|
},
|
|
|
|
// DXF generieren (vereinfacht - nur Linien)
|
|
svgToDxf: function(svgString) {
|
|
var parser = new DOMParser();
|
|
var svgDoc = parser.parseFromString(svgString, 'image/svg+xml');
|
|
var svgEl = svgDoc.documentElement;
|
|
|
|
var width = parseFloat(svgEl.getAttribute('width')) || 200;
|
|
var height = parseFloat(svgEl.getAttribute('height')) || 100;
|
|
|
|
var dxf = '0\nSECTION\n2\nENTITIES\n';
|
|
|
|
// Rechtecke
|
|
var rects = svgEl.querySelectorAll('rect');
|
|
rects.forEach(function(rect) {
|
|
var x = parseFloat(rect.getAttribute('x')) || 0;
|
|
var y = parseFloat(rect.getAttribute('y')) || 0;
|
|
var w = parseFloat(rect.getAttribute('width')) || 0;
|
|
var h = parseFloat(rect.getAttribute('height')) || 0;
|
|
var fy = height - y;
|
|
|
|
dxf += '0\nLINE\n8\n0\n';
|
|
dxf += '10\n' + x + '\n20\n' + fy + '\n30\n0\n';
|
|
dxf += '11\n' + (x + w) + '\n21\n' + fy + '\n31\n0\n';
|
|
|
|
dxf += '0\nLINE\n8\n0\n';
|
|
dxf += '10\n' + (x + w) + '\n20\n' + fy + '\n30\n0\n';
|
|
dxf += '11\n' + (x + w) + '\n21\n' + (fy - h) + '\n31\n0\n';
|
|
|
|
dxf += '0\nLINE\n8\n0\n';
|
|
dxf += '10\n' + (x + w) + '\n20\n' + (fy - h) + '\n30\n0\n';
|
|
dxf += '11\n' + x + '\n21\n' + (fy - h) + '\n31\n0\n';
|
|
|
|
dxf += '0\nLINE\n8\n0\n';
|
|
dxf += '10\n' + x + '\n20\n' + (fy - h) + '\n30\n0\n';
|
|
dxf += '11\n' + x + '\n21\n' + fy + '\n31\n0\n';
|
|
});
|
|
|
|
// Pfade (vereinfacht)
|
|
var paths = svgEl.querySelectorAll('path');
|
|
paths.forEach(function(path) {
|
|
var d = path.getAttribute('d');
|
|
if (!d) return;
|
|
|
|
var points = [];
|
|
var parts = d.match(/[ML]\s*[\d.-]+\s+[\d.-]+/g);
|
|
if (parts) {
|
|
parts.forEach(function(part) {
|
|
var nums = part.match(/[\d.-]+/g);
|
|
if (nums && nums.length >= 2) {
|
|
points.push({ x: parseFloat(nums[0]), y: parseFloat(nums[1]) });
|
|
}
|
|
});
|
|
}
|
|
|
|
for (var i = 0; i < points.length - 1; i++) {
|
|
dxf += '0\nLINE\n8\n0\n';
|
|
dxf += '10\n' + points[i].x + '\n20\n' + (height - points[i].y) + '\n30\n0\n';
|
|
dxf += '11\n' + points[i + 1].x + '\n21\n' + (height - points[i + 1].y) + '\n31\n0\n';
|
|
}
|
|
});
|
|
|
|
// Text (als Hinweis)
|
|
var texts = svgEl.querySelectorAll('text');
|
|
texts.forEach(function(text) {
|
|
var x = parseFloat(text.getAttribute('x')) || 0;
|
|
var y = parseFloat(text.getAttribute('y')) || 0;
|
|
var content = text.textContent || '';
|
|
|
|
dxf += '0\nTEXT\n8\n0\n';
|
|
dxf += '10\n' + x + '\n20\n' + (height - y) + '\n30\n0\n';
|
|
dxf += '40\n10\n1\n' + content + '\n';
|
|
});
|
|
|
|
dxf += '0\nENDSEC\n0\nEOF\n';
|
|
return dxf;
|
|
},
|
|
|
|
// DXF herunterladen
|
|
downloadDxf: function(svgString, filename) {
|
|
var dxf = this.svgToDxf(svgString);
|
|
var blob = new Blob([dxf], { type: 'application/dxf' });
|
|
var url = URL.createObjectURL(blob);
|
|
var a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename || 'symbol.dxf';
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(url);
|
|
},
|
|
|
|
// Feedback anzeigen
|
|
showFeedback: function(message, isError) {
|
|
var existing = document.querySelector('.export-feedback');
|
|
if (existing) existing.remove();
|
|
|
|
var feedback = document.createElement('div');
|
|
feedback.className = 'export-feedback';
|
|
feedback.style.cssText = 'position: fixed; bottom: 20px; right: 20px; padding: 12px 20px; border-radius: 8px; font-size: 14px; z-index: 10000; animation: fadeIn 0.3s;';
|
|
feedback.style.background = isError ? '#ef4444' : '#10b981';
|
|
feedback.style.color = 'white';
|
|
feedback.textContent = message;
|
|
document.body.appendChild(feedback);
|
|
|
|
setTimeout(function() {
|
|
feedback.style.opacity = '0';
|
|
feedback.style.transition = 'opacity 0.3s';
|
|
setTimeout(function() { feedback.remove(); }, 300);
|
|
}, 2000);
|
|
}
|
|
};
|
|
|
|
window.TextExport = TextExport;
|
|
|
|
// Globale Export-Funktionen fuer onclick-Handler
|
|
window.copyTextAsImage = function() {
|
|
var svg = window.SvgGenerator.generate(window.TextGenState.current);
|
|
window.TextExport.copyAsImage(svg).then(function() {
|
|
window.TextExport.showFeedback('Als PNG kopiert!');
|
|
}).catch(function(e) {
|
|
window.TextExport.showFeedback('Fehler: ' + e.message, true);
|
|
});
|
|
};
|
|
|
|
window.copyTextSVG = function() {
|
|
var svg = window.SvgGenerator.generate(window.TextGenState.current);
|
|
window.TextExport.copySvg(svg).then(function() {
|
|
window.TextExport.showFeedback('SVG kopiert!');
|
|
});
|
|
};
|
|
|
|
window.downloadTextPNG = function() {
|
|
var svg = window.SvgGenerator.generate(window.TextGenState.current);
|
|
window.TextExport.downloadPng(svg, 'text-symbol.png');
|
|
};
|
|
|
|
window.downloadTextJPG = function() {
|
|
var svg = window.SvgGenerator.generate(window.TextGenState.current);
|
|
window.TextExport.downloadJpg(svg, 'text-symbol.jpg');
|
|
};
|
|
|
|
window.downloadTextSVG = function() {
|
|
var svg = window.SvgGenerator.generate(window.TextGenState.current);
|
|
window.TextExport.downloadSvg(svg, 'text-symbol.svg');
|
|
};
|
|
|
|
window.downloadTextDXF = function() {
|
|
var svg = window.SvgGenerator.generate(window.TextGenState.current);
|
|
window.TextExport.downloadDxf(svg, 'text-symbol.dxf');
|
|
};
|
|
|
|
window.resetToDefaults = function() {
|
|
window.UiBindings.resetToDefaults();
|
|
};
|
|
|
|
// Standalone-Pfeil Funktionen
|
|
window.copyStandaloneArrow = function() {
|
|
var svg = window.SvgGenerator.generateArrowOnly(window.TextGenState.current);
|
|
if (svg) {
|
|
window.TextExport.copyAsImage(svg).then(function() {
|
|
window.TextExport.showFeedback('Pfeil als PNG kopiert!');
|
|
});
|
|
}
|
|
};
|
|
|
|
window.copyStandaloneArrowSVG = function() {
|
|
var svg = window.SvgGenerator.generateArrowOnly(window.TextGenState.current);
|
|
if (svg) {
|
|
window.TextExport.copySvg(svg).then(function() {
|
|
window.TextExport.showFeedback('Pfeil-SVG kopiert!');
|
|
});
|
|
}
|
|
};
|
|
|
|
window.downloadStandaloneArrowSVG = function() {
|
|
var svg = window.SvgGenerator.generateArrowOnly(window.TextGenState.current);
|
|
if (svg) {
|
|
window.TextExport.downloadSvg(svg, 'pfeil.svg');
|
|
}
|
|
};
|
|
|
|
window.downloadStandaloneArrowPNG = function() {
|
|
var svg = window.SvgGenerator.generateArrowOnly(window.TextGenState.current);
|
|
if (svg) {
|
|
window.TextExport.downloadPng(svg, 'pfeil.png');
|
|
}
|
|
};
|
|
|
|
window.downloadStandaloneArrowJPG = function() {
|
|
var svg = window.SvgGenerator.generateArrowOnly(window.TextGenState.current);
|
|
if (svg) {
|
|
window.TextExport.downloadJpg(svg, 'pfeil.jpg');
|
|
}
|
|
};
|
|
|
|
window.downloadStandaloneArrowDXF = function() {
|
|
var svg = window.SvgGenerator.generateArrowOnly(window.TextGenState.current);
|
|
if (svg) {
|
|
window.TextExport.downloadDxf(svg, 'pfeil.dxf');
|
|
}
|
|
};
|
|
|
|
// Zur Legende hinzufuegen
|
|
window.addTextToLegend = function() {
|
|
var state = window.TextGenState.current;
|
|
var svg = window.SvgGenerator.generate(state);
|
|
var name = state.text || 'Text-Symbol';
|
|
|
|
if (typeof legendItems !== 'undefined' && typeof updateLegendCount === 'function') {
|
|
legendItems.push({
|
|
id: 'text_' + Date.now(),
|
|
name: name.split('\n')[0].substring(0, 30),
|
|
svg: svg,
|
|
description: ''
|
|
});
|
|
updateLegendCount();
|
|
saveLegendToStorage();
|
|
if (typeof showNotification === 'function') {
|
|
showNotification('Zur Legende hinzugefuegt!');
|
|
}
|
|
}
|
|
};
|
|
|
|
window.addStandaloneArrowToLegend = function() {
|
|
var state = window.TextGenState.current;
|
|
var svg = window.SvgGenerator.generateArrowOnly(state);
|
|
if (!svg) return;
|
|
|
|
if (typeof legendItems !== 'undefined' && typeof updateLegendCount === 'function') {
|
|
legendItems.push({
|
|
id: 'arrow_' + Date.now(),
|
|
name: 'Pfeil ' + state.arrow,
|
|
svg: svg,
|
|
description: ''
|
|
});
|
|
updateLegendCount();
|
|
saveLegendToStorage();
|
|
if (typeof showNotification === 'function') {
|
|
showNotification('Pfeil zur Legende hinzugefuegt!');
|
|
}
|
|
}
|
|
};
|