// 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 = `
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:
Post a Comment