Firmenlogo

BB Sport GmbH & Co KG

Söderbergstr. 14, 84513 Töging am Inn

Tel: +49 (0) 8631 988 2029 | E-Mail: service@unterkunft-fluechtlinge.de

Metall Etagenbett Stockbett Liegefläche jeweils 90 x 200 cm - teilbar in zwei Einzelbetten

ArtikelNr.:16470

Metall Etagenbett Stockbett Liegefläche jeweils 90 x 200 cm - teilbar in zwei Einzelbetten

Stabile Metall-Rahmenkonstruktion für eine platzsparende Lösung in Jugendheimen, Wohnheimen, Notunterkünften, Kasernen etc.

Das Bett ist bei Bedarf teilbar in zwei Einzelbetten, verfügt über eine fest anschraubbare Leiter, Metall-Lattenroste sowie extra hohe Fallschutzgitter. Die Metallbetten sind leicht zu reinigen, sehr stabil und dabei trotzdem einfach und schnell montiert. Sie bieten den Standard-Matratzen in einer Größe von 90 x 200 cm Platz. Jedes Bett kann bis zu 180 kg belastet werden.

Unsere Etagenbetten stehen für geprüfte Qualität. Sie erfüllen sowohl die Anforderungen der bisherigen Norm DIN EN 747-1:2012+A1:2015 und DIN EN 747-2:2012+A1:2015 als auch der aktuellen Norm DIN EN 747-1:2024 und DIN EN 747-2:2024.

Details zum Etagen-Bett:

  • Einsatzbereiche: Kasernen, Wachen, Notunterkünfte, Jugendheime, Wohnheime etc.
  • Teilbar in zwei Einzelbetten
  • Robuste Metall-Rahmenkonstruktion
  • Inkl. Metall-Lattenroste
  • Belastbarkeit je Bett 180 kg
  • Liegefläche je Bett 90 x 200 cm
  • Hohe Fallschutzgitter mit 32 cm Höhe
  • Lieferung ohne Matratzen
  • Nicht für Kinder unter 6 Jahren geeignet

Technische Daten:

Außenmaße Bett komplett: 97 x 210 cm, Höhe 165 cm
Leiter: 99 x 35 cm, 3 Sprossen
Höhe Fallschutz: 32 cm
Material: Metall, pulverbeschichtet;
Standrohre Ø 50 mm
Gewicht: 41 kg
Packmaß: 204 x 42 x 15 cm

Vorteile gegenüber herkömmlichen Etagenbetten:

Produktart: Etagenbett von Montafox herkömmliche Etagenbetten
Material: Robuster, belastbarer
und beständiger Stahlrahmen
Oftmals Holz, pflegeintensiv,
hygienische Reinigung nur schwer möglich
Metallbetten sind meist sehr leicht durch
dünnwandige Rohre auf Kosten der Stabilität
Fallschutz: 32 cm Höhe Meist nur 26 cm, teilweise gar keiner,
oder lediglich abschnittsweise
Leiter: Inklusive Bei vielen Anbietern Sonderausstattung
Versand: Speditionsversand -> Äußerst attraktiv für Großkunden Standardversand mit Sperrgutaufschlag
// Warten, bis das DOM vollständig geladen ist $(document).ready(function() { // Globale Variable zum Speichern des PDF-Blobs let pdfBlob = null; let pdfObjectURL = null; let lastPDFFilename = 'Produktdokument.pdf'; let logoDataURL = null; // Variable zum Speichern des vorgeladenen Logos let logoAspectRatio = 1; // Seitenverhältnis des Logos (Breite / Höhe) let logoWidth = 40; // Breite erhöht für bessere Sichtbarkeit let logoHeight = 15; // Wird basierend auf dem Seitenverhältnis angepasst // Logo vorab laden preloadLogo('https://cdn02.plentymarkets.com/5rubvkuloybx/frontend/Template/UF-logo.png'); // Funktion zum Vorladen des Logos function preloadLogo(logoSrc) { console.log('Lade Logo vor der PDF-Erstellung...'); const img = new Image(); img.crossOrigin = 'Anonymous'; img.onload = function() { try { // Seitenverhältnis berechnen und speichern logoAspectRatio = this.width / this.height; console.log('Logo-Seitenverhältnis:', logoAspectRatio, 'Original-Dimensionen:', this.width, 'x', this.height); // Höhe basierend auf fester Breite und Seitenverhältnis anpassen logoHeight = logoWidth / logoAspectRatio; // Für ein typisches Logo (breiter als hoch) prüfen if (logoAspectRatio > 2.5) { // Logo ist sehr breit, Höhe anpassen logoHeight = logoWidth / logoAspectRatio; } else if (logoAspectRatio < 0.8) { // Logo ist sehr hoch, Breite anpassen logoWidth = logoHeight * logoAspectRatio; } const canvas = document.createElement('canvas'); canvas.width = this.width; canvas.height = this.height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); logoDataURL = canvas.toDataURL('image/png'); console.log('Logo erfolgreich vorgeladen! Angepasste Dimensionen:', logoWidth, 'x', logoHeight, 'mm'); } catch (e) { console.error('Fehler beim Vorladen des Logos:', e); // Falls CORS-Probleme auftreten, versuche mit Proxy loadLogoWithProxy(logoSrc); } }; img.onerror = function() { console.warn('Fehler beim direkten Laden des Logos, versuche mit Proxy...'); loadLogoWithProxy(logoSrc); }; img.src = logoSrc; } // Logo mit Proxy laden function loadLogoWithProxy(logoSrc) { const corsProxyUrl = 'https://corsproxy.io/?url='; const proxyLogoSrc = corsProxyUrl + encodeURIComponent(logoSrc); console.log('Versuche Logo über Proxy zu laden:', proxyLogoSrc); const proxyImg = new Image(); proxyImg.crossOrigin = 'Anonymous'; proxyImg.onload = function() { try { const canvas = document.createElement('canvas'); canvas.width = proxyImg.width; canvas.height = proxyImg.height; const ctx = canvas.getContext('2d'); ctx.drawImage(proxyImg, 0, 0); logoDataURL = canvas.toDataURL('image/png'); console.log('Logo erfolgreich über Proxy vorgeladen!'); } catch (e) { console.error('Fehler beim Vorladen des Logos über Proxy:', e); } }; proxyImg.onerror = function() { console.error('Auch Proxy-Laden des Logos fehlgeschlagen'); }; proxyImg.src = proxyLogoSrc; } // Funktion zum Drucken des PDFs function printPDF() { if (!pdfObjectURL) { alert('Bitte zuerst ein PDF generieren.'); return; } console.log('Öffne PDF zum Drucken...'); try { // Methode 1: Versuch mit neuem Tab/Popup const printWindow = window.open(pdfObjectURL, '_blank'); if (printWindow === null) { // Popup wurde blockiert, versuche alternative Methode console.warn('Popup wurde blockiert. Verwende alternative Druckmethode...'); printWithIframe(); } else { // Popup wurde erlaubt printWindow.addEventListener('load', function() { setTimeout(function() { try { printWindow.print(); } catch (e) { console.error('Fehler beim Drucken im neuen Fenster:', e); alert('Druckdialog konnte nicht automatisch geöffnet werden. Bitte drucken Sie die Seite manuell.'); } }, 1000); }); } } catch (e) { console.error('Fehler beim Öffnen des Druckfensters:', e); // Fallback zur iframe-Methode printWithIframe(); } } // Alternative Druckmethode mit iframe function printWithIframe() { console.log('Verwende iframe-Methode zum Drucken...'); // Entferne vorhandene Druck-iframes const oldIframe = document.getElementById('print-iframe'); if (oldIframe) { document.body.removeChild(oldIframe); } // Erstelle ein unsichtbares iframe const iframe = document.createElement('iframe'); iframe.id = 'print-iframe'; iframe.style.position = 'fixed'; iframe.style.width = '1px'; iframe.style.height = '1px'; iframe.style.opacity = '0.01'; iframe.style.left = '-9999px'; iframe.style.top = '-9999px'; // Setze die PDF-URL als Quelle iframe.src = pdfObjectURL; // Warte, bis der Inhalt geladen ist, dann drucken iframe.onload = function() { try { setTimeout(function() { // Versuche zu drucken iframe.contentWindow.print(); // Lösche das iframe nach einer Weile setTimeout(function() { try { document.body.removeChild(iframe); } catch (e) { console.warn('Konnte iframe nicht entfernen:', e); } }, 10000); // 10 Sekunden warten }, 1000); } catch (e) { console.error('Fehler beim Drucken mit iframe:', e); alert('Drucken nicht möglich. Möglicherweise blockiert Ihr Browser den Druckvorgang.\n\nBitte versuchen Sie, das PDF herunterzuladen und manuell zu drucken.'); // Biete Download als Alternative an offerDownload(); } }; // Fehlerbehandlung iframe.onerror = function() { console.error('Fehler beim Laden des iframes'); alert('Das PDF konnte nicht geladen werden. Bitte versuchen Sie es erneut oder laden Sie es manuell herunter.'); offerDownload(); }; // Füge das iframe zum Dokument hinzu document.body.appendChild(iframe); } // Biete Download als Fallback an function offerDownload() { console.log('Biete PDF-Download an'); // Erstelle einen Download-Link const link = document.createElement('a'); link.href = pdfObjectURL; link.download = lastPDFFilename; link.textContent = 'PDF herunterladen'; link.style.display = 'block'; link.style.margin = '20px auto'; link.style.textAlign = 'center'; link.style.padding = '10px'; link.style.backgroundColor = '#4CAF50'; link.style.color = 'white'; link.style.textDecoration = 'none'; link.style.width = '200px'; link.style.borderRadius = '4px'; // Füge den Link oben im Preview-Bereich ein const previewDiv = document.getElementById('preview'); previewDiv.innerHTML = '

Drucken nicht möglich

Sie können das PDF herunterladen und manuell drucken.

'; previewDiv.appendChild(link); } // Funktion zur PDF-Generierung function generatePDF() { // Melde dem Benutzer, dass die PDF-Generierung beginnt console.log('PDF-Generierung wird gestartet...'); // Hole die jsPDF-Instanz const { jsPDF } = window.jspdf; // Erstelle ein neues PDF-Dokument im A4-Format const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4', compress: true }); // Setze eine eindeutige Funktion, die für alle Seitenoperationen aufgerufen wird // Diese zentralisierte Verarbeitung stellt sicher, dass alle Seiten konsistent formatiert werden doc.setPageCallback = function(pageInfo) { console.log("Seite verarbeitet:", pageInfo.pageNumber); addHeader(); addFooter(pageInfo.pageNumber); }; // Überschreibe die interne addPage-Methode, um unsere Callback-Funktion aufzurufen const originalAddPage = doc.addPage; doc.addPage = function() { originalAddPage.apply(this, arguments); const pageInfo = doc.getCurrentPageInfo(); if (doc.setPageCallback) { doc.setPageCallback(pageInfo); } }; // Füge Metadaten zum PDF hinzu doc.setProperties({ title: 'Datenblatt', subject: 'Datenblatt', author: 'BB Sport GmbH & Co KG', keywords: 'Produkte', creator: 'BB Sport GmbH & Co KG' }); // Definiere Standardschriftart und -größe doc.setFont('helvetica'); doc.setFontSize(10); // Standardabstände const margin = 20; let currentY = margin; // Funktion zum Zeichnen des Headers auf jeder Seite function addHeader() { // Position zurücksetzen currentY = margin; // Prüfe, ob wir das Logo bereits vorgeladen haben if (logoDataURL) { // Verwende das vorgeladene Logo mit korrektem Seitenverhältnis console.log('Verwende vorgeladenes Logo im Header mit Dimensionen:', logoWidth, 'x', logoHeight, 'mm'); // Setze das Logo etwas höher, damit es besser zentriert ist doc.addImage(logoDataURL, 'PNG', margin, currentY, logoWidth, logoHeight); } else { const logoSrc = 'https://cdn02.plentymarkets.com/5rubvkuloybx/frontend/Template/UF-logo.png'; // Logo direkt im Dokument suchen als Fallback const logoImg = document.getElementById('logoImage'); if (logoImg && logoImg.complete && logoImg.naturalWidth > 0) { try { console.log('Logo aus DOM laden'); // Seitenverhältnis des DOM-Images berechnen const imgAspectRatio = logoImg.naturalWidth / logoImg.naturalHeight; const adjustedHeight = logoWidth / imgAspectRatio; const canvas = document.createElement('canvas'); canvas.width = logoImg.naturalWidth; canvas.height = logoImg.naturalHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(logoImg, 0, 0); const logoDataURLFromDOM = canvas.toDataURL('image/png'); doc.addImage(logoDataURLFromDOM, 'PNG', margin, currentY, logoWidth, adjustedHeight); console.log('Logo erfolgreich aus DOM geladen und hinzugefügt'); } catch (e) { console.warn('Logo konnte nicht aus DOM geladen werden:', e); // LOGO-Text wird NICHT mehr angezeigt - wir versuchen jetzt, ein Bild zu laden loadImageDirectlyIntoPDF(logoSrc, margin, currentY, logoWidth); } } else { // Versuche das Logo direkt zu laden loadImageDirectlyIntoPDF(logoSrc, margin, currentY, logoWidth); } } // Firmenname und Kontaktdaten doc.setFont('helvetica', 'bold'); doc.setFontSize(14); doc.text('BB Sport GmbH & Co KG', 190, currentY + 5, { align: 'right' }); doc.setFont('helvetica', 'normal'); doc.setFontSize(8); doc.text('Söderbergstr. 14, 84513 Töging am Inn', 190, currentY + 10, { align: 'right' }); doc.text('Tel: +49 (0) 8631 988 2029 | E-Mail: service@unterkunft-fluechtlinge.de', 190, currentY + 15, { align: 'right' }); // Linie unter dem Header currentY += 20; doc.setDrawColor(200, 200, 200); doc.line(margin, currentY, 190, currentY); currentY += 10; return currentY; } // Direktes Laden eines Bildes in das PDF function loadImageDirectlyIntoPDF(src, x, y, width) { fetch('https://corsproxy.io/?url=' + encodeURIComponent(src)) .then(response => response.blob()) .then(blob => { const reader = new FileReader(); reader.onload = function() { const imgData = reader.result; // Temporäres Image zum Ermitteln der Dimensionen erstellen const tempImg = new Image(); tempImg.onload = function() { // Berechne Höhe basierend auf dem Seitenverhältnis const imgAspectRatio = tempImg.width / tempImg.height; const height = width / imgAspectRatio; // Logo in allen Seiten einfügen const pageCount = doc.internal.getNumberOfPages(); for (let i = 1; i <= pageCount; i++) { doc.setPage(i); doc.addImage(imgData, 'PNG', x, y, width, height); } }; tempImg.src = imgData; }; reader.readAsDataURL(blob); }) .catch(error => { console.error('Fehler beim direkten Laden des Logos:', error); }); } // Funktion zum Zeichnen des Footers auf jeder Seite function addFooter(pageNumber) { // Position des Footers definieren (weiter unten auf der Seite) const pageHeight = doc.internal.pageSize.height; const footerPosition = pageHeight - 10; // 10mm vom unteren Rand // Linie über dem Footer doc.setDrawColor(200, 200, 200); doc.line(margin, footerPosition - 15, 190, footerPosition - 15); // Footer-Text doc.setFont('helvetica', 'normal'); doc.setFontSize(8); doc.text('BB Sport GmbH & Co KG | E-mail: service@unterkunft-fluechtlinge.de', 105, footerPosition - 10, { align: 'center' }); doc.text('Bürozeiten: Montag bis Donnerstag von 7.30 - 17.00 Uhr | Freitag von 7:30 - 13.30 Uhr', 105, footerPosition - 5, { align: 'center' }); // Seitenzahl - nun prominent im Footer positioniert doc.setFont('helvetica', 'bold'); // Fett für Seitenzahlen doc.setFontSize(9); // Etwas größer für bessere Lesbarkeit doc.text('Seite ' + pageNumber, 190, footerPosition - 5, { align: 'right' }); } // Erstelle das PDF async function createPDF() { try { // Wir zeichnen den Header für die erste Seite currentY = addHeader(); addFooter(1); // Kundendaten doc.setFont('helvetica', 'bold'); doc.setFontSize(12); doc.text('Produktinformationen', margin, currentY); currentY += 10; // Extrahiere den echten Content const productContent = document.querySelector('.printrow'); if (productContent) { // Produkttitel const title = productContent.querySelector('.printname')?.textContent || 'Produkttitel'; const articleNumber = productContent.querySelector('.printnumber')?.textContent || 'ArtikelNr.: ---'; // Titel einfügen doc.setFont('helvetica', 'bold'); doc.setFontSize(14); // Splitten des Textes, falls er zu lang für eine Zeile ist const titleLines = doc.splitTextToSize(title, 190 - 2 * margin); doc.text(titleLines, margin, currentY); currentY += titleLines.length * 7 + 3; // Artikelnummer doc.setFontSize(10); doc.setFont('helvetica', 'normal'); doc.text(articleNumber, margin, currentY); currentY += 8; // Produktbilder await processImages(productContent); // Produktbeschreibung processDescription(productContent); // Footer für die erste Seite hinzufügen addFooter(1); // Das PDF speichern oder öffnen // Die Output-Methode auf 'blob' setzen const pdfOutput = doc.output('blob'); // Speichern des PDF-Blobs für späteren Zugriff pdfBlob = pdfOutput; // Falls bereits eine URL für ein vorheriges PDF existiert, diese freigeben if (pdfObjectURL) { URL.revokeObjectURL(pdfObjectURL); } // Erstellen einer URL für den PDF-Blob pdfObjectURL = URL.createObjectURL(pdfBlob); // Dateiname festlegen (für evtl. späteren Download) lastPDFFilename = 'Produktdokument.pdf'; console.log('PDF wurde erfolgreich generiert!'); // Direkt zum Drucken übergehen, ohne Download try { printPDF(); } catch (printError) { console.error('Fehler beim Druckversuch:', printError); alert('Das PDF wurde erstellt, aber der Druckdialog konnte nicht automatisch geöffnet werden.\n\nBitte klicken Sie auf "PDF drucken".'); } } else { doc.text("Keine Produktinformationen gefunden.", margin, currentY); const pdfOutput = doc.output('blob'); pdfBlob = pdfOutput; if (pdfObjectURL) { URL.revokeObjectURL(pdfObjectURL); } pdfObjectURL = URL.createObjectURL(pdfBlob); lastPDFFilename = 'Dokument.pdf'; console.log('Leeres PDF wurde generiert'); // Auch hier direkt drucken try { printPDF(); } catch (printError) { console.error('Fehler beim Druckversuch:', printError); alert('Das PDF wurde erstellt, aber der Druckdialog konnte nicht automatisch geöffnet werden.\n\nBitte klicken Sie auf "PDF drucken".'); } } } catch (error) { console.error("Fehler bei der PDF-Erstellung:", error); alert("Fehler bei der PDF-Erstellung: " + error.message); } } // Bildverarbeitung async function processImages(productContent) { const images = productContent.querySelectorAll('.printimg img'); if (images && images.length > 0) { let imageLoaded = false; // Wir nehmen das erste Bild mit gültiger Quelle for (let i = 0; i < images.length; i++) { const imgSrc = images[i].getAttribute('src'); if (imgSrc && imgSrc.trim() !== '') { try { console.log('Versuche Bild zu laden:', imgSrc); // Verwende verschiedene Strategien, um das Bild zu laden let imageData = null; let imageWidth = 0; let imageHeight = 0; // 1. Strategie: Versuche direkt über das DOM const domImg = images[i]; if (domImg.complete && domImg.naturalWidth > 0) { console.log('Strategie 1: Bild ist bereits im DOM geladen'); try { const canvas = document.createElement('canvas'); canvas.width = domImg.naturalWidth; canvas.height = domImg.naturalHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(domImg, 0, 0); try { imageData = canvas.toDataURL('image/jpeg'); imageWidth = domImg.naturalWidth; imageHeight = domImg.naturalHeight; console.log('DOM-Bildkonvertierung erfolgreich'); } catch (canvasError) { console.error('CORS-Fehler bei DOM-Bildkonvertierung:', canvasError); throw new Error('CORS-Fehler'); } } catch (err) { console.warn('DOM-Bildkonvertierung fehlgeschlagen:', err); } } // 2. Strategie: Versuche es über einen CORS-Proxy if (!imageData) { console.log('Strategie 2: Versuche CORS-Proxy'); try { // Verwende einen öffentlichen CORS-Proxy (nur für Testzwecke!) // Im Produktionseinsatz sollte ein eigener Proxy verwendet werden const corsProxyUrl = 'https://corsproxy.io/?url='; const proxyImgSrc = corsProxyUrl + encodeURIComponent(imgSrc); console.log('Versuche mit Proxy:', proxyImgSrc); const proxyImg = await loadImage(proxyImgSrc); imageData = proxyImg; // Größeninformationen holen wir über ein temporäres Bild const tempImg = new Image(); tempImg.src = proxyImg; await new Promise(resolve => { tempImg.onload = resolve; // Falls es trotzdem nicht lädt, nach einer Sekunde fortfahren setTimeout(resolve, 1000); }); imageWidth = tempImg.width || 1000; // Standardwert, falls nicht geladen imageHeight = tempImg.height || 800; console.log('Proxy-Bildladung erfolgreich'); } catch (proxyErr) { console.warn('Proxy-Bildladung fehlgeschlagen:', proxyErr); } } // 3. Strategie: Direkte URL (als Fallback) if (!imageData) { console.log('Strategie 3: Direkte URL'); const img = await loadImage(imgSrc); imageData = img; // Da die Größe nicht bekannt ist, nehmen wir Standardwerte an imageWidth = 1000; imageHeight = 800; } if (imageData) { // Berechne das Seitenverhältnis (80mm Breite) const imgWidth = 80; const imgHeight = imgWidth * imageHeight / imageWidth; // Prüfe, ob genug Platz auf der Seite ist if (currentY + imgHeight > 250) { doc.addPage(); // Header auf der neuen Seite hinzufügen currentY = margin + 30; // Zurücksetzen der Y-Position addHeader(); // Header hinzufügen } // Füge Bild hinzu doc.addImage(imageData, 'JPEG', margin, currentY, imgWidth, imgHeight); currentY += imgHeight + 10; // Platz nach dem Bild console.log('Bild erfolgreich eingefügt'); imageLoaded = true; break; } else { throw new Error('Keine der Bildlade-Strategien war erfolgreich'); } } catch (e) { console.warn('Bild konnte nicht geladen werden:', e); // Nur einen Fehlereintrag für das erste Bild if (!imageLoaded) { // Zeige Bildpfad an, nicht die komplette URL (kann zu lang sein) let displayPath = imgSrc; try { const urlObj = new URL(imgSrc); displayPath = urlObj.pathname; } catch (urlError) { // Falls URL-Parsing fehlschlägt, verwende den originalen Pfad } doc.setFontSize(9); doc.text("Bild konnte nicht eingebettet werden (CORS-Richtlinien)", margin, currentY); currentY += 5; doc.setFontSize(8); // Beschränke die Länge des angezeigten Pfads const maxPathLength = 80; if (displayPath.length > maxPathLength) { displayPath = '...' + displayPath.substring(displayPath.length - maxPathLength); } doc.text(displayPath, margin, currentY); currentY += 10; } } } } } } // Verarbeite die Produktbeschreibung function processDescription(productContent) { const descSection = productContent.querySelector('.printdesc'); if (descSection) { // Alle direkten Kindelemente in der originalen Reihenfolge durchlaufen const childNodes = descSection.children; console.log('Verarbeite Beschreibung mit ' + childNodes.length + ' Elementen'); for (let i = 0; i < childNodes.length; i++) { const element = childNodes[i]; const tagName = element.tagName.toLowerCase(); // Überschriften (h1, h2, h3, etc.) if (tagName.startsWith('h') && tagName.length === 2) { const headingText = element.textContent || ''; const headingLevel = parseInt(tagName[1]); doc.setFont('helvetica', 'bold'); doc.setFontSize(headingLevel === 2 ? 12 : (headingLevel === 3 ? 11 : 10)); // Splitten des Textes, falls er zu lang für eine Zeile ist const headingLines = doc.splitTextToSize(headingText, 190 - 2 * margin); // Prüfen, ob genug Platz auf der Seite ist if (currentY + headingLines.length * 7 > 250) { doc.addPage(); // Header auf der neuen Seite hinzufügen currentY = margin + 30; // Zurücksetzen der Y-Position addHeader(); // Header hinzufügen } doc.text(headingLines, margin, currentY); currentY += headingLines.length * 7 + 3; } // Absätze else if (tagName === 'p') { const paragraphText = element.textContent || ''; doc.setFont('helvetica', 'normal'); doc.setFontSize(10); // Splitten des Textes, falls er zu lang für eine Zeile ist const paragraphLines = doc.splitTextToSize(paragraphText, 190 - 2 * margin); // Prüfen, ob genug Platz auf der Seite ist if (currentY + paragraphLines.length * 5 > 250) { doc.addPage(); // Header auf der neuen Seite hinzufügen currentY = margin + 30; // Zurücksetzen der Y-Position addHeader(); // Header hinzufügen } doc.text(paragraphLines, margin, currentY); currentY += paragraphLines.length * 5 + 5; } // Listen else if (tagName === 'ul') { const listItems = element.querySelectorAll('li'); listItems.forEach(item => { const itemText = '• ' + (item.textContent || ''); doc.setFont('helvetica', 'normal'); doc.setFontSize(10); // Splitten des Textes, falls er zu lang für eine Zeile ist const itemLines = doc.splitTextToSize(itemText, 185 - 2 * margin); // Prüfen, ob genug Platz auf der Seite ist if (currentY + itemLines.length * 5 > 250) { doc.addPage(); // Header auf der neuen Seite hinzufügen currentY = margin + 30; // Zurücksetzen der Y-Position addHeader(); // Header hinzufügen } doc.text(itemLines, margin, currentY); currentY += itemLines.length * 5 + 2; }); currentY += 3; // Zusätzlicher Abstand nach der Liste } // Tabellen else if (tagName === 'table') { const tableElement = element; // Reduziere den Abstand vor der Tabelle currentY += 2; // Früher: 5 // Lasse die Überschrift "Technische Daten" weg, da sie bereits als h3 enthalten ist //doc.setFont('helvetica', 'bold'); //doc.setFontSize(11); //doc.text('Technische Daten', margin, currentY); currentY += 2; // Früher: 7 - Reduziere den Leerraum const rows = tableElement.querySelectorAll('tr'); const tableData = []; rows.forEach(row => { const cells = row.querySelectorAll('td'); if (cells.length >= 2) { const rowData = [ cells[0].textContent || '', cells[1].textContent.replace(/\t{2,}/g, "\n").replace(/\t/g, " ") || '' ]; tableData.push(rowData); } }); // Technische Daten als Tabelle rendern if (tableData.length > 0) { doc.autoTable({ startY: currentY, body: tableData, theme: 'plain', // Zurück zu 'plain' und manueller Linien-Steuerung styles: { fontSize: 9, cellPadding: 3, lineWidth: 0.5, // Einheitliche Linienstärke lineColor: [80, 80, 80] // Dunkelgrau }, columnStyles: { 0: { fontStyle: 'bold', cellWidth: 40 }, 1: { cellWidth: 'auto' } }, margin: { left: margin, right: margin, top: 40, // Abstand von oben für den Header bottom: 40 // Mehr Abstand unten für den Footer }, // Klare Tabelleneigenschaften tableLineWidth: 0.5, // Moderate Linienstärke tableLineColor: [80, 80, 80], // Dunkelgrau drawCell: function(cell, data) { // Klar definierte Zellenrahmen für alle Zellen const doc = data.doc; const cellPos = cell.getTextPos(); // Zeichne standardmäßig alle Außenlinien doc.setDrawColor(80, 80, 80); // Einheitliche Linienfarbe doc.setLineWidth(0.5); // Einheitliche Linienstärke // Zeichne Zellenrahmen (oben, rechts, unten, links) doc.rect(cell.x, cell.y, cell.width, cell.height, 'S'); }, // Entferne den didParseCell-Handler, der dickere Linien hinzugefügt hat didDrawPage: function(data) { // Header und Footer werden nicht explizit hier gezeichnet, // da die modifizierte addPage-Methode dies automatisch macht } }); // Position nach der Tabelle aktualisieren currentY = doc.autoTable.previous.finalY + 5; // Reduziere auch den Abstand nach der Tabelle } } } } } // Hilfsfunktion zum Laden eines Bildes function loadImage(src) { return new Promise((resolve, reject) => { console.log('loadImage aufgerufen für:', src); const img = new Image(); img.crossOrigin = 'Anonymous'; // Für CORS-Unterstützung // Setze Timeout für Bildladung const timeoutId = setTimeout(() => { console.warn('Bild-Ladezeitüberschreitung:', src); img.src = ''; // Abbrechen des Ladevorgangs reject(new Error('Zeitüberschreitung beim Laden des Bildes')); }, 5000); // 5 Sekunden Timeout img.onload = function() { clearTimeout(timeoutId); // Timeout löschen console.log('Bild geladen, Größe:', this.width, 'x', this.height); // Konvertiere das Bild zu einer Data URL const canvas = document.createElement('canvas'); canvas.width = this.width; canvas.height = this.height; const ctx = canvas.getContext('2d'); try { ctx.drawImage(this, 0, 0); const dataURL = canvas.toDataURL('image/jpeg'); console.log('Bild erfolgreich zu Data URL konvertiert'); resolve(dataURL); } catch (error) { console.error("CORS-Fehler beim Konvertieren des Bildes:", error); reject(new Error('CORS-Fehler: Bild kann nicht von externer Domain geladen werden')); } }; img.onerror = function() { clearTimeout(timeoutId); // Timeout löschen console.error('Bild konnte nicht geladen werden:', src); reject(new Error('Bild konnte nicht geladen werden')); }; img.src = src; // Für bereits gecachte Bilder, die sofort geladen werden if (img.complete) { clearTimeout(timeoutId); // Timeout löschen try { const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); const dataURL = canvas.toDataURL('image/jpeg'); console.log('Bereits gecachtes Bild erfolgreich konvertiert'); resolve(dataURL); } catch (error) { console.error("CORS-Fehler bei bereits geladenem Bild:", error); reject(error); } } }); } // Starte die PDF-Erstellung createPDF(); } setTimeout(function(){ generatePDF(); },1000) });