Work Commute Cost Savings Calculator
Commute Profile & Method 1 (e.g., Current)
General Commute Details
Method 1 Details
Driving Costs
Public Transport Costs
Ridesharing Costs
Carpooling Costs
Cycling/Walking Costs
Method 2 Details (e.g., Alternative)
Method 2 Details
Driving Costs
Public Transport Costs
Ridesharing Costs
Carpooling Costs
Cycling/Walking Costs
Commute Cost Comparison & Savings
Comparison based on N/A commute days/week.
| Cost Period | Method 1 | Method 2 |
|---|
Daily Commute Time:
Method 1: N/A hours
Method 2: N/A hours
Please fill in details for both commute methods and click "Calculate Comparison".
Switching from ${moreExpensiveMethodName} to ${cheaperMethodName} could save you:
- `;
periods.forEach(p => {
const saving = Math.abs(costsM1[p.toLowerCase()] - costsM2[p.toLowerCase()]);
savingsText += `
- Per ${p}: ${wccs_formatCurrency(saving)} `; }); savingsText += `
Both methods have similar estimated annual costs.
"; } savingsSummaryDiv.innerHTML = savingsText; // Display times document.getElementById('wccs-timeMethod1Name').textContent = method1Name; document.getElementById('wccs-timeMethod2Name').textContent = method2Name; document.getElementById('wccs-timeMethod1Display').textContent = typeof method1Time === 'number' ? method1Time.toFixed(1) : method1Time; document.getElementById('wccs-timeMethod2Display').textContent = typeof method2Time === 'number' ? method2Time.toFixed(1) : method2Time; wccs_openTab(null, 'wccs-tab3'); } catch (error) { console.error("Error calculating comparison:", error); alert("Error calculating: " + error.message); wccs_comparisonDataStore = null; } } function wccs_getMethodInputs(methodPrefix) { // Helper for PDF data const type = document.getElementById(`wccs-${methodPrefix}Type`).value; const inputs = { type: type, name: wccs_getInputText(`${methodPrefix}Name`) }; switch (type) { case 'driving': inputs.distance = wccs_getInputNum(`${methodPrefix}-driveDistance`); inputs.efficiency = wccs_getInputNum(`${methodPrefix}-fuelEfficiency`); inputs.fuelPrice = wccs_getInputNum(`${methodPrefix}-fuelPrice`); inputs.parkingPerDay = wccs_getInputNum(`${methodPrefix}-parkingPerDay`); inputs.tollsPerDay = wccs_getInputNum(`${methodPrefix}-tollsPerDay`); inputs.maintMonthly = wccs_getInputNum(`${methodPrefix}-maintenanceMonthly`); inputs.insuranceMonthly = wccs_getInputNum(`${methodPrefix}-insuranceMonthly`); inputs.carPaymentMonthly = wccs_getInputNum(`${methodPrefix}-carPaymentMonthly`); break; case 'publicTransport': inputs.costPerTrip = wccs_getInputNum(`${methodPrefix}-ptCostPerTrip`); inputs.dailyPass = wccs_getInputNum(`${methodPrefix}-ptDailyPass`); inputs.weeklyPass = wccs_getInputNum(`${methodPrefix}-ptWeeklyPass`); inputs.monthlyPass = wccs_getInputNum(`${methodPrefix}-ptMonthlyPass`); break; case 'ridesharing': inputs.rsCostOneWay = wccs_getInputNum(`${methodPrefix}-rsCostOneWay`); break; case 'carpooling': inputs.cpContributionDaily = wccs_getInputNum(`${methodPrefix}-cpContributionDaily`); break; case 'cyclingWalking': inputs.cwBikeMaintMonthly = wccs_getInputNum(`${methodPrefix}-cwBikeMaintMonthly`); break; } return inputs; } function wccs_downloadPDF() { if (!wccs_comparisonDataStore) { alert("Please calculate a comparison first."); return; } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF library (jsPDF) not loaded.'); console.error("jsPDF library not found."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); if (typeof doc.autoTable !== 'function') { alert('PDF Table plugin (jsPDF-AutoTable) not loaded.'); console.error("jsPDF-AutoTable plugin not found."); return; } const data = wccs_comparisonDataStore; const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--wccs-primary-color').trim(); const accentColor = getComputedStyle(document.documentElement).getPropertyValue('--wccs-accent-color').trim(); doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Work Commute Cost Savings Report", 105, 20, { align: 'center' }); let yPos = 30; doc.setFontSize(10); doc.setTextColor(50); doc.text(`Based on ${data.commuteDaysPerWeek} commute days/week. Comparison Period: ${data.comparisonPeriod}`, 105, yPos, {align:'center'}); yPos += 10; function addMethodDetailsToPdf(methodData, title) { doc.setFontSize(12); doc.setTextColor(primaryColor); doc.setFont(undefined, 'bold'); doc.text(title + ` (${methodData.name} - ${methodData.type})`, 14, yPos); yPos += 6; doc.setFont(undefined, 'normal'); doc.setTextColor(50); const detailsBody = []; switch (methodData.type) { case 'driving': detailsBody.push(["Round-trip Distance:", `${methodData.inputs.distance} (km/miles)`]); detailsBody.push(["Fuel Efficiency:", `${methodData.inputs.efficiency} (units/L or G)`]); detailsBody.push(["Fuel Price:", `${wccs_formatCurrency(methodData.inputs.fuelPrice)} / (L or G)`]); detailsBody.push(["Parking/Day:", wccs_formatCurrency(methodData.inputs.parkingPerDay)]); detailsBody.push(["Tolls/Day:", wccs_formatCurrency(methodData.inputs.tollsPerDay)]); detailsBody.push(["Maintenance/Month:", wccs_formatCurrency(methodData.inputs.maintMonthly)]); detailsBody.push(["Insurance/Month:", wccs_formatCurrency(methodData.inputs.insuranceMonthly)]); detailsBody.push(["Car Deprec./Pay/Month:", wccs_formatCurrency(methodData.inputs.carPaymentMonthly)]); break; case 'publicTransport': if(methodData.inputs.costPerTrip > 0) detailsBody.push(["Cost per One-Way Trip:", wccs_formatCurrency(methodData.inputs.costPerTrip)]); if(methodData.inputs.dailyPass > 0) detailsBody.push(["Daily Pass Cost:", wccs_formatCurrency(methodData.inputs.dailyPass)]); if(methodData.inputs.weeklyPass > 0) detailsBody.push(["Weekly Pass Cost:", wccs_formatCurrency(methodData.inputs.weeklyPass)]); if(methodData.inputs.monthlyPass > 0) detailsBody.push(["Monthly Pass Cost:", wccs_formatCurrency(methodData.inputs.monthlyPass)]); break; case 'ridesharing': detailsBody.push(["Avg. Cost One-Way:", wccs_formatCurrency(methodData.inputs.rsCostOneWay)]); break; case 'carpooling': detailsBody.push(["Contribution/Day:", wccs_formatCurrency(methodData.inputs.cpContributionDaily)]); break; case 'cyclingWalking': detailsBody.push(["Bike Maintenance/Month:", wccs_formatCurrency(methodData.inputs.cwBikeMaintMonthly)]); break; } if(typeof methodData.time === 'number') detailsBody.push(["Avg. Daily Commute Time:", `${methodData.time.toFixed(1)} hours`]); else detailsBody.push(["Avg. Daily Commute Time:", "N/A"]); if(detailsBody.length > 0) { doc.autoTable({ startY: yPos, body: detailsBody, theme: 'plain', styles: { fontSize: 9 }, columnStyles: {0: {fontStyle:'bold'}} }); yPos = doc.lastAutoTable.finalY + 5; } else { yPos +=3; } } addMethodDetailsToPdf(data.method1, "Method 1 Details"); addMethodDetailsToPdf(data.method2, "Method 2 Details"); yPos += 5; // Extra space before summary table doc.setFontSize(12); doc.setTextColor(primaryColor); doc.setFont(undefined, 'bold'); doc.text("Cost Comparison Summary", 14, yPos); yPos += 7; const summaryHeaders = ["Cost Period", data.method1.name, data.method2.name]; const summaryBody = []; ['Daily', 'Weekly', 'Monthly', 'Annually'].forEach(p => { summaryBody.push([ `Cost per ${p}`, wccs_formatCurrency(data.method1.costs[p.toLowerCase()]), wccs_formatCurrency(data.method2.costs[p.toLowerCase()]) ]); }); doc.autoTable({ startY: yPos, head: [summaryHeaders], body: summaryBody, theme: 'grid', headStyles: { fillColor: primaryColor, textColor: [255,255,255], fontStyle: 'bold', halign: 'center' }, columnStyles: { 1: { halign: 'right' }, 2: { halign: 'right' } }, styles: { fontSize: 9 } }); yPos = doc.lastAutoTable.finalY + 10; doc.setFontSize(10); doc.setTextColor(accentColor); doc.setFont(undefined, 'bold'); const annualCostM1 = data.method1.costs.annually; const annualCostM2 = data.method2.costs.annually; let savingsTextPdf = ""; if (annualCostM1 !== annualCostM2) { const cheaperMethodName = annualCostM1 < annualCostM2 ? data.method1.name : data.method2.name; const moreExpensiveMethodName = annualCostM1 < annualCostM2 ? data.method2.name : data.method1.name; savingsTextPdf = `${cheaperMethodName} is cheaper. Switching from ${moreExpensiveMethodName} to ${cheaperMethodName} could save:`; doc.text(savingsTextPdf, 14, yPos); yPos += 6; const periods = ['Daily', 'Weekly', 'Monthly', 'Annually']; const savingsBody = periods.map(p => { const saving = Math.abs(data.method1.costs[p.toLowerCase()] - data.method2.costs[p.toLowerCase()]); return [`Savings per ${p}:`, wccs_formatCurrency(saving)]; }); doc.autoTable({startY: yPos, body: savingsBody, theme:'plain', styles:{fontSize:9}, columnStyles:{0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY; } else { savingsTextPdf = "Both methods have similar estimated annual costs."; doc.text(savingsTextPdf, 14, yPos); yPos += 6; } // Footer const pageHeight = doc.internal.pageSize.height || doc.internal.pageSize.getHeight(); doc.setFontSize(8); doc.setTextColor(150); doc.text(`Generated on: ${new Date().toLocaleDateString('en-US', {year:'numeric', month:'short', day:'numeric'})}`, 14, pageHeight - 10); doc.text(`Work Commute Cost Savings Calculator`, doc.internal.pageSize.width - 14, pageHeight - 10, { align: 'right' }); doc.save("Work_Commute_Cost_Savings.pdf"); } // Initialize document.addEventListener('DOMContentLoaded', () => { if (wccs_tabs.length > 0 && wccs_tabs[0]) wccs_openTab(null, wccs_tabs[0].id); wccs_updateNavButtons(); wccs_toggleMethodFields('method1'); // Init method 1 fields wccs_toggleMethodFields('method2'); // Init method 2 fields const numInputs = document.querySelectorAll('.wccs-tool-container input[type="number"]'); numInputs.forEach(input => { if (input.value === '' && input.id !== 'wccs-commuteDaysPerWeek') { // Keep default for commute days input.value = '0'; } }); if(document.getElementById('wccs-commuteDaysPerWeek').value === '') document.getElementById('wccs-commuteDaysPerWeek').value = '5'; const primaryColorVal = getComputedStyle(document.documentElement).getPropertyValue('--wccs-primary-color').trim(); if (primaryColorVal.startsWith('#')) { const r = parseInt(primaryColorVal.slice(1, 3), 16); const g = parseInt(primaryColorVal.slice(3, 5), 16); const b = parseInt(primaryColorVal.slice(5, 7), 16); document.documentElement.style.setProperty('--wccs-primary-color-rgb', `${r},${g},${b}`); } });