NoSQL Visualization Dashboard

NoSQL Data Visualizer

Data Overview

Sales by Category

Sales by State

Invalid data format. Please provide an array of objects.

'; return; } const totalOrders = nosqlData.length; const totalRevenue = nosqlData.reduce((sum, order) => sum + (order.total || 0), 0); const avgOrderValue = totalRevenue / totalOrders || 0; const uniqueCustomers = new Set(nosqlData.map(order => order.customer?.id)).size; const stats = [ { label: 'Total Documents', value: totalOrders, icon: '📄' }, { label: 'Total Revenue', value: formatCurrency(totalRevenue), icon: '💰' }, { label: 'Avg. Order Value', value: formatCurrency(avgOrderValue), icon: '🛒' }, { label: 'Unique Customers', value: uniqueCustomers, icon: '👥' }, ]; statsGrid.innerHTML = stats.map(stat => `
${stat.icon}
${stat.label}
${stat.value}
`).join(''); renderCharts(); }; const renderCharts = () => { Object.values(charts).forEach(chart => chart.destroy()); if (!Array.isArray(nosqlData)) return; const salesByCategory = nosqlData.flatMap(o => o.items || []).reduce((acc, item) => { acc[item.category] = (acc[item.category] || 0) + (item.price * item.quantity); return acc; }, {}); const categoryCtx = document.getElementById('categoryChart'); if (categoryCtx) { charts.categoryChart = new Chart(categoryCtx, { type: 'doughnut', data: { labels: Object.keys(salesByCategory), datasets: [{ data: Object.values(salesByCategory), backgroundColor: ['#8b5cf6', '#3b82f6', '#10b981', '#f97316', '#ef4444'] }] }, options: { responsive: true, maintainAspectRatio: false } }); } const salesByState = nosqlData.reduce((acc, order) => { const state = order.customer?.state || 'Unknown'; acc[state] = (acc[state] || 0) + (order.total || 0); return acc; }, {}); const stateCtx = document.getElementById('stateChart'); if (stateCtx) { charts.stateChart = new Chart(stateCtx, { type: 'bar', data: { labels: Object.keys(salesByState), datasets: [{ label: 'Total Sales', data: Object.values(salesByState), backgroundColor: '#6d28d9' }] }, options: { responsive: true, maintainAspectRatio: false } }); } }; const renderJsonExplorer = () => { if (!jsonExplorerContainer) return; const createNode = (key, val) => { const li = document.createElement('li'); const keySpan = document.createElement('span'); keySpan.className = 'json-key'; keySpan.textContent = key; li.appendChild(keySpan); if (typeof val === 'object' && val !== null) { const nestedUl = document.createElement('ul'); nestedUl.className = 'json-nested hidden'; Object.entries(val).forEach(([nestedKey, nestedVal]) => { nestedUl.appendChild(createNode(nestedKey, nestedVal)); }); li.appendChild(nestedUl); keySpan.addEventListener('click', (e) => { e.stopPropagation(); keySpan.classList.toggle('open'); nestedUl.classList.toggle('hidden'); }); } else { const valSpan = document.createElement('span'); valSpan.className = 'json-value'; let typeClass = `json-${typeof val}`; valSpan.innerHTML = `: ${JSON.stringify(val)}`; li.appendChild(valSpan); } return li; }; jsonExplorerContainer.innerHTML = ''; const rootUl = document.createElement('ul'); Object.entries(nosqlData).forEach(([key, val]) => { rootUl.appendChild(createNode(key, val)); }); jsonExplorerContainer.appendChild(rootUl); }; const renderAll = () => { renderDashboard(); renderJsonExplorer(); }; // --- EVENT HANDLING --- // tabButtons.forEach((btn, index) => btn.addEventListener('click', () => switchTab(index))); prevBtn.addEventListener('click', () => switchTab(activeTabIndex - 1)); nextBtn.addEventListener('click', () => switchTab(activeTabIndex + 1)); updateDataBtn.addEventListener('click', () => { try { const newData = JSON.parse(jsonInput.value); nosqlData = newData; renderAll(); alert('Dashboard updated successfully!'); } catch (e) { alert('Error: Invalid JSON format. Please check your data.'); console.error("JSON Parse Error:", e); } }); downloadPdfBtn.addEventListener('click', () => { if (!Array.isArray(nosqlData)) { alert('Cannot generate PDF with invalid data.'); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); const totalOrders = nosqlData.length; const totalRevenue = nosqlData.reduce((sum, order) => sum + (order.total || 0), 0); doc.setFontSize(18); doc.text("NoSQL Data Report", 14, 22); doc.setFontSize(11); doc.text(`Total Documents: ${totalOrders} | Total Revenue: ${formatCurrency(totalRevenue)}`, 14, 30); const head = [['Order ID', 'Date', 'Customer', 'State', 'Total']]; const body = nosqlData.map(o => [o.orderId, o.date, o.customer?.name || 'N/A', o.customer?.state || 'N/A', formatCurrency(o.total || 0)]); doc.autoTable({ head: head, body: body, startY: 40, theme: 'grid', headStyles: { fillColor: [109, 40, 217] }, // violet-700 }); const finalY = doc.lastAutoTable.finalY; if (finalY + 90 < doc.internal.pageSize.height) { doc.text("Charts", 14, finalY + 15); const categoryChartImg = charts.categoryChart.toBase64Image(); doc.addImage(categoryChartImg, 'PNG', 14, finalY + 20, 80, 80); const stateChartImg = charts.stateChart.toBase64Image(); doc.addImage(stateChartImg, 'PNG', 105, finalY + 20, 90, 60); } doc.save('NoSQL_Data_Report.pdf'); }); // --- INITIALIZATION --- // jsonInput.value = JSON.stringify(sampleJson, null, 2); switchTab(0); renderAll(); });
Scroll to Top