Work Output Analyzer

Work Output Analyzer

Log New Work Output

Manage Output Categories

    Logged Work Outputs

    DateOutputCategoryQty Time (hrs)ImpactComplexityActions

    Note: Output data is stored in your browser's LocalStorage.

    Dashboard Filters

    Log work outputs and select a date range to view the dashboard.

    No work outputs logged. Please log outputs in Tab 1 to see the dashboard.

    '; return; } const startDateStr = document.getElementById('woa-analysis-start-date').value; const endDateStr = document.getElementById('woa-analysis-end-date').value; const filterCategory = document.getElementById('woa-filter-category-dashboard').value; if(!startDateStr || !endDateStr) { return; } const startDate = new Date(startDateStr + "T00:00:00"); const endDate = new Date(endDateStr + "T23:59:59"); let filteredOutputs = woaLoggedOutputs.filter(out => out.dateObj >= startDate && out.dateObj <= endDate); if (filterCategory !== "All") { filteredOutputs = filteredOutputs.filter(out => out.category === filterCategory); } if (filteredOutputs.length === 0 && woaCurrentTabIndex === 1) { // Check if on dashboard tab document.getElementById('woa-dashboard-display').innerHTML = '

    No work outputs found for the selected filters/date range.

    '; if(woaChartCategoryInstance) woaChartCategoryInstance.destroy(); if(woaChartImpactInstance) woaChartImpactInstance.destroy(); if(woaChartTrendInstance) woaChartTrendInstance.destroy(); return; } let timeByCategory = {}; woaCategories.forEach(cat => timeByCategory[cat] = 0); let countByCategory = {}; woaCategories.forEach(cat => countByCategory[cat] = 0); let timeByImpact = { High: 0, Medium: 0, Low: 0 }; let countByImpact = { High: 0, Medium: 0, Low: 0 }; let totalLoggedTime = 0; let totalOutputsCount = 0; filteredOutputs.forEach(out => { timeByCategory[out.category] = (timeByCategory[out.category] || 0) + (out.timeSpent * out.quantity); countByCategory[out.category] = (countByCategory[out.category] || 0) + out.quantity; timeByImpact[out.impact] = (timeByImpact[out.impact] || 0) + (out.timeSpent * out.quantity); countByImpact[out.impact] = (countByImpact[out.impact] || 0) + out.quantity; totalLoggedTime += (out.timeSpent * out.quantity); totalOutputsCount += out.quantity; }); // Prepare data for Trend Chart (Output count over time) let trendData = {}; // { "YYYY-MM-DD": count } filteredOutputs.forEach(out => { const dateKey = out.dateObj.toISOString().split('T')[0]; trendData[dateKey] = (trendData[dateKey] || 0) + out.quantity; }); const sortedTrendData = Object.keys(trendData).sort((a,b) => new Date(a) - new Date(b)).map(dateKey => ({x: new Date(dateKey+"T00:00:00"), y: trendData[dateKey]})); let dashboardHTML = `

    Key Metrics (${startDate.toLocaleDateString()} - ${endDate.toLocaleDateString()})

    • Total Outputs Logged: ${totalOutputsCount}
    • Total Time on Outputs: ${totalLoggedTime.toFixed(1)} hrs
    • Avg. Time per Output: ${(totalOutputsCount > 0 ? totalLoggedTime / totalOutputsCount : 0).toFixed(1)} hrs
    • Time on High-Impact: ${(timeByImpact["High"] / 60 * 100 / (totalLoggedTime||1)).toFixed(0)}% (${(timeByImpact["High"]).toFixed(1)} hrs)

    Output Count by Category

    Time Spent by Category

    Output Count by Impact

    Time Spent by Impact

    Output Trend (Count over Time)

    Analysis Insights

      `; document.getElementById('woa-dashboard-display').innerHTML = dashboardHTML; // Render Charts woaRenderBarOrPieChart('woa-category-count-chart', countByCategory, 'Output Count by Category', 'bar'); woaRenderBarOrPieChart('woa-category-time-chart', timeByCategory, 'Time (hrs) by Category', 'pie'); woaRenderBarOrPieChart('woa-impact-count-chart', countByImpact, 'Output Count by Impact', 'pie'); woaRenderBarOrPieChart('woa-impact-time-chart', timeByImpact, 'Time (hrs) by Impact', 'bar'); woaRenderLineChart('woa-output-trend-chart', sortedTrendData, 'Output Count Over Time'); // Generate Insights const insightsListEl = document.getElementById('woa-insights-list'); insightsListEl.innerHTML = ''; let insightsGenerated = 0; if(totalLoggedTime > 0){ if ((timeByImpact["Low"] / totalLoggedTime) > 0.3) { insightsListEl.innerHTML += `
    • Over 30% of your time is spent on activities you perceive as Low Impact. Consider strategies to reduce or delegate these.
    • `; insightsGenerated++;} if ((timeByCategory["Focused Work"] / totalLoggedTime) < 0.4 && timeByCategory["Focused Work"] !== undefined) { insightsListEl.innerHTML += `
    • Less than 40% of time is on 'Focused Work'. If deep work is important, look for ways to increase dedicated focus blocks.
    • `; insightsGenerated++;} if ((timeByCategory["Meetings"] / totalLoggedTime) > 0.35 && timeByCategory["Meetings"] !== undefined) { insightsListEl.innerHTML += `
    • Meetings take up over 35% of your logged time. Evaluate their necessity and efficiency.
    • `; insightsGenerated++;} // Find category with most time spent let maxTime = 0; let maxCat = ''; for(const cat in timeByCategory){ if(timeByCategory[cat] > maxTime) {maxTime = timeByCategory[cat]; maxCat = cat;} } if(maxCat && totalLoggedTime > 0) insightsListEl.innerHTML += `
    • Your most time-consuming category is '${maxCat}', accounting for ${(maxTime/totalLoggedTime*100).toFixed(0)}% of logged hours.
    • `; } if(insightsGenerated === 0 && totalLoggedTime > 0) insightsListEl.innerHTML += `
    • Your output distribution seems balanced based on the current rules. Keep tracking to identify personal trends!
    • `; else if (totalLoggedTime === 0) insightsListEl.innerHTML += `
    • No output logged in this period to provide insights.
    • `; } function woaRenderBarOrPieChart(canvasId, dataObject, chartLabel, type = 'pie') { const ctx = document.getElementById(canvasId); if (!ctx) return; const labels = Object.keys(dataObject).filter(key => dataObject[key] > 0); // Only show categories with data const data = labels.map(key => dataObject[key]); const chartColors = ['#7E57C2', '#26C6DA', '#FFCA28', '#66BB6A', '#EF5350', '#AB47BC', '#FFA726', '#42A5F5', '#26A69A', '#EC407A']; const backgroundColors = labels.map((_, i) => chartColors[i % chartColors.length]); let existingChartInstance; if (canvasId === 'woa-category-count-chart') existingChartInstance = window.woaChartCatCountInst; else if (canvasId === 'woa-category-time-chart') existingChartInstance = window.woaChartCatTimeInst; else if (canvasId === 'woa-impact-count-chart') existingChartInstance = window.woaChartImpCountInst; else if (canvasId === 'woa-impact-time-chart') existingChartInstance = window.woaChartImpTimeInst; if (existingChartInstance) existingChartInstance.destroy(); const chartConfig = { type: type, data: { labels: labels, datasets: [{ label: chartLabel, data: data, backgroundColor: backgroundColors, borderColor: '#fff', borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: type==='pie'?'right':'top', labels:{boxWidth:15, font:{size:10}} }, tooltip: { callbacks: { label: function(context) { let label = context.label || ''; if (label) label += ': '; if (context.parsed !== null) { label += context.parsed.toFixed(1) + (chartLabel.toLowerCase().includes("time") ? ' hrs' : ''); if (type === 'pie') { const total = context.dataset.data.reduce((a,b) => a+b, 0); const percentage = total > 0 ? (context.parsed / total * 100).toFixed(1) : 0; label += ` (${percentage}%)`; } } return label; } } } } } }; if(type === 'bar') { chartConfig.options.scales = { y: { beginAtZero: true, title: {display: true, text: chartLabel.includes("Time") ? "Hours" : "Count"} } }; } const newChartInstance = new Chart(ctx.getContext('2d'), chartConfig); if (canvasId === 'woa-category-count-chart') window.woaChartCatCountInst = newChartInstance; else if (canvasId === 'woa-category-time-chart') window.woaChartCatTimeInst = newChartInstance; else if (canvasId === 'woa-impact-count-chart') window.woaChartImpCountInst = newChartInstance; else if (canvasId === 'woa-impact-time-chart') window.woaChartImpTimeInst = newChartInstance; } function woaRenderLineChart(canvasId, dataPoints, chartLabel) { // dataPoints = [{x: Date, y: value}] const ctx = document.getElementById(canvasId); if (!ctx) return; if (window.woaChartTrendInstance) window.woaChartTrendInstance.destroy(); window.woaChartTrendInstance = new Chart(ctx.getContext('2d'), { type: 'line', data: { datasets: [{ label: chartLabel, data: dataPoints, borderColor: 'var(--primary-color)', backgroundColor: 'rgba(126, 87, 194, 0.1)', tension: 0.1, fill: true }] }, options: { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'day', tooltipFormat: 'MMM dd, yyyy', displayFormats: {'day': 'MMM dd'} } }, y: { beginAtZero: true, title: { display: true, text: "Output Count" } } }, plugins: { legend: { display: false } } } }); } // PDF Download function woaDownloadPDF() { const dashboardDisplayElement = document.getElementById('woa-dashboard-display'); if (!dashboardDisplayElement || dashboardDisplayElement.innerHTML.includes("Log work outputs")) { alert("Please generate the dashboard first."); return; } const analysisStartDate = document.getElementById('woa-analysis-start-date').value; const analysisEndDate = document.getElementById('woa-analysis-end-date').value; let pdfHTML = `

      Work Output Analysis Report

      `; pdfHTML += `

      Analysis Period: ${analysisStartDate} to ${analysisEndDate}

      `; const metricsCardContent = dashboardDisplayElement.querySelector('.woa-metrics-card'); if(metricsCardContent) pdfHTML += `

      Key Metrics

      ${metricsCardContent.innerHTML.replace(/

      .*<\/h4>/, '')}`; // Remove h4 for PDF const chartsToInclude = [ {instance: window.woaChartCatCountInst, title: "Output Count by Category"}, {instance: window.woaChartCatTimeInst, title: "Time Spent by Category"}, {instance: window.woaChartImpCountInst, title: "Output Count by Impact"}, {instance: window.woaChartImpTimeInst, title: "Time Spent by Impact"}, {instance: window.woaChartTrendInst, title: "Output Trend (Count over Time)"} ]; chartsToInclude.forEach(chartInfo => { if(chartInfo.instance){ pdfHTML += `

      ${chartInfo.title}

      `; } }); const insightsCardContent = dashboardDisplayElement.querySelector('.woa-insights-card'); if(insightsCardContent) pdfHTML += `
      ${insightsCardContent.innerHTML.replace(/

      .*<\/h4>/, '

      Analysis Insights

      ')}`; const filteredOutputsForPDF = woaLoggedOutputs.filter(out => { const outDateOnly = out.dateObj.toISOString().split('T')[0]; return outDateOnly >= analysisStartDate && outDateOnly <= analysisEndDate; }); if (filteredOutputsForPDF.length > 0) { pdfHTML += `

      Detailed Output Log (${analysisStartDate} to ${analysisEndDate})

      `; pdfHTML += ``; filteredOutputsForPDF.forEach(out => { pdfHTML += ``; }); pdfHTML += `
      DateOutputCategoryQtyTime (hrs)ImpactComplexity
      ${out.dateObj.toLocaleDateString()}${out.name}${out.category} ${out.quantity}${out.timeSpent.toFixed(1)} ${out.impact}${out.complexity || 'N/A'}
      `; } const pdfContainer = document.getElementById('woa-report-content-for-pdf'); pdfContainer.innerHTML = pdfHTML; pdfContainer.querySelectorAll('.woa-impact-tag').forEach(tag => { if (tag.classList.contains('impact-High')) { tag.style.backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--impact-high-bg'); tag.style.color = getComputedStyle(document.documentElement).getPropertyValue('--impact-high-text');} else if (tag.classList.contains('impact-Medium')) { tag.style.backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--impact-medium-bg'); tag.style.color = getComputedStyle(document.documentElement).getPropertyValue('--impact-medium-text');} else if (tag.classList.contains('impact-Low')) { tag.style.backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--impact-low-bg'); tag.style.color = getComputedStyle(document.documentElement).getPropertyValue('--impact-low-text');} }); const opt = { margin: [0.5, 0.3, 0.5, 0.3], filename: `Work_Output_Analysis_${analysisStartDate}_to_${analysisEndDate}.pdf`, image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2, useCORS: true, logging: false, scrollX:0, scrollY: -window.scrollY, windowWidth: pdfContainer.scrollWidth + 100 }, jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }, pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } }; html2pdf().from(pdfContainer).set(opt).save().then(() => { pdfContainer.innerHTML = ''; }).catch(err => { console.error("Error generating PDF:", err); pdfContainer.innerHTML = ''; alert("An error occurred while generating the PDF. Check console for details."); }); }
      Scroll to Top