Deadline Tracking Dashboard

Deadline Tracking Dashboard

Upcoming Deadlines

Overview of your tasks and their current status.

Deadlines by Status

Configure Deadlines

Add, edit, or remove deadlines for your projects and tasks.

Add/Edit Deadline

ID Task Name Due Date Status Priority Actions

Notes: ${d.notes || 'N/A'}

${d.status} ${d.priority} Priority `; deadlineCardsContainer.appendChild(card); }); } /** * Renders a bar chart of deadlines by status using D3.js. */ function renderStatusChart() { if (!statusChartContainer) { console.error('Error: statusChartContainer not found.'); return; } // Clear previous chart, but keep the title div const chartSvg = statusChartContainer.querySelector('svg'); if (chartSvg) { chartSvg.remove(); } if (deadlines.length === 0) { // No need to display chart if no data, the cards container handles this message return; } // Aggregate data by status const statusCounts = d3.rollup(deadlines, v => v.length, d => d.status); const chartData = Array.from(statusCounts, ([status, count]) => ({ status, count })); // Ensure all possible statuses are present, even if count is 0 const allStatuses = ['Not Started', 'In Progress', 'Completed', 'Overdue']; allStatuses.forEach(status => { if (!chartData.some(d => d.status === status)) { chartData.push({ status, count: 0 }); } }); // Sort chart data by a custom order for statuses const statusOrder = { 'Overdue': 0, 'In Progress': 1, 'Not Started': 2, 'Completed': 3 }; chartData.sort((a, b) => statusOrder[a.status] - statusOrder[b.status]); const margin = { top: 20, right: 20, bottom: 40, left: 40 }; const width = statusChartContainer.clientWidth - margin.left - margin.right; const height = statusChartContainer.clientHeight - margin.top - margin.bottom - 30; // Account for title height const svg = d3.select(statusChartContainer) .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", `translate(${margin.left},${margin.top})`); // X scale const x = d3.scaleBand() .domain(chartData.map(d => d.status)) .range([0, width]) .padding(0.1); // Y scale const y = d3.scaleLinear() .domain([0, d3.max(chartData, d => d.count) * 1.2]) // 20% buffer for count .range([height, 0]); // Add X axis svg.append("g") .attr("class", "chart-axis x-axis") .attr("transform", `translate(0,${height})`) .call(d3.axisBottom(x)); // Add Y axis svg.append("g") .attr("class", "chart-axis y-axis") .call(d3.axisLeft(y).tickFormat(d3.format("d"))); // Integer ticks // Tooltip const tooltip = d3.select("body").append("div") .attr("class", "chart-tooltip") .style("opacity", 0); // Add bars svg.selectAll(".chart-bar") .data(chartData) .enter().append("rect") .attr("class", "chart-bar") .attr("x", d => x(d.status)) .attr("y", d => y(d.count)) .attr("width", x.bandwidth()) .attr("height", d => height - y(d.count)) .attr("fill", d => { // Color bars based on status switch (d.status) { case 'Not Started': return '#6c757d'; case 'In Progress': return '#007bff'; case 'Completed': return '#28a745'; case 'Overdue': return '#dc3545'; default: return 'steelblue'; } }) .on("mouseover", function(event, d) { d3.select(this).attr("fill", d3.rgb(this.getAttribute('fill')).darker(0.5)); tooltip.transition() .duration(200) .style("opacity", .9); tooltip.html(`Status: ${d.status}
Count: ${d.count}`) .style("left", (event.pageX + 10) + "px") .style("top", (event.pageY - 28) + "px"); }) .on("mouseout", function(d) { d3.select(this).attr("fill", d3.rgb(this.getAttribute('fill')).brighter(0.5)); // Restore original color tooltip.transition() .duration(500) .style("opacity", 0); }); } // --- PDF Download Function --- /** * Generates and downloads a PDF of the current dashboard content. */ window.downloadPdf = async function() { if (!dashboardTab) { console.error('Error: Dashboard tab content not found for PDF generation.'); return; } // Temporarily hide elements not needed in PDF const elementsToHide = document.querySelectorAll('.tab-nav, .nav-buttons, #downloadPdfButton, .chart-tooltip'); elementsToHide.forEach(el => el.style.display = 'none'); // Ensure the dashboard tab is active for capture dashboardTab.classList.add('active'); // Capture deadline cards const cardsCanvas = await html2canvas(deadlineCardsContainer, { scale: 2, useCORS: true, logging: false }); const cardsImgData = cardsCanvas.toDataURL('image/png'); // Capture chart const chartCanvas = await html2canvas(statusChartContainer, { scale: 2, useCORS: true, logging: false }); const chartImgData = chartCanvas.toDataURL('image/png'); // Re-show hidden elements immediately after capture elementsToHide.forEach(el => el.style.display = ''); const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'portrait', unit: 'px', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); let yOffset = 40; // Add title to PDF pdf.setFontSize(22); pdf.text("Deadline Tracking Report", pdfWidth / 2, yOffset, { align: 'center' }); yOffset += 20; // Add current date/time to PDF pdf.setFontSize(10); pdf.text(`Generated on: ${new Date().toLocaleString()}`, pdfWidth / 2, yOffset, { align: 'center' }); yOffset += 40; // Add Deadline Cards Image pdf.setFontSize(18); pdf.text("Upcoming Deadlines Overview", pdfWidth / 2, yOffset, { align: 'center' }); yOffset += 10; const cardsImgHeight = (cardsCanvas.height * (pdfWidth - 40)) / cardsCanvas.width; pdf.addImage(cardsImgData, 'PNG', 20, yOffset, pdfWidth - 40, cardsImgHeight); yOffset += cardsImgHeight + 30; // Add Status Chart Image pdf.setFontSize(18); pdf.text("Deadlines by Status Chart", pdfWidth / 2, yOffset, { align: 'center' }); yOffset += 10; const chartImgHeight = (chartCanvas.height * (pdfWidth - 40)) / chartCanvas.width; pdf.addImage(chartImgData, 'PNG', 20, yOffset, pdfWidth - 40, chartImgHeight); yOffset += chartImgHeight + 30; // Add a section for detailed data (tabular format) pdf.addPage(); pdf.setFontSize(18); pdf.text("Detailed Deadlines Table", pdf.internal.pageSize.getWidth() / 2, 40, { align: 'center' }); const tableData = deadlines.map(d => [ d.id, d.taskName, d.dueDate, d.status, d.priority, d.notes || 'N/A' ]); pdf.autoTable({ head: [['ID', 'Task Name', 'Due Date', 'Status', 'Priority', 'Notes']], body: tableData, startY: 60, theme: 'grid', styles: { fontSize: 8, cellPadding: 4 }, headStyles: { fillColor: [242, 242, 242], textColor: [51, 51, 51], fontStyle: 'bold' }, alternateRowStyles: { fillColor: [251, 251, 251] }, margin: { top: 70, left: 10, right: 10 } // Adjust margins for more columns }); pdf.save('deadline_tracking_report.pdf'); }; // --- Event Listeners and Initial Render --- downloadPdfButton.addEventListener('click', downloadPdf); // Initial setup // Sort deadlines by due date initially deadlines.sort((a, b) => new Date(a.dueDate) - new Date(b.dueDate)); updateConfigTable(); renderDeadlineCards(); renderStatusChart(); updateNavigationButtons(); // Set initial button states });
Scroll to Top