Weighted Average Contribution Margin Per Unit Calculator
Streamline your profitability analysis.
Calculate Weighted Average Contribution Margin Per Unit
Results
—
Weighted Average Selling Price Per Unit: —
Weighted Average Variable Cost Per Unit: —
Total Contribution Margin: —
Formula Used: Weighted Average Contribution Margin Per Unit = Weighted Average Selling Price Per Unit – Weighted Average Variable Cost Per Unit
Where:
Weighted Average Selling Price Per Unit = Σ(Selling Price of Productᵢ * Units Sold of Productᵢ) / Σ(Units Sold of Productᵢ)
Weighted Average Variable Cost Per Unit = Σ(Variable Cost per Unit of Productᵢ * Units Sold of Productᵢ) / Σ(Units Sold of Productᵢ)
Total Contribution Margin = Σ(Contribution Margin per Unit of Productᵢ * Units Sold of Productᵢ)
Contribution Margin Breakdown
Understanding How to Calculate Weighted Average Contribution Margin Per Unit
What is Weighted Average Contribution Margin Per Unit?
The weighted average contribution margin per unit is a crucial financial metric that helps businesses understand the profitability of their product mix. It represents the average profit generated by each unit sold across all products, considering the volume of sales for each product. Unlike a simple average, the weighted average accounts for how many units of each product are sold, giving more importance to higher-volume products. This metric is essential for making informed decisions regarding pricing, sales strategies, product development, and overall business planning. Businesses of all sizes, from small startups to large corporations, can benefit from understanding and tracking their weighted average contribution margin per unit. It provides a clearer picture of profitability than looking at individual products in isolation, especially when dealing with a diverse product portfolio with varying sales volumes and profit margins.
Who Should Use It?
Anyone involved in financial analysis, strategic planning, or operational management within a business can benefit from understanding the weighted average contribution margin per unit. This includes:
Financial Analysts: To assess overall product profitability and forecast financial performance.
Sales Managers: To understand which products are most profitable on average and to guide sales efforts.
Marketing Teams: To inform pricing strategies and promotional activities based on profitability.
Product Developers: To identify which products contribute most to the bottom line and where R&D efforts might be best focused.
Business Owners and Executives: To make strategic decisions about resource allocation, product mix optimization, and overall business direction.
Common Misconceptions:
It's the same as a simple average: This is incorrect. The weighted average factors in sales volume, making it a more accurate representation of average profitability per unit sold across all products.
It only applies to large businesses: Small businesses with multiple product lines can gain significant insights from this metric, helping them optimize their limited resources.
It's too complex to calculate: While it involves multiple steps, with the right tools like our calculator, it's accessible and straightforward.
Weighted Average Contribution Margin Per Unit Formula and Mathematical Explanation
The core idea behind the weighted average contribution margin per unit is to find a single, representative figure that reflects the profitability of each unit sold, taking into account the sales mix. The formula is derived from the concepts of weighted averages and contribution margins.
Step-by-Step Derivation:
Calculate the Contribution Margin Per Unit for Each Product: For each product, subtract its variable cost per unit from its selling price per unit.
Contribution Margin per Unit (CMᵢ) = Selling Price per Unit (SPᵢ) – Variable Cost per Unit (VCᵢ)
Calculate the Total Contribution Margin for Each Product: Multiply the contribution margin per unit by the number of units sold for that product.
Total CMᵢ = CMᵢ * Units Sold (Uᵢ)
Calculate the Total Contribution Margin for All Products: Sum up the total contribution margins calculated in step 2 for all products.
Total Overall CM = Σ (Total CMᵢ)
Calculate the Total Units Sold for All Products: Sum up the units sold for all products.
Total Units Sold (Total U) = Σ (Uᵢ)
Calculate the Weighted Average Contribution Margin Per Unit: Divide the Total Overall Contribution Margin by the Total Units Sold.
Weighted Average Contribution Margin Per Unit (WACM) = Total Overall CM / Total U
Alternatively, you can calculate the weighted average selling price and weighted average variable cost separately and then find their difference:
Weighted Average Selling Price Per Unit (WASP) = Σ(SPᵢ * Uᵢ) / Total U
Weighted Average Variable Cost Per Unit (WAVC) = Σ(VCᵢ * Uᵢ) / Total U
WACM = WASP – WAVC
Both methods yield the same result, providing a robust way to understand your average per-unit profitability.
Variables Explanation
Variable
Meaning
Unit
Typical Range
SPᵢ
Selling Price per Unit for Product i
Currency (e.g., USD, EUR)
Positive value, depends on market and product
VCᵢ
Variable Cost per Unit for Product i
Currency (e.g., USD, EUR)
Non-negative value, less than SPᵢ
CMᵢ
Contribution Margin per Unit for Product i
Currency (e.g., USD, EUR)
Non-negative value
Uᵢ
Units Sold for Product i
Count (e.g., units, pieces)
Non-negative integer (or decimal for fractional units)
Total Overall CM: $10,000 + $18,000 + $7,500 = $35,500
Total Units Sold: 100 + 300 + 500 = 900
Weighted Average Contribution Margin Per Unit: $35,500 / 900 = $39.44
Interpretation: On average, each headphone unit sold contributes approximately $39.44 towards covering fixed costs and generating profit. Although the premium headphones have the highest per-unit CM ($100), the mid-range earbuds contribute significantly due to higher volume. The basic earphones, while having the lowest per-unit CM ($15), are high-volume drivers that contribute substantially to the overall CM.
Example 2: SaaS Company with Tiered Subscriptions
A software company offers three subscription tiers:
Plan 1: Basic
Monthly Recurring Revenue (MRR) per customer: $50
Variable Cost per customer (support, transaction fees): $10
Number of Customers: 1000
Plan 2: Pro
Monthly Recurring Revenue (MRR) per customer: $150
Variable Cost per customer: $25
Number of Customers: 500
Plan 3: Enterprise
Monthly Recurring Revenue per customer: $500
Variable Cost per customer: $50
Number of Customers: 100
Note: For SaaS, "Selling Price" is typically MRR, and "Units Sold" is the number of customers.
Calculation Steps:
Plan 1 CM: $50 – $10 = $40
Plan 2 CM: $150 – $25 = $125
Plan 3 CM: $500 – $50 = $450
Total CM for Plan 1: $40 * 1000 = $40,000
Total CM for Plan 2: $125 * 500 = $62,500
Total CM for Plan 3: $450 * 100 = $45,000
Total Overall CM: $40,000 + $62,500 + $45,000 = $147,500
Total Customers (Units): 1000 + 500 + 100 = 1600
Weighted Average Contribution Margin Per Unit (per customer/month): $147,500 / 1600 = $92.19
Interpretation: The weighted average contribution margin per customer per month is $92.19. This indicates that, on average, each active customer generates $92.19 in contribution margin monthly. The higher CM of the Enterprise plan significantly boosts this average, even with fewer customers.
How to Use This Weighted Average Contribution Margin Per Unit Calculator
Our calculator is designed for simplicity and accuracy. Follow these steps:
Enter the Number of Products: Start by specifying how many distinct products or service lines your business offers.
Input Product Details: For each product, you will see input fields. Enter:
Selling Price per Unit: The price at which you sell one unit of the product.
Variable Cost per Unit: All costs directly associated with producing or acquiring one unit (e.g., materials, direct labor, commissions).
Units Sold: The total quantity of this product sold during the period you are analyzing.
You can add more product lines using the "Add Product" button or remove them using "Remove Product".
Click Calculate: Once all your data is entered, press the "Calculate" button.
Review the Results: The calculator will display:
Weighted Average Contribution Margin Per Unit: This is your primary result, highlighted prominently.
Weighted Average Selling Price Per Unit: The average selling price, weighted by units sold.
Weighted Average Variable Cost Per Unit: The average variable cost, weighted by units sold.
Total Contribution Margin: The sum of contribution margins from all products.
Understand the Formula: The calculator explains the formula used for clarity.
Analyze Key Assumptions: This section outlines the data you entered, serving as a reminder of the inputs used.
Examine the Chart: The dynamic chart provides a visual breakdown of the contribution margin by product, helping you quickly identify which products are your biggest profit drivers.
Copy Results: Use the "Copy Results" button to easily transfer the calculated metrics and assumptions to your reports or spreadsheets.
Reset: The "Reset" button clears all fields, allowing you to start fresh.
Decision-Making Guidance: A higher weighted average contribution margin per unit generally indicates better profitability. If the result is lower than expected, consider strategies to increase prices, reduce variable costs, or shift sales focus towards higher-margin products. Use this metric alongside break-even analysis to set sales targets.
Key Factors That Affect Weighted Average Contribution Margin Results
Several elements can influence the weighted average contribution margin per unit, impacting your business's perceived profitability and strategic decisions:
Sales Mix Volume:The proportion of total sales volume contributed by each product. A shift towards lower-margin products, even if high-volume, will decrease the weighted average. Conversely, increasing the sales of higher-margin products will boost it.
A significant change in the number of units sold for different products directly alters the 'weight' each product's margin has on the average. If a company sells many low-margin items and few high-margin items, the WACM will be pulled down.
Pricing Strategies:The prices set for each product. Price adjustments directly impact the contribution margin per unit for individual products and, consequently, the weighted average.
Any change in the selling price of individual products will affect their contribution margin. A strategic price increase on a high-volume product can significantly lift the WACM, while a price decrease might lower it.
Variable Cost Management:Costs directly tied to producing or selling a unit, such as raw materials, direct labor, and sales commissions. Reducing these costs increases the CM per unit.
Fluctuations in the cost of raw materials, manufacturing efficiencies, or changes in sales commission structures directly impact the variable cost per unit. Lowering these costs, especially for high-volume products, improves the WACM.
Product Lifecycle Stage:The phase a product is in (introduction, growth, maturity, decline), which often correlates with pricing flexibility and cost structure.
New products might have higher initial variable costs or lower introductory prices, impacting the WACM. Mature products may have optimized costs and stable pricing. Products in decline might see price erosion or increased marketing costs.
Promotions and Discounts:Temporary price reductions or bundled offers that can reduce the effective selling price per unit.
Offering discounts or running sales promotions effectively lowers the selling price for a period, reducing the contribution margin for those specific sales and potentially lowering the weighted average if the promotion is widespread or on high-volume items.
Economic Conditions and Competition:External factors like inflation, recessions, and competitive pressures that can force price adjustments or impact demand.
A competitive market might force prices down or necessitate higher marketing spend (increasing variable costs), thereby reducing contribution margins. Economic downturns can reduce overall sales volume and put pressure on pricing.
Frequently Asked Questions (FAQ)
Q1: What is the difference between contribution margin and gross margin?
Contribution margin focuses on variable costs only (e.g., materials, direct labor, sales commissions), while gross margin subtracts the cost of goods sold (COGS), which may include both fixed and variable manufacturing overheads. Contribution margin is more useful for short-term decisions like pricing and product mix, whereas gross margin is a broader measure of production efficiency.
Q2: Can the weighted average contribution margin per unit be negative?
Yes, it can be negative if the weighted average variable cost per unit exceeds the weighted average selling price per unit. This indicates that, on average, each unit sold is losing money, meaning the business is incurring losses on every sale before even considering fixed costs.
Q3: How often should I recalculate my weighted average contribution margin per unit?
It's best to recalculate this metric periodically, such as monthly or quarterly, especially if there are significant changes in sales volumes, pricing, or variable costs. For businesses with highly dynamic operations, real-time or weekly calculations might be more beneficial.
Q4: What are considered "variable costs" for this calculation?
Variable costs are expenses that change in direct proportion to the volume of goods or services produced or sold. Examples include raw materials, direct labor, packaging, sales commissions, shipping costs, and transaction processing fees. Fixed costs (like rent, salaries, insurance) are excluded.
Q5: How does this metric relate to break-even analysis?
The weighted average contribution margin per unit is a key component in break-even analysis for multi-product companies. It allows you to calculate a weighted average break-even point in units, simplifying the understanding of how many total units need to be sold, across the entire product mix, to cover fixed costs.
Q6: Should I focus on maximizing the weighted average CM per unit or total contribution margin?
Both are important. Maximizing WACM per unit suggests efficiency and strong pricing power on average. However, maximizing total contribution margin (Total CM = WACM * Total Units Sold) is ultimately what drives profitability. A company might have a lower WACM per unit but achieve higher total CM through significantly higher sales volumes, especially if fixed costs are high.
Q7: Does this calculator handle different currencies?
This calculator operates on numerical inputs. While it doesn't enforce currency symbols, ensure all your inputs (selling price, variable cost) are in the same currency for accurate results. The output will be in that same currency.
Q8: Can I use this for services instead of physical products?
Yes, absolutely. For services, "Selling Price per Unit" could be your hourly rate or project fee, and "Variable Cost per Unit" might include costs like contractor fees, software subscriptions directly tied to service delivery, or client-specific materials. "Units Sold" could represent billable hours, projects completed, or client accounts.
Related Tools and Internal Resources
Calculate Profit Margin – Learn how to determine the profitability of your products and services.
var productCount = 3; // Initial number of products
function initializeProductInputs() {
var productContainer = document.getElementById('productInputs');
productContainer.innerHTML = "; // Clear existing inputs
for (var i = 1; i <= productCount; i++) {
addProductRow(i);
}
updateChartData(); // Update chart with initial data
}
function addProductRow(index) {
var productContainer = document.getElementById('productInputs');
var div = document.createElement('div');
div.setAttribute('class', 'product-row');
div.setAttribute('id', 'productRow' + index);
div.innerHTML = `
Product ${index}
`;
productContainer.appendChild(div);
}
function addProductInput() {
productCount++;
addProductRow(productCount);
updateChartData(); // Update chart after adding
}
function removeProductInput() {
if (productCount > 1) {
var productContainer = document.getElementById('productInputs');
var rowToRemove = document.getElementById('productRow' + productCount);
productContainer.removeChild(rowToRemove);
productCount–;
updateChartData(); // Update chart after removing
}
}
function clearErrors() {
var errorMessages = document.querySelectorAll('.error-message');
for (var i = 0; i < errorMessages.length; i++) {
errorMessages[i].textContent = '';
}
}
function validateInputs() {
clearErrors();
var isValid = true;
var inputs = document.querySelectorAll('.product-input');
var requiredFields = ['productCount'];
// Validate productCount separately
var productCountInput = document.getElementById('productCount');
var pcValue = parseFloat(productCountInput.value);
if (isNaN(pcValue) || pcValue < 1) {
document.getElementById('productCountError').textContent = 'Number of products must be at least 1.';
isValid = false;
} else {
productCount = pcValue; // Update global productCount if valid
}
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
var value = parseFloat(input.value);
var id = input.id;
var errorElement = document.getElementById(id + 'Error');
if (input.value === '' || isNaN(value)) {
errorElement.textContent = 'This field is required.';
isValid = false;
} else if (value < 0) {
errorElement.textContent = 'Value cannot be negative.';
isValid = false;
} else {
// Specific checks for selling price vs variable cost
if (id.startsWith('sellingPrice')) {
var costInputId = id.replace('sellingPrice', 'variableCost');
var costValue = parseFloat(document.getElementById(costInputId).value);
if (!isNaN(costValue) && value < costValue) {
errorElement.textContent = 'Selling price cannot be less than variable cost.';
isValid = false;
}
}
}
}
return isValid;
}
function calculateWeightedContributionMargin() {
if (!validateInputs()) {
return;
}
var totalWeightedSellingPrice = 0;
var totalWeightedVariableCost = 0;
var totalContributionMargin = 0;
var totalUnitsSold = 0;
var productDetails = []; // For chart and results
for (var i = 1; i <= productCount; i++) {
var sp = parseFloat(document.getElementById('sellingPrice' + i).value);
var vc = parseFloat(document.getElementById('variableCost' + i).value);
var units = parseFloat(document.getElementById('unitsSold' + i).value);
var contributionMarginPerUnit = sp – vc;
var productTotalCM = contributionMarginPerUnit * units;
totalWeightedSellingPrice += sp * units;
totalWeightedVariableCost += vc * units;
totalContributionMargin += productTotalCM;
totalUnitsSold += units;
productDetails.push({
name: 'Product ' + i,
sellingPrice: sp,
variableCost: vc,
unitsSold: units,
contributionMarginPerUnit: contributionMarginPerUnit,
productTotalCM: productTotalCM
});
}
var weightedAvgSellingPrice = totalUnitsSold === 0 ? 0 : totalWeightedSellingPrice / totalUnitsSold;
var weightedAvgVariableCost = totalUnitsSold === 0 ? 0 : totalWeightedVariableCost / totalUnitsSold;
var weightedAvgContributionMargin = totalUnitsSold === 0 ? 0 : totalContributionMargin / totalUnitsSold;
// Display Results
document.getElementById('mainResult').textContent = '$' + weightedAvgContributionMargin.toFixed(2);
document.getElementById('avgSellingPrice').textContent = '$' + weightedAvgSellingPrice.toFixed(2);
document.getElementById('avgVariableCost').textContent = '$' + weightedAvgVariableCost.toFixed(2);
document.getElementById('totalContributionMargin').textContent = '$' + totalContributionMargin.toFixed(2);
// Display Key Assumptions
var assumptionsHtml = 'Key Assumptions:';
for (var j = 0; j < productDetails.length; j++) {
assumptionsHtml += `Product ${j + 1}: SP=$${productDetails[j].sellingPrice}, VC=$${productDetails[j].variableCost}, Units=${productDetails[j].unitsSold}`;
}
document.getElementById('keyAssumptions').innerHTML = assumptionsHtml;
// Update Chart
updateChart(productDetails, totalContributionMargin);
}
function resetCalculator() {
document.getElementById('productCount').value = 3;
productCount = 3;
initializeProductInputs(); // Re-initialize with default values
clearErrors();
// Optionally, reset results to default state
document.getElementById('mainResult').textContent = '–';
document.getElementById('avgSellingPrice').textContent = '–';
document.getElementById('avgVariableCost').textContent = '–';
document.getElementById('totalContributionMargin').textContent = '–';
document.getElementById('keyAssumptions').innerHTML = '';
}
function copyResults() {
var mainResult = document.getElementById('mainResult').textContent;
var avgSellingPrice = document.getElementById('avgSellingPrice').textContent;
var avgVariableCost = document.getElementById('avgVariableCost').textContent;
var totalContributionMargin = document.getElementById('totalContributionMargin').textContent;
var assumptions = document.getElementById('keyAssumptions').innerHTML.replace(//g, '\n').replace(//g, "); // Basic text conversion
var resultString = `Weighted Average Contribution Margin Per Unit: ${mainResult}\n`;
resultString += `Weighted Average Selling Price Per Unit: ${avgSellingPrice}\n`;
resultString += `Weighted Average Variable Cost Per Unit: ${avgVariableCost}\n`;
resultString += `Total Contribution Margin: ${totalContributionMargin}\n\n`;
resultString += `Key Assumptions:\n${assumptions}`;
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(resultString).then(function() {
alert('Results copied to clipboard!');
}).catch(function(err) {
console.error('Failed to copy results: ', err);
fallbackCopyTextToClipboard(resultString);
});
} else {
fallbackCopyTextToClipboard(resultString);
}
}
function fallbackCopyTextToClipboard(text) {
var textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.position = "fixed";
textArea.style.top = "0";
textArea.style.left = "0";
textArea.style.width = "2em";
textArea.style.height = "2em";
textArea.style.padding = "0";
textArea.style.border = "none";
textArea.style.outline = "none";
textArea.style.boxShadow = "none";
textArea.style.background = "transparent";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
alert('Results copied to clipboard! (' + msg + ')');
} catch (err) {
console.error('Fallback: Oops, unable to copy', err);
alert('Failed to copy results. Please copy manually.');
}
document.body.removeChild(textArea);
}
// Charting Logic using Canvas API
var myChart = null;
var chartData = {
labels: [],
datasets: [{
label: 'Product Total Contribution Margin',
data: [],
backgroundColor: [],
borderColor: [],
borderWidth: 1
}, {
label: 'Individual Contribution Margin per Unit',
data: [],
backgroundColor: [],
borderColor: [],
borderWidth: 1
}]
};
function updateChartData() {
var productContainer = document.getElementById('productInputs');
var rows = productContainer.querySelectorAll('.product-row');
chartData.labels = [];
chartData.datasets[0].data = [];
chartData.datasets[1].data = [];
chartData.datasets[0].backgroundColor = [];
chartData.datasets[0].borderColor = [];
chartData.datasets[1].backgroundColor = [];
chartData.datasets[1].borderColor = [];
var colors = ['rgba(0, 74, 153, 0.6)', 'rgba(40, 167, 69, 0.6)', 'rgba(255, 193, 7, 0.6)', 'rgba(108, 117, 125, 0.6)', 'rgba(23, 162, 184, 0.6)'];
var borderColors = ['rgba(0, 74, 153, 1)', 'rgba(40, 167, 69, 1)', 'rgba(255, 193, 7, 1)', 'rgba(108, 117, 125, 1)', 'rgba(23, 162, 184, 1)'];
for (var i = 0; i < rows.length; i++) {
var index = i + 1;
var productName = 'Product ' + index;
var units = parseFloat(document.getElementById('unitsSold' + index).value);
var sp = parseFloat(document.getElementById('sellingPrice' + index).value);
var vc = parseFloat(document.getElementById('variableCost' + index).value);
var cmPerUnit = sp – vc;
var totalCM = cmPerUnit * units;
chartData.labels.push(productName);
chartData.datasets[0].data.push(totalCM);
chartData.datasets[1].data.push(cmPerUnit);
var colorIndex = i % colors.length;
chartData.datasets[0].backgroundColor.push(colors[colorIndex]);
chartData.datasets[0].borderColor.push(borderColors[colorIndex]);
chartData.datasets[1].backgroundColor.push('rgba(255, 255, 255, 0.1)'); // Lighter for secondary series
chartData.datasets[1].borderColor.push('rgba(0, 0, 0, 0.3)');
}
if (myChart) {
myChart.update();
}
}
function updateChart(productDetails, totalContributionMargin) {
var ctx = document.getElementById('contributionMarginChart').getContext('2d');
if (myChart) {
myChart.destroy(); // Destroy previous chart instance
}
// Prepare data for chart
var labels = [];
var productTotalCMs = [];
var productCMPerUnits = [];
var backgroundColors = [];
var borderColors = [];
var colors = ['rgba(0, 74, 153, 0.7)', 'rgba(40, 167, 69, 0.7)', 'rgba(255, 193, 7, 0.7)', 'rgba(108, 117, 125, 0.7)', 'rgba(23, 162, 184, 0.7)'];
var borderColorsPalette = ['rgba(0, 74, 153, 1)', 'rgba(40, 167, 69, 1)', 'rgba(255, 193, 7, 1)', 'rgba(108, 117, 125, 1)', 'rgba(23, 162, 184, 1)'];
productDetails.forEach(function(product, index) {
labels.push(product.name);
productTotalCMs.push(product.productTotalCM);
productCMPerUnits.push(product.contributionMarginPerUnit);
var colorIndex = index % colors.length;
backgroundColors.push(colors[colorIndex]);
borderColors.push(borderColorsPalette[colorIndex]);
});
// Dynamically set chart title based on total contribution margin
var chartTitleElement = document.getElementById('chartTitle');
if (totalContributionMargin !== null && !isNaN(totalContributionMargin)) {
chartTitleElement.textContent = `Contribution Margin Breakdown (Total CM: $${totalContributionMargin.toFixed(2)})`;
} else {
chartTitleElement.textContent = 'Contribution Margin Breakdown';
}
myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Total Contribution Margin per Product',
data: productTotalCMs,
backgroundColor: backgroundColors,
borderColor: borderColors,
borderWidth: 1,
order: 2 // Render this dataset behind the line
}, {
label: 'Contribution Margin Per Unit',
data: productCMPerUnits,
type: 'line', // Line chart for per-unit values
borderColor: 'rgba(255, 10, 10, 0.8)', // Distinct color for line
backgroundColor: 'rgba(255, 10, 10, 0.2)',
borderWidth: 2,
fill: false,
yAxisID: 'y-axis-per-unit', // Use a secondary y-axis
order: 1 // Render this dataset in front
}]
},
options: {
responsive: true,
maintainAspectRatio: true, // Allow aspect ratio to adjust
scales: {
x: {
title: {
display: true,
text: 'Product'
}
},
y: {
title: {
display: true,
text: 'Total Contribution Margin ($)'
},
beginAtZero: true
},
'y-axis-per-unit': { // Configuration for the secondary y-axis
type: 'linear',
position: 'right',
title: {
display: true,
text: 'Contribution Margin Per Unit ($)'
},
beginAtZero: true,
grid: {
drawOnChartArea: false, // Don't draw grid lines for the secondary axis on the main chart area
}
}
},
plugins: {
tooltip: {
mode: 'index',
intersect: false,
callbacks: {
label: function(context) {
var label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(context.parsed.y);
}
return label;
}
}
},
legend: {
position: 'top',
}
}
}
});
}
// Load chart library if not present (for simplicity, assume it's available via CDN or in the head)
// In a real-world scenario, you'd include the Chart.js library script tag in the
// For this self-contained example, we'll assume Chart.js is loaded.
// If Chart.js is not loaded, the `new Chart(…)` call will fail.
// Example CDN:
document.addEventListener('DOMContentLoaded', function() {
// Add Chart.js library dynamically if not present
if (typeof Chart === 'undefined') {
var script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js';
script.onload = function() {
initializeProductInputs();
calculateWeightedContributionMargin(); // Calculate on load with defaults
};
script.onerror = function() {
console.error("Failed to load Chart.js library.");
document.getElementById('chartContainer').innerHTML = '
Error: Charting library could not be loaded.
';
};
document.head.appendChild(script);
} else {
initializeProductInputs();
calculateWeightedContributionMargin(); // Calculate on load with defaults
}
// Add event listeners for real-time updates
var productCountInput = document.getElementById('productCount');
productCountInput.addEventListener('input', function() {
var pcValue = parseInt(this.value);
if (!isNaN(pcValue) && pcValue >= 1) {
productCount = pcValue;
// Re-initialize inputs to match the new count
var currentProductCount = document.querySelectorAll('.product-row').length;
if (pcValue > currentProductCount) {
for (var i = currentProductCount + 1; i <= pcValue; i++) {
addProductRow(i);
}
} else if (pcValue pcValue; i–) {
removeProductInput();
}
}
updateChartData(); // Update chart data structure
} else if (pcValue === 0) {
document.getElementById('productCountError').textContent = 'Number of products must be at least 1.';
} else {
document.getElementById('productCountError').textContent = 'Invalid input.';
}
});
// Add input event listeners for all product inputs for real-time calculation
document.getElementById('productInputs').addEventListener('input', function(event) {
if (event.target.classList.contains('product-input')) {
calculateWeightedContributionMargin();
}
});
});