Cryptocurrency Investment Risk Evaluator
Risk Evaluation Summary
Risk Level
--
(Score: -- / 100)
${levelInfo.text}
`; // Update Radar Chart const chartData = { labels: ['Market Cap', 'Volume', 'Age', 'Whitepaper', 'Dev Activity'], datasets: [{ label: 'Risk Factor Score', data: [ scores.marketCap / factors.marketCap.weight * 100, scores.tradingVolume / factors.tradingVolume.weight * 100, scores.coinAge / factors.coinAge.weight * 100, scores.whitepaperQuality / factors.whitepaperQuality.weight * 100, scores.devActivity / factors.devActivity.weight * 100, ], backgroundColor: 'rgba(59, 130, 246, 0.2)', borderColor: 'rgba(59, 130, 246, 1)', borderWidth: 2, pointBackgroundColor: 'rgba(59, 130, 246, 1)', }] }; if (riskRadarChart) riskRadarChart.destroy(); riskRadarChart = new Chart(radarCanvas, { type: 'radar', data: chartData, options: { responsive: true, maintainAspectRatio: true, scales: { r: { beginAtZero: true, max: 100, grid: { color: '#e5e7eb' }, angleLines: { color: '#e5e7eb' }, pointLabels: { font: { size: 12, weight: '500' }, color: '#374151' } } }, plugins: { legend: { display: false } } } }); // Store data for PDF window.currentRiskData = { scores, totalScore, riskLevel, inputs: getCurrentInputValues() }; }; const getCurrentInputValues = () => ({ coinName: inputs.coinName.value || 'N/A', marketCap: getSliderLabel('marketCap', inputs.marketCap.value), tradingVolume: getSliderLabel('tradingVolume', inputs.tradingVolume.value), coinAge: getSliderLabel('coinAge', inputs.coinAge.value), whitepaperQuality: factors.whitepaperQuality.values[inputs.whitepaperQuality.value], devActivity: factors.devActivity.values[inputs.devActivity.value], }); const generatePdf = () => { const data = window.currentRiskData; if (!data) { alert("Please evaluate risk first."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); const docWidth = doc.internal.pageSize.getWidth(); // --- PDF TEMPLATE --- doc.setFillColor(248, 250, 252); // gray-50 doc.rect(0, 0, docWidth, doc.internal.pageSize.getHeight(), 'F'); // Header doc.setFontSize(22); doc.setTextColor(30, 41, 59); // slate-800 doc.setFont('helvetica', 'bold'); doc.text("Cryptocurrency Risk Report", 40, 50); doc.setFontSize(11); doc.setFont('helvetica', 'normal'); doc.text(`For: ${data.inputs.coinName}`, 40, 70); doc.text(`Generated: ${new Date().toLocaleDateString('en-US')}`, docWidth - 40, 50, { align: 'right' }); // Risk Score Banner const levelInfo = riskLevels[data.riskLevel]; const bannerColor = { 'bg-red-700': [185, 28, 28], 'bg-red-500': [239, 68, 68], 'bg-yellow-500': [234, 179, 8], 'bg-green-500': [34, 197, 94], 'bg-green-700': [21, 128, 61] }[levelInfo.color]; doc.setFillColor(bannerColor[0], bannerColor[1], bannerColor[2]); doc.roundedRect(40, 90, docWidth - 80, 70, 10, 10, 'F'); doc.setTextColor(255, 255, 255); doc.setFontSize(14); doc.text("Overall Risk Assessment", 60, 115); doc.setFontSize(26); doc.setFont('helvetica', 'bold'); doc.text(data.riskLevel.toUpperCase(), docWidth - 60, 130, { align: 'right' }); let yPos = 190; // Input Parameters Table doc.setFontSize(14); doc.setTextColor(30, 41, 59); doc.text("Input Parameters", 40, yPos); doc.autoTable({ startY: yPos + 10, head: [['Factor', 'Selected Value']], body: Object.entries(data.inputs).filter(([key])=> key !== 'coinName').map(([key, value]) => { const formattedKey = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase()); return [formattedKey, value]; }), theme: 'striped', margin: { left: 40, right: 40 }, headStyles: { fillColor: [71, 85, 105] } }); yPos = doc.autoTable.previous.finalY + 30; // Radar Chart if (riskRadarChart) { const chartImage = riskRadarChart.toBase64Image('image/png', 1.0); doc.setFontSize(14); doc.setTextColor(30, 41, 59); doc.text("Risk Factor Analysis", 40, yPos); const chartWidth = 300; const chartX = (docWidth - chartWidth) / 2; doc.addImage(chartImage, 'PNG', chartX, yPos + 15, chartWidth, chartWidth); } // Footer doc.setFontSize(8); doc.setTextColor(156, 163, 175); doc.text("This is an automated evaluation based on user-provided data and should not be considered financial advice.", docWidth / 2, doc.internal.pageSize.getHeight() - 20, { align: 'center' }); doc.save(`Crypto_Risk_Report_${data.inputs.coinName.replace(/\s+/g, '_')}.pdf`); }; // --- EVENT LISTENERS --- Object.values(inputs).forEach(input => { input.addEventListener('input', () => { updateSliderDisplays(); updateUI(); }); }); downloadPdfBtn.addEventListener('click', generatePdf); // --- INITIALIZATION --- updateSliderDisplays(); updateUI(); });