Sunday, February 9, 2025

calc

// Constants const INDUSTRY_BENCHMARKS = { 'Early Stage Startup (1-20 devs)': { avgSecurityHours: 6, avgFixTime: 12, delayedReleases: 3, avgImpact: 30000 }, 'Growth Stage (21-50 devs)': { avgSecurityHours: 8, avgFixTime: 16, delayedReleases: 4, avgImpact: 50000 }, 'Scale-up (51-200 devs)': { avgSecurityHours: 10, avgFixTime: 20, delayedReleases: 6, avgImpact: 100000 } }; // State management const state = { companySize: 'Growth Stage (21-50 devs)', benchmarkData: [], inputs: { numDevelopers: 5, avgSalary: 120000, securityHoursPerWeek: 8, avgFixTimeHours: 16, delayedReleasesPerYear: 4, avgRevenueImpactPerDelay: 50000, }, results: { annualTimeWaste: 0, annualCost: 0, potentialSavings: 0, revenueImpact: 0, totalBenefit: 0 } }; // Utility functions function formatCurrency(value) { return value.toLocaleString(undefined, {maximumFractionDigits: 0}); } function formatNumber(value) { return value.toLocaleString(); } // Calculation functions function calculateResults() { const weeksPerYear = 50; const annualTimeWaste = state.inputs.numDevelopers * state.inputs.securityHoursPerWeek * weeksPerYear; const hourlyRate = state.inputs.avgSalary / (40 * weeksPerYear); const annualCost = annualTimeWaste * hourlyRate; const potentialSavings = annualCost * 0.6; const revenueImpact = state.inputs.delayedReleasesPerYear * state.inputs.avgRevenueImpactPerDelay; const totalBenefit = potentialSavings + revenueImpact; state.results = { annualTimeWaste, annualCost, potentialSavings, revenueImpact, totalBenefit }; } function calculateBenchmarks() { state.benchmarkData = [ { metric: 'Security Hours/Week', your: state.inputs.securityHoursPerWeek, benchmark: INDUSTRY_BENCHMARKS[state.companySize].avgSecurityHours, difference: ((state.inputs.securityHoursPerWeek - INDUSTRY_BENCHMARKS[state.companySize].avgSecurityHours) / INDUSTRY_BENCHMARKS[state.companySize].avgSecurityHours * 100).toFixed(1) }, { metric: 'Fix Time (Hours)', your: state.inputs.avgFixTimeHours, benchmark: INDUSTRY_BENCHMARKS[state.companySize].avgFixTime, difference: ((state.inputs.avgFixTimeHours - INDUSTRY_BENCHMARKS[state.companySize].avgFixTime) / INDUSTRY_BENCHMARKS[state.companySize].avgFixTime * 100).toFixed(1) }, { metric: 'Delayed Releases/Year', your: state.inputs.delayedReleasesPerYear, benchmark: INDUSTRY_BENCHMARKS[state.companySize].delayedReleases, difference: ((state.inputs.delayedReleasesPerYear - INDUSTRY_BENCHMARKS[state.companySize].delayedReleases) / INDUSTRY_BENCHMARKS[state.companySize].delayedReleases * 100).toFixed(1) } ]; } // DOM Update functions function updateResults() { document.getElementById('annualTimeWaste').textContent = `${formatNumber(state.results.annualTimeWaste)} hours`; document.getElementById('annualCost').textContent = `$${formatCurrency(state.results.annualCost)}`; document.getElementById('potentialSavings').textContent = `$${formatCurrency(state.results.potentialSavings)}`; document.getElementById('totalBenefit').textContent = `$${formatCurrency(state.results.totalBenefit)}`; // Update analysis section document.getElementById('savedHours').textContent = formatNumber(state.results.annualTimeWaste * 0.6); document.getElementById('recoveredTime').textContent = formatCurrency(state.results.potentialSavings); document.getElementById('reducedDelays').textContent = formatCurrency(state.results.revenueImpact); document.getElementById('totalAnnualBenefit').textContent = formatCurrency(state.results.totalBenefit); } function updateBenchmarkChart() { // Clear previous chart if exists const chartContainer = document.getElementById('benchmarkChart'); chartContainer.innerHTML = ''; // Create new chart using a charting library of choice // This is a simplified version - you'd want to use a proper charting library state.benchmarkData.forEach(item => { const row = document.createElement('div'); row.className = 'benchmark-row'; row.innerHTML = ` ${item.metric}
${Number(item.difference) > 0 ? '+' : ''}${item.difference}% vs benchmark
`; chartContainer.appendChild(row); }); } // Event handlers function handleInputChange(event) { const { name, value } = event.target; state.inputs[name] = Number(value); calculateResults(); calculateBenchmarks(); updateResults(); updateBenchmarkChart(); } function handleCompanySizeChange(event) { state.companySize = event.target.value; calculateBenchmarks(); updateBenchmarkChart(); } // Initial setup function initializeCalculator() { // Set up input event listeners document.querySelectorAll('input[type="number"]').forEach(input => { input.addEventListener('change', handleInputChange); }); document.getElementById('companySize').addEventListener('change', handleCompanySizeChange); // Initialize calculations calculateResults(); calculateBenchmarks(); updateResults(); updateBenchmarkChart(); } // HTML structure document.addEventListener('DOMContentLoaded', () => { const container = document.createElement('div'); container.className = 'calculator-container'; container.innerHTML = `

Security Time-Waste Calculator

Annual Time Waste

Industry Benchmark Comparison

`; document.body.appendChild(container); initializeCalculator(); }); // Update benchmark chart using Chart.js function updateBenchmarkChart() { const ctx = document.getElementById('benchmarkChart').getContext('2d'); // Destroy existing chart if it exists if (window.benchmarkChart) { window.benchmarkChart.destroy(); } const labels = state.benchmarkData.map(item => item.metric); const yourData = state.benchmarkData.map(item => item.your); const benchmarkData = state.benchmarkData.map(item => item.benchmark); window.benchmarkChart = new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [ { label: 'Your Company', data: yourData, backgroundColor: '#4f46e5', }, { label: 'Industry Benchmark', data: benchmarkData, backgroundColor: '#9333ea', } ] }, options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', scales: { x: { beginAtZero: true, grid: { display: true, drawBorder: false, }, }, y: { grid: { display: false, }, } } } }); // Update benchmark stats const statsContainer = document.getElementById('benchmarkStats'); statsContainer.innerHTML = state.benchmarkData.map(item => `
${item.metric}
${Number(item.difference) > 0 ? '+' : ''}${item.difference}% vs benchmark
`).join('');

No comments: