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

ALPIDEX Isomatte Selbstaufblasende Thermomatte Selfinflating Matte 190 x 60 x 2,5 cm

ArtikelNr.:9454_rot

Isomatte Selfinflating Matte 190 x 60 x 2,5 cm

Kompakt, aufblasbar, strapazierfähig und wärmend - Ein idealer Begleiter für kurze Campingtrips !

Die Matte füllt sich nach dem Öffnen des Ventils selbständig mit Luft und erspart somit das Mitführen einer unhandlichen Luftpumpe.

Hinweise zu Funktion und Lagerung:

Die Matte erreicht nicht von jetzt auf gleich ihr volles Volumen. Je nach Umgebung und/oder vorheriger Lagerung kann dies etwas länger dauern. Vorallem in den kälteren Monaten braucht der Schaumstoff eine gewisse Zeit, um sich zu entfalten. Sobald sich die Matte dann vollständig gefüllt hat, ist das Ventil wieder zu schließen.

Bitte achten Sie stets auf eine richtige Lagerung der Matte damit Sie lange Freude daran haben. Dazu ist folgendes wichtig:
Matte nur zum Transport einrollen und nicht längere Zeit auf diese Art lagern, da sonst das Füllmaterial stark leidet. Damit sich der Schaumstoff immer wieder schön ausbreiten kann und nicht dauerhaft verformt, die Matte am besten ausgebreitet und mit offenem Ventil, z. B. auf einem Schrank oder unter dem Bett lagern.

Lieferumfang:

  • Selfinflating-Matte
  • Tragebeutel mit Kordel und Stopper
  • 2 x Fixierband

Technische Daten:

Material Mattenoberfläche: 100 % Polyester
Material Schaum: 100 % Polyurethan
Material Aufbewahrungstasche: 100 % Polyester
Länge: 190 cm
Breite: 60 cm
Höhe: 2,5 cm
Packmaß gerollt: 61 x 14 cm
Gewicht: 1.196 g
Farben:

black, rot, grün, orange, military,
dunkelblau, lime, berry, türkis

// 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) });