const handleDownloadReport = async () => { setIsGeneratingReport(true); setForecastError(''); try { const res = await axios.get('http://localhost:5000/api/generate-report-data', { withCredentials: true }); setReportData({ ...res.data, historicalLabels: filteredData.map(d => d.timestamp) }); setTimeout(async () => { const pdf = new jsPDF('p', 'mm', 'a4'); const margin = 15; const pdfWidth = pdf.internal.pageSize.getWidth(); const textWidth = pdfWidth - (margin * 2); let currentY = margin; pdf.setFontSize(22).setFont('helvetica', 'bold'); pdf.text('SuDS Performance & Forecast Report', pdfWidth / 2, currentY, { align: 'center' }); currentY += 10; pdf.setFontSize(14).setFont('helvetica', 'normal'); pdf.text(`Generated on: ${new Date().toLocaleDateString('en-GB')}`, pdfWidth / 2, currentY, { align: 'center' }); currentY += 15; const firstDate = new Date(filteredData[0].timestamp).toLocaleDateString('en-GB'); const lastDate = new Date(filteredData[filteredData.length - 1].timestamp).toLocaleDateString('en-GB'); const introText = `This report analyzes the performance of a Sustainable Drainage System (SuDS) using historical data from ${firstDate} to ${lastDate}, and provides a 24-hour forecast. The system is evaluated on three key performance metrics:`; const splitIntro = pdf.splitTextToSize(introText, textWidth); pdf.setFontSize(12).setFont('helvetica', 'normal'); pdf.text(splitIntro, margin, currentY); currentY += (splitIntro.length * 5) + 5; const bulletPoints = ["Rainfall (mm): Measures the amount of rain entering the system.","Water Level (cm): Measures the height of water collected within the SuDS infrastructure.","Flow Rate (lps): Measures the volume of water the system is discharging."]; pdf.setFontSize(11).setFont('helvetica', 'normal'); bulletPoints.forEach(point => { pdf.text(`\u2022 ${point}`, margin + 5, currentY); currentY += 7; }); currentY += 5; const conclusionText = `To provide a robust outlook, two different forecasting methods were used: a traditional statistical model and a modern machine learning model. \nThis dual-model approach allows for a comprehensive evaluation of potential future system behavior.`; const splitConclusion = pdf.splitTextToSize(conclusionText, textWidth); pdf.setFontSize(12).setFont('helvetica', 'normal'); pdf.text(splitConclusion, margin, currentY); currentY += (splitConclusion.length * 5) + 10; const chart1_canvas = reportRefs.chart1Ref.current.canvas; const chart1_img = chart1_canvas.toDataURL('image/png', 2.5); const chart1_img_height = (chart1_canvas.height * (pdfWidth - margin*2)) / chart1_canvas.width; pdf.addImage(chart1_img, 'PNG', margin, currentY, pdfWidth - (margin*2), chart1_img_height); pdf.addPage(); currentY = margin; const chart2_canvas = reportRefs.chart2Ref.current.canvas; const chart2_img = chart2_canvas.toDataURL('image/png', 2.5); const chart2_img_height = (chart2_canvas.height * (pdfWidth - margin*2)) / chart2_canvas.width; pdf.addImage(chart2_img, 'PNG', margin, currentY, pdfWidth - (margin*2), chart2_img_height); currentY += chart2_img_height + 10; const chart3_canvas = reportRefs.chart3Ref.current.canvas; const chart3_img = chart3_canvas.toDataURL('image/png', 2.5); const chart3_img_height = (chart3_canvas.height * (pdfWidth - margin*2)) / chart3_canvas.width; pdf.addImage(chart3_img, 'PNG', margin, currentY, pdfWidth - (margin*2), chart3_img_height); pdf.save("SuDS_Forecast_Report.pdf"); setReportData(null); setIsGeneratingReport(false); }, 500); } catch (err) { setForecastError("Failed to generate report data."); setIsGeneratingReport(false); } };
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter