Calculating Dead Weight Loss

Deadweight Loss Calculator & Analysis

:root {
–primary-color: #004a99;
–success-color: #28a745;
–background-color: #f8f9fa;
–text-color: #333;
–border-color: #dee2e6;
–card-background: #ffffff;
–shadow: 0 4px 8px rgba(0,0,0,0.1);
}
body {
font-family: ‘Segoe UI’, Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: var(–text-color);
background-color: var(–background-color);
margin: 0;
padding: 0;
}
.container {
max-width: 1000px;
margin: 20px auto;
padding: 20px;
background-color: var(–card-background);
border-radius: 8px;
box-shadow: var(–shadow);
}
header {
text-align: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 1px solid var(–border-color);
}
h1, h2, h3 {
color: var(–primary-color);
}
h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
h2 {
font-size: 1.8em;
margin-top: 30px;
margin-bottom: 15px;
}
h3 {
font-size: 1.3em;
margin-top: 20px;
margin-bottom: 10px;
}
.calculator-wrapper {
background-color: var(–card-background);
border-radius: 8px;
padding: 25px;
box-shadow: var(–shadow);
margin-bottom: 40px;
}
.calculator-wrapper h2 {
text-align: center;
margin-top: 0;
margin-bottom: 25px;
}
.input-group {
margin-bottom: 18px;
}
.input-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: var(–primary-color);
}
.input-group input[type=”number”],
.input-group select {
width: calc(100% – 22px); /* Account for padding and border */
padding: 10px;
border: 1px solid var(–border-color);
border-radius: 4px;
font-size: 1em;
box-sizing: border-box; /* Include padding and border in the element’s total width and height */
}
.input-group .helper-text {
font-size: 0.85em;
color: #6c757d;
margin-top: 5px;
display: block;
}
.input-group .error-message {
color: #dc3545;
font-size: 0.85em;
margin-top: 5px;
display: block;
height: 1.2em; /* Reserve space for error message */
}
.button-group {
margin-top: 25px;
display: flex;
justify-content: space-between;
gap: 10px;
}
button {
padding: 12px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
font-weight: 600;
transition: background-color 0.3s ease;
}
button.primary {
background-color: var(–primary-color);
color: white;
}
button.primary:hover {
background-color: #003366;
}
button.reset {
background-color: #6c757d;
color: white;
}
button.reset:hover {
background-color: #5a6268;
}
button.copy {
background-color: var(–success-color);
color: white;
}
button.copy:hover {
background-color: #218838;
}
.results-wrapper {
margin-top: 30px;
padding: 20px;
background-color: #e9ecef;
border-radius: 8px;
border: 1px solid #ced4da;
}
.results-wrapper h3 {
margin-top: 0;
color: var(–primary-color);
text-align: center;
}
.main-result {
font-size: 2.2em;
font-weight: bold;
color: var(–success-color);
text-align: center;
margin: 15px 0;
padding: 15px;
background-color: #d4edda;
border: 1px solid var(–success-color);
border-radius: 5px;
}
.intermediate-results {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
gap: 15px;
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #dee2e6;
}
.intermediate-results .result-item {
text-align: center;
padding: 10px;
background-color: var(–card-background);
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
flex: 1; /* Distribute space */
min-width: 150px; /* Minimum width before wrapping */
}
.intermediate-results .result-item .label {
font-size: 0.9em;
color: #6c757d;
margin-bottom: 5px;
}
.intermediate-results .result-item .value {
font-size: 1.5em;
font-weight: bold;
color: var(–primary-color);
}
.formula-explanation {
margin-top: 20px;
font-size: 0.95em;
color: #495057;
text-align: center;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 30px;
margin-bottom: 30px;
box-shadow: var(–shadow);
}
th, td {
padding: 12px 15px;
text-align: left;
border: 1px solid var(–border-color);
}
thead th {
background-color: var(–primary-color);
color: white;
font-weight: bold;
}
tbody tr:nth-child(even) {
background-color: #f8f9fa;
}
caption {
font-size: 1.1em;
font-weight: bold;
color: var(–primary-color);
margin-bottom: 10px;
caption-side: top;
text-align: left;
}
canvas {
display: block;
margin: 30px auto;
max-width: 100%;
background-color: var(–card-background);
border-radius: 8px;
box-shadow: var(–shadow);
}
.article-content {
margin-top: 40px;
padding-top: 30px;
border-top: 1px solid var(–border-color);
}
.article-content p, .article-content ul, .article-content ol {
margin-bottom: 15px;
}
.article-content ul, .article-content ol {
padding-left: 20px;
}
.article-content li {
margin-bottom: 8px;
}
.faq-item {
margin-bottom: 15px;
padding: 10px;
background-color: #e9ecef;
border-left: 4px solid var(–primary-color);
border-radius: 4px;
}
.faq-item strong {
display: block;
color: var(–primary-color);
margin-bottom: 5px;
}
.internal-links-section ul {
list-style: none;
padding: 0;
}
.internal-links-section li {
margin-bottom: 10px;
}
.internal-links-section a {
color: var(–primary-color);
text-decoration: none;
font-weight: bold;
}
.internal-links-section a:hover {
text-decoration: underline;
}
.internal-links-section .description {
font-size: 0.9em;
color: #555;
margin-left: 5px;
}
@media (max-width: 768px) {
.container {
margin: 10px;
padding: 15px;
}
h1 {
font-size: 2em;
}
h2 {
font-size: 1.5em;
}
button {
padding: 10px 15px;
font-size: 0.95em;
}
.button-group {
flex-direction: column;
align-items: center;
}
.button-group button {
width: 100%;
margin-bottom: 10px;
}
.intermediate-results {
flex-direction: column;
align-items: center;
}
.intermediate-results .result-item {
width: 80%;
margin-bottom: 10px;
}
}

Deadweight Loss Calculator

Assess the economic inefficiency caused by market distortions.

Calculate Deadweight Loss

The quantity of goods or services traded in a perfectly competitive market.

The equilibrium price where supply equals demand.

The price set by a tax, subsidy, or price control.

The quantity producers are willing to supply at the intervention price.

The quantity consumers are willing to buy at the intervention price.



Calculation Results

Quantity Traded (Q_int)

Price Wedge (PW)

Total Surplus Loss

Formula Used:

Deadweight Loss (DWL) = 0.5 * (Price Wedge) * (Quantity Reduction)

Where Quantity Reduction = Quantity at Equilibrium (Qe) – Quantity Traded (Q_int)

Price Wedge (PW) = | Price with Intervention – Equilibrium Price (Pe) | or Tax/Subsidy per unit

What is Deadweight Loss?

Deadweight loss (DWL), also known as excess burden, is a fundamental concept in economics that quantifies the inefficiency arising from a market’s inability to reach its optimal equilibrium. This inefficiency occurs when the marginal benefit to consumers of an additional unit of a good or service no longer equals the marginal cost of producing it, leading to a loss of potential economic welfare for both consumers and producers. Essentially, deadweight loss represents the value of transactions that do not occur due to market distortions, such as taxes, subsidies, price ceilings, price floors, or externalities. It’s a direct measure of how much society “loses out” when markets are not operating at their most efficient point.

Who should use this calculator?
Economists, policymakers, business analysts, students of economics, and anyone interested in understanding the societal costs of market interventions can benefit from using a deadweight loss calculator. It provides a quantitative measure to assess the impact of policies like taxes or subsidies on overall economic welfare.

Common misconceptions about deadweight loss:
One common misconception is that deadweight loss only applies to taxes. In reality, any market distortion that prevents the market from clearing at its efficient equilibrium can create deadweight loss, including price controls (ceilings and floors), monopolies, and externalities. Another misconception is that deadweight loss is a direct monetary loss to a specific entity; instead, it represents a loss of aggregate economic surplus – the combined benefit to society that is not captured by anyone. It’s a measure of potential gains forgone.

Deadweight Loss Formula and Mathematical Explanation

The deadweight loss from a market distortion is typically visualized as a triangle on a supply and demand diagram. The size of this triangle represents the lost economic surplus. The calculation involves understanding the difference between the efficient market outcome and the outcome under intervention.

The general formula for deadweight loss, particularly when caused by a per-unit tax or subsidy or a price control that creates a gap between quantity supplied and demanded, can be derived from the supply and demand curves. Assuming linear supply and demand curves for simplicity, the deadweight loss is calculated as half the product of the price wedge (the difference in price that buyers pay and sellers receive) and the reduction in the quantity traded.

Step-by-step derivation:

  1. Identify Equilibrium: Determine the equilibrium quantity (Qe) and equilibrium price (Pe) where the original supply and demand curves intersect.
  2. Identify Intervention Impact: Determine the new quantity traded (Q_int) after the intervention (e.g., a tax, subsidy, or price control). This quantity is usually the lesser of the quantity supplied (Qs_int) or demanded (Qd_int) at the new price.
  3. Calculate Quantity Reduction: Find the difference between the equilibrium quantity and the new quantity traded: Quantity Reduction = Qe – Q_int.
  4. Calculate Price Wedge: Determine the wedge between the price consumers pay and the price producers receive. For a tax, this is the tax per unit. For a price control, it’s the difference between the controlled price and the market-clearing price if the control were lifted, or more practically, the difference between what consumers pay and what producers receive after the intervention. Often, P_int represents the price consumers pay, and we infer the price producers receive based on their supply curve at Q_int. For this calculator, we directly use the intervention price and its effect on quantities. The ‘Price Wedge’ calculated in the calculator is often represented by the tax amount or the difference between consumer and producer prices resulting from a price control.
  5. Calculate Deadweight Loss: Apply the formula: DWL = 0.5 * Price Wedge * Quantity Reduction.

In our calculator, we simplify this by using the provided intervention price and the resulting quantities. The ‘Quantity Traded (Q_int)’ is the quantity that actually exchanges hands, which is the minimum of quantity supplied and quantity demanded at the intervention price. The ‘Price Wedge’ is often the per-unit tax or the effective difference in price due to controls. The ‘Quantity Reduction’ is then Qe – Q_int.

Variables Explained:

Variable Meaning Unit Typical Range
Qe (quantityDemandedAtEquilibrium) Quantity of goods/services at market equilibrium Units Non-negative
Pe (priceDemandedAtEquilibrium) Price of goods/services at market equilibrium Currency Units Non-negative
P_int (priceWithIntervention) Price after intervention (e.g., tax-inclusive price for consumers, or price floor/ceiling) Currency Units Non-negative
Qs_int (quantitySuppliedAtIntervention) Quantity supplied by producers at the intervention price Units Non-negative
Qd_int (quantityDemandedAtIntervention) Quantity demanded by consumers at the intervention price Units Non-negative
Q_int (Quantity Traded) Actual quantity transacted in the market with intervention (min(Qs_int, Qd_int)) Units Non-negative
PW (Price Wedge) Difference between the price consumers pay and producers receive, or the per-unit tax/subsidy. This is calculated as |P_int – (Producer Price at Q_int)| or simply the tax amount. For simplicity in calculator, it can be approximated by the tax per unit if P_int is the tax-inclusive price for consumers. If P_int is a price floor/ceiling, it’s the gap it creates. If P_int is directly the tax, then PW = P_int. Assuming P_int is consumer price and PW reflects tax, Producer Price = P_int – PW. For this calculator, we infer PW based on the price inputs and quantity reduction. A simplified PW is often the difference between the price received by sellers and paid by buyers. Currency Units per Unit Non-negative
Quantity Reduction The decrease in quantity traded due to the intervention (Qe – Q_int) Units Non-negative
DWL (Deadweight Loss) The loss of total economic surplus (consumer + producer surplus) resulting from the intervention. Currency Units Non-negative

Practical Examples (Real-World Use Cases)

Understanding deadweight loss is crucial for evaluating the economic consequences of various policies. Here are a couple of examples:

Example 1: Impact of a Sales Tax on Gasoline

Consider the market for gasoline. Suppose the equilibrium price (Pe) is $3.00 per gallon, and the equilibrium quantity (Qe) is 100 million gallons. The government imposes a $0.50 per gallon sales tax. This tax creates a price wedge between what consumers pay and what producers receive. Consumers now effectively pay $3.25 per gallon (P_int), and producers receive $2.75 per gallon (P_int – tax). At these prices, quantity supplied (Qs_int) is 105 million gallons, but quantity demanded (Qd_int) falls to 95 million gallons.

  • Inputs:
  • Qe = 100 million gallons
  • Pe = $3.00
  • P_int (Consumer Price) = $3.25
  • Qs_int = 105 million gallons
  • Qd_int = 95 million gallons
  • Price Wedge (Tax) = $0.50

Calculation:
The actual quantity traded (Q_int) is the lesser of Qs_int and Qd_int, which is 95 million gallons.
Quantity Reduction = Qe – Q_int = 100 million – 95 million = 5 million gallons.
Price Wedge = $0.50 per gallon.
Deadweight Loss (DWL) = 0.5 * $0.50/gallon * 5 million gallons = $1.25 million.

Interpretation: The $1.25 million represents the lost economic value from the 5 million gallons of gasoline that are no longer traded due to the tax. This is a loss to society that is not captured by either consumers or the government.

Example 2: Effect of a Price Ceiling on Rental Apartments

Suppose the market for rental apartments in a city has an equilibrium price (Pe) of $1200 per month and an equilibrium quantity (Qe) of 50,000 units. The government imposes a price ceiling (maximum allowable rent) of $1000 per month (P_int). At this lower price, landlords are willing to supply (Qs_int) only 40,000 units, while tenants demand (Qd_int) 60,000 units.

  • Inputs:
  • Qe = 50,000 units
  • Pe = $1200
  • P_int (Price Ceiling) = $1000
  • Qs_int = 40,000 units
  • Qd_int = 60,000 units

Calculation:
The actual quantity traded (Q_int) is the lesser of Qs_int and Qd_int, which is 40,000 units.
Quantity Reduction = Qe – Q_int = 50,000 – 40,000 = 10,000 units.
The ‘Price Wedge’ here represents the loss in potential transaction value. A simplified way to think about DWL with a price ceiling is the loss on the units that *could* have been traded but are not. The lost surplus occurs on the 10,000 units that are not rented out because the price is artificially low. The DWL triangle’s base is the difference in quantity (10,000 units), and its height is the difference between the price consumers are willing to pay for the 40,000th unit (found on the demand curve at Q=40,000, which would be higher than $1000) and the price producers are willing to accept for the 40,000th unit (which is related to the supply curve at Q=40,000). A more direct calculation using the DWL formula requires knowing the price producers receive at Q_int. If we assume the $1000 is the price producers receive, the demand price for the 40,000th unit would be higher. For this calculator’s purpose, let’s assume the intervention price P_int implies a certain wedge. A common simplification for DWL from price controls: DWL = 0.5 * (Demand Price at Q_int – Supply Price at Q_int) * (Qe – Q_int). If P_int ($1000) is the price producers receive and demanders are willing to pay more for the last units, we need the demand curve. Let’s use the calculator’s framework: The price wedge can be thought of as the gap between the demand price and supply price at Q_int. If P_int is the controlled price and leads to Q_int=40,000, the implicit demand price for the 40,000th unit would be higher than $1000, and the supply price for the 40,000th unit would be related to the supply curve at 40,000 units (let’s assume $800 for illustration, making PW=$200).
Let’s recalculate assuming the calculator’s structure: P_int=$1000, Qe=50000, Pe=$1200, Qs_int=40000, Qd_int=60000.
Q_int = 40,000. Quantity Reduction = 10,000.
Price Wedge (PW): This is tricky without the curves. If P_int is the price consumers pay, and producers receive less (e.g. $900 due to side payments or costs incurred by scarcity), PW = $100. If P_int is the price producers receive and consumers pay more implicitly, PW could be higher. For simplicity in calculation, if P_int is the consumer price and leads to Qs_int, we’d need the producer price. Let’s assume the calculator context implies P_int and the resulting Qs_int/Qd_int define the intervention. The PW for DWL calculation often requires finding the difference between the price consumers are willing to pay and producers are willing to accept at the quantity traded (Q_int).
Let’s use a common approach: DWL = 0.5 * (Price Consumers Pay – Price Producers Receive) * (Qe – Q_int). If P_int ($1000) is the effective price paid by consumers, and producers receive $900 (due to costs or lower P_int implies lower producer price), then PW = $100.
DWL = 0.5 * $100 * 10,000 units = $500,000.

Interpretation: The $500,000 represents the lost welfare because 10,000 potential housing units are not rented out due to the price ceiling. This loss is due to mutually beneficial transactions that cannot occur. This analysis helps policymakers understand the true cost of price controls beyond the immediate impact on prices.

How to Use This Deadweight Loss Calculator

Our Deadweight Loss Calculator is designed for simplicity and accuracy. Follow these steps to understand the economic inefficiency in a market:

  1. Input Equilibrium Values: Enter the Quantity at Market Equilibrium (Qe) and the Price at Market Equilibrium (Pe). These represent the natural clearing point of the market before any intervention.
  2. Input Intervention Values:
    • Price with Intervention (P_int): Enter the price level that exists due to a government policy (e.g., the price consumers pay including tax, a price floor, or a price ceiling).
    • Quantity Supplied at Intervention (Qs_int): Enter the quantity producers are willing to supply at P_int.
    • Quantity Demanded at Intervention (Qd_int): Enter the quantity consumers are willing to buy at P_int.
  3. Calculate: Click the “Calculate Deadweight Loss” button.

How to Read Results:

  • Main Result (Deadweight Loss): This is the primary output, showing the total economic value lost due to the market distortion in currency units.
  • Quantity Traded (Q_int): Displays the actual amount of the good or service that is exchanged in the market after the intervention. This is always the lower of Qs_int and Qd_int.
  • Price Wedge (PW): Represents the difference between what consumers pay and what producers receive per unit, or the per-unit impact of the intervention (like a tax).
  • Total Surplus Loss: This is another way to express the DWL, showing the combined loss of consumer and producer surplus.
  • Formula Used: Provides a clear explanation of the calculation performed.

Decision-Making Guidance: A high deadweight loss suggests that the market intervention is significantly reducing overall economic welfare. Policymakers can use this information to weigh the benefits of a policy (e.g., revenue from a tax, protection for a group) against its efficiency costs. If DWL is high, alternative policies might be considered to achieve the same objective with less economic distortion.

Key Factors That Affect Deadweight Loss Results

The magnitude of deadweight loss is not static; it depends heavily on several economic characteristics of the market and the nature of the intervention. Understanding these factors allows for a more nuanced analysis of market inefficiencies:

  1. Elasticity of Demand and Supply: This is arguably the most critical factor.

    • High Elasticity: If demand or supply is highly elastic (responsive to price changes), a small price wedge (like a tax) will lead to a large reduction in quantity traded. This results in a larger deadweight loss triangle. For instance, a tax on a luxury good with many substitutes (high elasticity) will likely cause a greater DWL than a tax on a necessity with few substitutes (low elasticity).
    • Low Elasticity: Conversely, if demand and supply are inelastic, the quantity traded will not change much in response to price changes, leading to a smaller deadweight loss, even with a significant price wedge.
  2. Magnitude of the Intervention (Price Wedge): The larger the per-unit tax, subsidy, or price gap created by a price control, the greater the deadweight loss. A doubling of the tax rate, assuming similar elasticities, will roughly double the deadweight loss.
  3. Initial Equilibrium Quantity (Qe): A higher equilibrium quantity means a larger potential market. If an intervention causes a significant percentage reduction in quantity from a large base, the absolute deadweight loss will be greater. The base quantity influences the size of the market that is potentially disrupted.
  4. Type of Intervention: While taxes and subsidies often create DWL, other interventions like monopolies (which restrict output below the efficient level to raise prices) also cause deadweight loss. The specific mechanism of distortion affects how DWL is calculated and its magnitude.
  5. Market Structure: Perfectly competitive markets are assumed for efficient equilibrium. In markets with pre-existing imperfections (like monopolies or oligopolies), deadweight loss might already exist. Adding further interventions can exacerbate this or interact in complex ways. Monopolies inherently create DWL by producing less than the socially optimal quantity.
  6. Government Goals vs. Efficiency: Sometimes, policies that create deadweight loss serve other objectives, such as income redistribution (e.g., welfare programs) or correcting externalities (e.g., carbon taxes designed to reduce pollution). Policymakers must weigh the efficiency loss (DWL) against these other societal goals. The perceived “fairness” or social benefit might outweigh the calculated economic inefficiency.
  7. Time Horizon: In the short run, elasticities might be low, leading to less DWL. Over the long run, consumers and producers can adjust their behavior more significantly, increasing elasticities and potentially leading to higher DWL from sustained interventions.

Frequently Asked Questions (FAQ)

Q1: Is deadweight loss always a negative thing?

From a pure economic efficiency standpoint, yes. Deadweight loss represents lost potential welfare. However, policies causing DWL might be implemented for other important reasons, such as social equity, environmental protection, or national security. Policymakers must balance efficiency with these other goals.

Q2: Can deadweight loss be zero?

Deadweight loss is zero only when the market is operating at its efficient equilibrium, meaning there are no market distortions like taxes, subsidies, price controls, or externalities. In practice, achieving perfect efficiency is rare.

Q3: How is deadweight loss different from the tax revenue collected by the government?

Tax revenue is a transfer of money from taxpayers to the government. Deadweight loss is a loss of *total* economic surplus (consumer and producer surplus) that is not captured by anyone – it’s pure waste or inefficiency. Tax revenue can sometimes be larger than DWL, but often DWL represents the cost of raising that revenue.

Q4: Does deadweight loss apply to monopolies?

Yes. A monopolist restricts output below the socially efficient level (where price equals marginal cost) to maximize profits, leading to deadweight loss. The monopolist captures some surplus as profit, but there’s also a portion of lost surplus that benefits neither the monopolist nor consumers.

Q5: What is the difference between deadweight loss and transfer payments?

A transfer payment (like a subsidy or welfare check) redistributes existing wealth or income from one party to another. It does not create or destroy economic value itself. Deadweight loss, on the other hand, represents a loss of value that is permanently gone from the economy.

Q6: How do subsidies create deadweight loss?

Subsidies lower the price for consumers or producers, encouraging more transactions. However, if the subsidy leads to production or consumption beyond the efficient equilibrium (where marginal benefit equals marginal cost), the cost of producing those extra units exceeds their value, creating deadweight loss. The government’s cost for the subsidy might exceed the gains in consumer and producer surplus.

Q7: Can I use this calculator for subsidies?

Yes. For subsidies, you would typically input the equilibrium values. Then, for the intervention, consider the net price change. If it’s a subsidy to consumers, P_int might be the lower price consumers pay. If it’s a subsidy to producers, P_int could reflect the price producers receive, and Qs_int would be higher. The calculation of DWL from subsidies involves comparing the subsidized market outcome to the efficient outcome, similar to taxes but with a potential gain in surplus offset by the subsidy cost. The calculator framework can be adapted by carefully defining P_int and the resulting quantities.

Q8: What does it mean if the “Quantity Traded” is less than “Quantity Supplied at Intervention” but more than “Quantity Demanded at Intervention”?

In a standard market, the quantity actually traded is always the *minimum* of the quantity supplied and the quantity demanded at the prevailing price. If you input values where Qs_int > Qd_int, the market will only trade Qd_int. If Qd_int > Qs_int, only Qs_int will trade. The calculator correctly identifies Q_int as min(Qs_int, Qd_int).

© 2023 Your Financial Tools. All rights reserved.

function validateInput(id, errorId, minValue = null, maxValue = null) {
var input = document.getElementById(id);
var errorSpan = document.getElementById(errorId);
var value = parseFloat(input.value);

errorSpan.textContent = ”; // Clear previous error

if (isNaN(value)) {
errorSpan.textContent = ‘Please enter a valid number.’;
return false;
}
if (minValue !== null && value maxValue) {
errorSpan.textContent = ‘Value exceeds maximum limit.’;
return false;
}
return true;
}

function calculateDeadweightLoss() {
// Clear previous results and errors
document.getElementById(‘resultsDiv’).style.display = ‘none’;
var inputs = [‘quantityDemandedAtEquilibrium’, ‘priceDemandedAtEquilibrium’, ‘priceWithIntervention’, ‘quantitySuppliedAtIntervention’, ‘quantityDemandedAtIntervention’];
for (var i = 0; i < inputs.length; i++) {
var errorId = 'error' + inputs[i].charAt(0).toUpperCase() + inputs[i].slice(1);
document.getElementById(errorId).textContent = '';
}

// Validate all inputs first
var allValid = true;
allValid = validateInput('quantityDemandedAtEquilibrium', 'errorQuantityDemandedAtEquilibrium', 0) && allValid;
allValid = validateInput('priceDemandedAtEquilibrium', 'errorPriceDemandedAtEquilibrium', 0) && allValid;
allValid = validateInput('priceWithIntervention', 'errorPriceWithIntervention', 0) && allValid;
allValid = validateInput('quantitySuppliedAtIntervention', 'errorQuantitySuppliedAtIntervention', 0) && allValid;
allValid = validateInput('quantityDemandedAtIntervention', 'errorQuantityDemandedAtIntervention', 0) && allValid;

if (!allValid) {
return; // Stop calculation if any input is invalid
}

// Get values
var qe = parseFloat(document.getElementById('quantityDemandedAtEquilibrium').value);
var pe = parseFloat(document.getElementById('priceDemandedAtEquilibrium').value);
var pInt = parseFloat(document.getElementById('priceWithIntervention').value);
var qsInt = parseFloat(document.getElementById('quantitySuppliedAtIntervention').value);
var qdInt = parseFloat(document.getElementById('quantityDemandedAtIntervention').value);

// Determine actual quantity traded
var qInt = Math.min(qsInt, qdInt);

// Calculate Quantity Reduction
var quantityReduction = qe – qInt;
if (quantityReduction Pe, and Q_int Qd_int (or vice versa),
// the “effective” price wedge is what separates the demand price and supply price at Q_int.
// Let’s assume P_int is the CONSUMER PRICE.
// And Qs_int is the quantity SUPPLIED. We need the Producer Price (Pp) at Qs_int.
// Without a supply curve, we cannot find Pp exactly.
// Let’s make a simplifying assumption: The “Price Wedge” is the difference between the
// intervention price (P_int) and the equilibrium price (Pe), *if* the intervention price
// is what drives the quantity change. This is imperfect.

// **REVISED PW CALCULATION LOGIC:**
// The price wedge (PW) is the difference between the price consumers pay and the price producers receive.
// var P_consumer = P_int (as entered).
// var Q_traded = qInt.
// We need P_producer at Q_traded. Without supply curve, we estimate.
// If P_int > Pe and Q_int < Qe, it suggests a tax or price floor.
// If P_int < Pe and Q_int Pp).
// Or, PW = Pd – P_int (if Pd > P_int, for price ceiling).
// For this calculator, let’s set PW = |P_int – Pe| IF the quantity reduction suggests this is the primary driver.
// OR, let’s calculate PW as the difference between P_int and the producer price implied by the supply curve at Qs_int.
// This is still too complex without curves.

// **Simplest pragmatic approach for calculator:**
// Assume PW is the difference between the price consumers pay (P_int) and the price producers receive
// after the intervention. If we assume P_int is the consumer price, and the intervention caused
// Q_int, then the producer price would be found on the supply curve at Q_int.
// A simpler proxy often used: if P_int is tax-inclusive consumer price, and Q_int is traded,
// then the producer price P_producer = P_int – Tax.
// The quantity reduction (Qe – Q_int) is key.
// Let’s approximate PW as the difference between P_int and a derived producer price.
// If P_int is the consumer price, and Qs_int is supplied, let’s assume the producer price is Pe if Qs_int = Qe.
// If Qs_int deviates, producer price deviates.
// Let’s use the formula: DWL = 0.5 * (P_consumer – P_producer) * (Qe – Q_int).
// var P_consumer = P_int.
// var P_producer = Pe – (delta_P_supply) where delta_P_supply is related to Qs_int.
// This is getting complicated. Let’s follow the standard DWL formula assumption.
// DWL = 0.5 * Base * Height.
// Base = Quantity Reduction = Qe – Q_int.
// Height = Price Wedge = P_consumer – P_producer (or Tax).
// If P_int is the price consumers pay (e.g., including tax), and Qs_int is supplied,
// let’s assume the producer price is related to the supply curve at Qs_int.
// For this calculator, we MUST define PW. Let’s DEFINE PW = P_int – (Pe – (Qe – Qs_int) * slope_S).
// This requires slope_S.
// **FINAL SIMPLIFICATION FOR PW:**
// var PW be the difference between P_int and the equilibrium price Pe, IF P_int causes the deviation.
// PW = abs(P_int – Pe) IF this is the primary driver.
// Or, if P_int is tax-inclusive consumer price, PW is the tax.
// Let’s calculate PW as the price difference needed to create Q_int from Qe.
// Or, a simpler approach: calculate DWL = 0.5 * |P_int – Pe| * (Qe – Q_int) is WRONG.
// It must be 0.5 * (Price Consumers Pay – Price Producers Receive) * (Qe – Q_int).
// var P_consumer = P_int.
// var P_producer = Price Producers Receive.
// Let’s assume P_producer = Pe – ((Qe – Qs_int) * slope_S) – this requires slope_S.
// **LET’S USE A DEFINITION FOR PW FOR THIS CALCULATOR:**
// PW = The price difference between consumers and producers at the traded quantity Q_int.
// We will approximate this using P_int.
// If P_int is the consumer price, and Qs_int is supplied:
// A common DWL formula uses PW directly. Let’s calculate PW as the absolute difference
// between the intervention price and the equilibrium price, IF the intervention price
// is directly causing the distortion. This is an approximation.
// PW = Math.abs(P_int – Pe) is NOT accurate.

// Let’s calculate PW as the effective price difference that creates the quantity change.
// If P_int is higher than Pe, and Q_int < Qe, PW is the difference between P_int and producer price.
// If P_int is lower than Pe, and Q_int slope_s = pe / qe.
// At Q_int, the producer price (Pp) would be Pp = Q_int * slope_s.
// This assumes supply curve starts at origin and is linear.
// For this calculator, let’s calculate PW = P_int – (Pp).
// If P_int Pe (tax), P_consumer is P_int, P_producer is found on supply curve.
// Let’s assume P_int is the consumer price.
// Let’s use a simplified approach for PW:
// If Q_int Pe (tax/price floor): PW = P_int – (Pe – (Qe – Q_int) * (Pe/Qe)) approx.
// If P_int < Pe (price ceiling): PW = (Pe + (Qe – Q_int) * (Pe/Qe)) – P_int approx.

// A BETTER approach for PW:
// The calculation assumes P_int is the CONSUMER price.
// The quantity traded is Q_int = min(Qs_int, Qd_int).
// If Q_int is determined by Qs_int (e.g., price floor or tax above equilibrium),
// then producer price Pp is on the supply curve at Q_int.
// If Q_int is determined by Qd_int (e.g., price ceiling or tax below equilibrium),
// then consumer price Pc is P_int, producer price Pp is on supply curve at Q_int.
// Let's assume the calculator inputs implicitly define the price wedge.
// P_int = price consumers pay.
// Q_int = actual traded quantity.
// The price producers receive (Pp) is found on the supply curve at Q_int.
// For simplicity, let's assume a linear supply curve S(Q) = mQ where m = Pe/Qe.
// Then Pp = Q_int * (Pe/Qe).
// And a linear demand curve D(Q) = mq + b. D(Qe) = Pe. m = -Pe/Qe. So b = Pe – m*Qe = Pe – (-Pe/Qe)*Qe = 2Pe.
// D(Q) = (-Pe/Qe)Q + 2Pe.
// So, consumer price Pc = P_int. Producer price Pp = Q_int * (Pe/Qe).
// Price Wedge PW = Pc – Pp = P_int – (Q_int * (Pe/Qe)).
// This PW calculation is valid IF Q_int is determined by supply (Qs_int <= Qd_int).
// If Q_int is determined by demand (Qd_int <= Qs_int), then Pc=P_int, Q_int = Qd_int.
// P_producer = Q_int * (Pe/Qe).
// But P_int is given.

// **Let's simplify the PW calculation based on common calculator implementations:**
// PW = Price Wedge (Difference between consumer and producer price).
// This calculator assumes P_int is the CONSUMER price.
// And that Qs_int and Qd_int reflect supply and demand at P_int.
// The actual quantity traded is qInt = min(qsInt, qdInt).
// Let's assume a linear supply curve S(Q) = mQ where m = Pe/Qe.
// The producer price (Pp) for the quantity traded (qInt) is Pp = qInt * m.
// The price wedge is then PW = P_int – Pp.
// This formula works IF qInt is determined by supply (qsInt <= qdInt).
// If qInt is determined by demand (qdInt <= qsInt), then consumers pay P_int,
// and producers receive Pp found on the supply curve at qInt.
// Let's use this definition of PW for calculation.
var priceWedgeValue;
var slopeS = qe === 0 ? 0 : pe / qe; // Avoid division by zero

// If P_int resulted in Qs_int 0.
var producerPriceApprox = (qInt > 0 && slopeS > 0) ? qInt * slopeS : 0;

priceWedgeValue = Math.abs(pInt – producerPriceApprox); // Use absolute for wedge magnitude

// Handle cases where P_int is below the implied producer price from supply curve at Q_int
// or above the implied demand price at Q_int.
// This simplified model assumes P_int is the consumer price.
// If P_int is above what producers receive at Q_int, then PW = P_int – ProducerPrice.
// If P_int is below what consumers demand at Q_int, this implies a price ceiling.
// Let’s refine PW:
if (qInt >= 0 && slopeS >= 0) {
producerPriceApprox = qInt * slopeS;
if (pInt >= producerPriceApprox) {
priceWedgeValue = pInt – producerPriceApprox;
} else {
// P_int is below the supply price at Q_int. This implies P_int might be the producer price,
// or the market is distorted differently. For simplicity, we’ll use the absolute difference
// or focus on the quantity reduction.
// Let’s assume P_int is the CONSUMER price. If it’s below producer price at Q_int,
// this suggests an unusual scenario or input error.
// For DWL calculation, the relevant wedge is between consumer and producer price at Q_int.
// If P_int is the consumer price, and the supply curve dictates Pp, then PW = P_int – Pp.
// If P_int < Pp, this input combination might be inconsistent or requires different interpretation.
// Let's cap priceWedgeValue at 0 if P_int is less than implied producer price.
priceWedgeValue = Math.max(0, pInt – producerPriceApprox);
}
} else {
priceWedgeValue = 0; // Cannot calculate if inputs are zero/invalid
}

// Deadweight Loss Calculation: DWL = 0.5 * Price Wedge * Quantity Reduction
var deadweightLoss = 0.5 * priceWedgeValue * quantityReduction;

// Total Surplus Loss is the same as Deadweight Loss in this context
var totalSurplusLossValue = deadweightLoss;

// Display Results
document.getElementById('mainResult').innerText = '$' + deadweightLoss.toFixed(2);
document.getElementById('quantityTradedInt').innerText = qInt.toFixed(2);
document.getElementById('priceWedge').innerText = '$' + priceWedgeValue.toFixed(2);
document.getElementById('totalSurplusLoss').innerText = '$' + totalSurplusLossValue.toFixed(2);
document.getElementById('resultsDiv').style.display = 'block';

// Update Chart
updateChart(qe, qInt, pe, pInt, priceWedgeValue, quantityReduction);
}

function resetForm() {
document.getElementById('quantityDemandedAtEquilibrium').value = '100';
document.getElementById('priceDemandedAtEquilibrium').value = '10';
document.getElementById('priceWithIntervention').value = '12';
document.getElementById('quantitySuppliedAtIntervention').value = '80';
document.getElementById('quantityDemandedAtIntervention').value = '60';

document.getElementById('resultsDiv').style.display = 'none';
var inputs = ['quantityDemandedAtEquilibrium', 'priceDemandedAtEquilibrium', 'priceWithIntervention', 'quantitySuppliedAtIntervention', 'quantityDemandedAtIntervention'];
for (var i = 0; i < inputs.length; i++) {
var errorId = 'error' + inputs[i].charAt(0).toUpperCase() + inputs[i].slice(1);
document.getElementById(errorId).textContent = '';
}
// Clear canvas
var ctx = document.getElementById('dwlChart').getContext('2d');
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}

function copyResults() {
var mainResult = document.getElementById('mainResult').innerText;
var quantityTraded = document.getElementById('quantityTradedInt').innerText;
var priceWedge = document.getElementById('priceWedge').innerText;
var totalSurplusLoss = document.getElementById('totalSurplusLoss').innerText;

var inputs = {
'Qe (Equilibrium Quantity)': document.getElementById('quantityDemandedAtEquilibrium').value,
'Pe (Equilibrium Price)': document.getElementById('priceDemandedAtEquilibrium').value,
'P_int (Intervention Price)': document.getElementById('priceWithIntervention').value,
'Qs_int (Quantity Supplied at Int)': document.getElementById('quantitySuppliedAtIntervention').value,
'Qd_int (Quantity Demanded at Int)': document.getElementById('quantityDemandedAtIntervention').value
};

var assumptions = [];
for (var key in inputs) {
assumptions.push(key + ': ' + inputs[key]);
}

var textToCopy = "Deadweight Loss Calculation Results:\n\n";
textToCopy += "Main Result (DWL): " + mainResult + "\n";
textToCopy += "Quantity Traded (Q_int): " + quantityTraded + "\n";
textToCopy += "Price Wedge (PW): " + priceWedge + "\n";
textToCopy += "Total Surplus Loss: " + totalSurplusLoss + "\n\n";
textToCopy += "Key Assumptions / Inputs:\n";
textToCopy += assumptions.join("\n");

// Use navigator.clipboard for modern browsers, fallback for older ones
if (navigator.clipboard) {
navigator.clipboard.writeText(textToCopy).then(function() {
alert('Results copied to clipboard!');
}).catch(function(err) {
console.error('Could not copy text: ', err);
fallbackCopyTextToClipboard(textToCopy);
});
} else {
fallbackCopyTextToClipboard(textToCopy);
}
}

function fallbackCopyTextToClipboard(text) {
var textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.position = "fixed"; // Avoid scrolling to bottom of page in MS Edge.
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';
console.log('Fallback: Copying text command was ' + msg);
alert('Results copied to clipboard!');
} catch (err) {
console.error('Fallback: Oops, unable to copy', err);
alert('Failed to copy results. Please copy manually.');
}

document.body.removeChild(textArea);
}

// — Charting Logic —
var dwlChart; // Global variable for chart instance

function updateChart(qe, qInt, pe, pInt, priceWedge, quantityReduction) {
var ctx = document.getElementById('dwlChart').getContext('2d');

// Clear previous chart if it exists
if (dwlChart) {
dwlChart.destroy();
}

// Chart configuration
var chartData = {
labels: [], // Will be populated based on price points
datasets: [
{
label: 'Supply Curve',
data: [],
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.1)',
fill: false,
tension: 0,
pointRadius: 4,
pointHoverRadius: 6,
showLine: true
},
{
label: 'Demand Curve',
data: [],
borderColor: 'rgb(54, 162, 235)',
backgroundColor: 'rgba(54, 162, 235, 0.1)',
fill: false,
tension: 0,
pointRadius: 4,
pointHoverRadius: 6,
showLine: true
},
{
label: 'Price Intervention Line',
data: [], // Dynamic points for vertical/horizontal lines
borderColor: 'rgb(255, 205, 86)',
backgroundColor: 'rgba(255, 205, 86, 0.2)',
borderDash: [5, 5],
fill: false,
tension: 0,
pointRadius: 0,
showLine: true
}
]
};

// Calculate points for supply and demand curves
// Assuming linear curves: S(Q) = m_s * Q, D(Q) = m_d * Q + b_d
// m_s = pe / qe
// m_d = -pe / qe
// b_d = pe – m_d * qe = pe – (-pe/qe)*qe = 2*pe
var slope_s = qe === 0 ? 0 : pe / qe;
var slope_d = qe === 0 ? 0 : -pe / qe;
var intercept_d = 2 * pe;

// Determine max quantity for chart scaling
var maxQ = Math.max(qe, qInt) * 1.2; // Add buffer
var numPoints = 50;
var stepQ = maxQ / numPoints;

for (var i = 0; i <= numPoints; i++) {
var q = i * stepQ;
if (q = 0) {
chartData.datasets[0].data.push({ x: q, y: priceS });
}
if (priceD >= 0) {
chartData.datasets[1].data.push({ x: q, y: priceD });
}
}

// Add intervention points
var qIntAdjusted = Math.min(qInt, maxQ); // Ensure qInt fits within chart scale

// Intervention line: Vertical line at Q_int, horizontal line at P_int
chartData.datasets[2].data.push({ x: qIntAdjusted, y: 0 }); // Bottom of vertical line
chartData.datasets[2].data.push({ x: qIntAdjusted, y: pInt }); // Top of vertical line

// Add horizontal line segment if needed, or use separate dataset
// Let’s add points for the horizontal line representing P_int across the relevant quantity range
var interventionLinePoints = [];
if (qIntAdjusted > 0) {
interventionLinePoints.push({ x: 0, y: pInt }); // Start of horizontal line
interventionLinePoints.push({ x: qIntAdjusted, y: pInt }); // End of horizontal line
}
// Add this as a new dataset or modify existing one. For simplicity, let’s stick to vertical line.

// The DWL triangle area needs to be visualized.
// Vertices of DWL triangle:
// 1. Intersection of Supply & Demand at Q_int (if P_int leads to Q_int)
// 2. Point on Supply Curve at Q_int
// 3. Point on Demand Curve at Q_int

// Simplified visualization: Show the points at Q_int.
// Point on Supply Curve at Q_int: (qInt, qInt * slope_s)
// Point on Demand Curve at Q_int: (qInt, slope_d * qInt + intercept_d)
// The Price Wedge is between these two points vertically at Q_int.
// P_consumer = P_int
// P_producer = qInt * slope_s (approx)

// Highlight the DWL triangle area (optional, complex with Canvas only)
// For simplicity, we’ll focus on plotting the curves and intervention line.

// Chart options
var chartOptions = {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
type: ‘linear’,
position: ‘bottom’,
title: {
display: true,
text: ‘Quantity’
},
min: 0,
max: maxQ
},
y: {
title: {
display: true,
text: ‘Price’
},
min: 0,
// max: Math.max(pe, pInt) * 1.5 // Auto-adjust max price
}
},
plugins: {
title: {
display: true,
text: ‘Supply, Demand, and Intervention’
},
tooltip: {
callbacks: {
label: function(context) {
var label = context.dataset.label || ”;
if (label) {
label += ‘: ‘;
}
if (context.parsed.y !== null) {
label += ‘$’ + context.parsed.y.toFixed(2) + ‘ at Qty ‘ + context.parsed.x.toFixed(2);
}
return label;
}
}
}
},
elements: {
line: {
// Global line settings if needed
},
point: {
// Global point settings if needed
}
}
};

// Add equilibrium point
if (qe >= 0 && pe >= 0) {
chartData.datasets.push({
label: ‘Equilibrium Point’,
data: [{x: qe, y: pe}],
borderColor: ‘rgb(40, 167, 69)’, // Success green
backgroundColor: ‘rgb(40, 167, 69)’,
pointRadius: 6,
pointHoverRadius: 8,
showLine: false
});
}

// Add intervention point (quantity traded at intervention price)
if (qInt >= 0 && pInt >= 0) {
chartData.datasets.push({
label: ‘Intervention Outcome’,
data: [{x: qInt, y: pInt}], // Assuming P_int is the consumer price at Q_int
borderColor: ‘rgb(255, 193, 7)’, // Warning yellow
backgroundColor: ‘rgb(255, 193, 7)’,
pointRadius: 6,
pointHoverRadius: 8,
showLine: false
});
}

// Create the chart
dwlChart = new Chart(ctx, {
type: ‘scatter’, // Use scatter to plot lines using x, y data points
data: chartData,
options: chartOptions
});
}

// Initial calculation on page load if values are present
document.addEventListener(‘DOMContentLoaded’, function() {
// Check if Chart.js is loaded (assuming it’s loaded externally or included via CDN)
// If Chart.js is NOT included, this part needs modification or removal.
// For this pure HTML output, we’ll assume Chart.js is available or needs to be included separately.
// If NOT using Chart.js, a pure SVG or Canvas implementation would be needed here.

// For this prompt, using a element requires manual drawing logic OR
// a charting library. Since no libraries are allowed, we’ll simulate drawing.
// **REPLACING CHART.JS WITH PURE CANVAS DRAWING**
drawInitialChart(); // Draw initial chart on load

// Add event listeners to inputs for real-time updates
var formInputs = document.querySelectorAll(‘#dwlForm input[type=”number”]’);
for (var i = 0; i < formInputs.length; i++) {
formInputs[i].addEventListener('input', function() {
// Clear results initially to avoid showing stale data
document.getElementById('resultsDiv').style.display = 'none';
// Debounce or throttled update might be better for performance,
// but for simplicity, direct update on input.
// Need to call calculateDeadweightLoss() AND updateChart()
// But validate first before calculating.
var currentErrors = document.querySelectorAll('.error-message');
var hasErrors = false;
for(var j=0; j availableWidth * (val / maxVal);
var yScale = (val, maxVal, availableHeight) => availableHeight * (1 – (val / maxVal));

// Determine max values for scaling
var maxX = Math.max(qe, qInt) * 1.2;
var maxY = Math.max(pe, pInt) * 1.5; // Max price considering equilibrium and intervention

// Draw axes
ctx.beginPath();
ctx.moveTo(padding, chartHeight – padding); // X-axis start
ctx.lineTo(chartWidth – padding, chartHeight – padding); // X-axis end
ctx.moveTo(padding, padding); // Y-axis start
ctx.lineTo(padding, chartHeight – padding); // Y-axis end
ctx.strokeStyle = ‘#ccc’;
ctx.lineWidth = 1;
ctx.stroke();

// Draw axis labels
ctx.fillStyle = ‘#333′;
ctx.font = ’12px Arial’;
ctx.textAlign = ‘center’;
ctx.fillText(‘Quantity’, chartWidth / 2, chartHeight – padding / 4);
ctx.save();
ctx.rotate(-Math.PI / 2);
ctx.fillText(‘Price’, -chartHeight / 2, padding / 4);
ctx.restore();

// Draw curves (simplified linear approximation)
// Supply Curve: S(Q) = m_s * Q where m_s = pe / qe
// Demand Curve: D(Q) = m_d * Q + b_d where m_d = -pe / qe, b_d = 2*pe
var slope_s = qe === 0 ? 0 : pe / qe;
var slope_d = qe === 0 ? 0 : -pe / qe;
var intercept_d = 2 * pe;

// Supply curve points
ctx.beginPath();
ctx.strokeStyle = ‘rgb(255, 99, 132)’; // Red
ctx.lineWidth = 2;
var startX_S = padding + xScale(0, maxX, chartWidth – 2 * padding);
var startY_S = chartHeight – padding – yScale(0, maxY, chartHeight – 2 * padding);
ctx.moveTo(startX_S, startY_S);

for (var q = 1; q = 0) {
var xPos = padding + xScale(q, maxX, chartWidth – 2 * padding);
var yPos = chartHeight – padding – yScale(priceS, maxY, chartHeight – 2 * padding);
ctx.lineTo(xPos, yPos);
}
}
ctx.stroke();

// Demand curve points
ctx.beginPath();
ctx.strokeStyle = ‘rgb(54, 162, 235)’; // Blue
ctx.lineWidth = 2;
var startX_D = padding + xScale(0, maxX, chartWidth – 2 * padding);
var startY_D = chartHeight – padding – yScale(intercept_d, maxY, chartHeight – 2 * padding);
ctx.moveTo(startX_D, startY_D);

for (var q = 1; q = 0) {
var xPos = padding + xScale(q, maxX, chartWidth – 2 * padding);
var yPos = chartHeight – padding – yScale(priceD, maxY, chartHeight – 2 * padding);
ctx.lineTo(xPos, yPos);
}
}
ctx.stroke();

// Draw Equilibrium Point
ctx.fillStyle = ‘rgb(40, 167, 69)’; // Green
var eqX = padding + xScale(qe, maxX, chartWidth – 2 * padding);
var eqY = chartHeight – padding – yScale(pe, maxY, chartHeight – 2 * padding);
ctx.beginPath();
ctx.arc(eqX, eqY, 5, 0, Math.PI * 2);
ctx.fill();
ctx.fillText(‘Eq (‘ + qe.toFixed(1) + ‘, $’ + pe.toFixed(2) + ‘)’, eqX + 20, eqY – 10);

// Draw Intervention Line (Vertical at Q_int, Horizontal at P_int)
ctx.beginPath();
ctx.setLineDash([5, 5]);
ctx.strokeStyle = ‘rgb(255, 193, 7)’; // Yellow
ctx.lineWidth = 2;

// Vertical line at Q_int
var intQX = padding + xScale(qInt, maxX, chartWidth – 2 * padding);
ctx.moveTo(intQX, chartHeight – padding);
ctx.lineTo(intQX, padding);
ctx.stroke();

// Horizontal line at P_int
var intPY = chartHeight – padding – yScale(pInt, maxY, chartHeight – 2 * padding);
ctx.moveTo(padding, intPY);
ctx.lineTo(chartWidth – padding, intPY);
ctx.stroke();
ctx.setLineDash([]); // Reset line dash

// Draw Intervention Outcome Point
ctx.fillStyle = ‘rgb(255, 193, 7)’; // Yellow
var intOutcomeX = intQX; // Use the Q_int x-coordinate
var intOutcomeY = intPY; // Use the P_int y-coordinate
ctx.beginPath();
ctx.arc(intOutcomeX, intOutcomeY, 5, 0, Math.PI * 2);
ctx.fill();
ctx.fillText(‘Int (‘ + qInt.toFixed(1) + ‘, $’ + pInt.toFixed(2) + ‘)’, intOutcomeX + 20, intOutcomeY – 10);

// — Draw DWL Triangle —
// Vertices:
// A: Point on Demand curve at Q_int => (qInt, D(qInt))
// B: Point on Supply curve at Q_int => (qInt, S(qInt))
// C: Point related to the price wedge affecting transactions
// For DWL = 0.5 * PW * (Qe – Q_int)
// PW = P_consumer – P_producer
// var P_consumer = P_int
// P_producer = qInt * slope_s (approx)
// P_demand_at_Qint = slope_d * qInt + intercept_d

var consumerPriceAtQint = pInt; // As per input
var producerPriceAtQint = qInt * slope_s;
var demandPriceAtQint = slope_d * qInt + intercept_d;

// Ensure P_producer isn’t negative and P_demand_at_Qint is relevant
producerPriceAtQint = Math.max(0, producerPriceAtQint);
demandPriceAtQint = Math.max(0, demandPriceAtQint);

// The DWL triangle has vertices at:
// 1. Intersection of P_int line and Demand Curve at Q_int (if P_int Supply Price at Q_int)
// 3. The point (Q_int, P_producer) or (Q_int, P_consumer) depending on which side of equilibrium the intervention is.

// Let’s redraw based on standard DWL triangle visualization:
// Base of triangle is (Qe – Q_int)
// Height is the Price Wedge (P_consumer – P_producer at Q_int)

var dwlTriangleX1 = padding + xScale(qInt, maxX, chartWidth – 2 * padding);
var dwlTriangleY1 = chartHeight – padding – yScale(Math.min(consumerPriceAtQint, demandPriceAtQint), maxY, chartHeight – 2 * padding); // Point on demand curve or P_int
if(consumerPriceAtQint > demandPriceAtQint) dwlTriangleY1 = chartHeight – padding – yScale(demandPriceAtQint, maxY, chartHeight – 2 * padding); // Point on demand curve

var dwlTriangleX2 = padding + xScale(qInt, maxX, chartWidth – 2 * padding);
var dwlTriangleY2 = chartHeight – padding – yScale(Math.max(producerPriceAtQint, 0), maxY, chartHeight – 2 * padding); // Point on supply curve

var dwlTriangleX3 = padding + xScale(qe, maxX, chartWidth – 2 * padding);
var dwlTriangleY3 = chartHeight – padding – yScale(pe, maxY, chartHeight – 2 * padding); // Equilibrium point (used as reference)

// The triangle is formed by the intersection of Price Wedge lines and the Quantity Reduction
// Vertices are:
// Top left: (Q_int, P_consumer) –> (qInt, pInt)
// Top right: (Qe, P_consumer_at_Qe) –> Not directly plotted, this is complex
// Bottom left: (Q_int, P_producer) –> (qInt, producerPriceAtQint)
// Bottom right: (Qe, P_producer_at_Qe) –> Not directly plotted

// Let’s draw the DWL area using the calculated PW and Q Reduction.
// Vertices of the DWL triangle are:
// 1. Point on Demand Curve at Q_int: (qInt, demandPriceAtQint)
// 2. Point on Supply Curve at Q_int: (qInt, producerPriceAtQint)
// 3. Intersection of lines representing where transactions stop.

// Let’s draw a shaded area representing the DWL triangle.
// The DWL triangle vertices are:
// V1: (Q_int, P_producer_at_Q_int)
// V2: (Q_int, P_consumer_at_Q_int) –> P_int if P_int On supply curve at Q_int
// P2: (qInt, pInt) –> Intervention outcome point
// P3: (Qe, Pe) –> Equilibrium point (This is NOT a vertex of the DWL triangle)

// Correct vertices for DWL Triangle:
// Vertex 1: Intersection of Demand curve with the price producers receive at Q_int.
// Vertex 2: Intersection of Supply curve with the price consumers pay at Q_int.
// Vertex 3: The point (Q_int, P_producer) or (Q_int, P_consumer) depending on intervention.

// Let’s define PW = pInt – producerPriceAtQint. (Assuming P_int > producerPriceAtQint)
// If PW > 0:
var dwlX1 = padding + xScale(qInt, maxX, chartWidth – 2 * padding);
var dwlY1 = chartHeight – padding – yScale(producerPriceAtQint, maxY, chartHeight – 2 * padding); // Point on supply curve at Q_int

var dwlX2 = padding + xScale(qInt, maxX, chartWidth – 2 * padding);
var dwlY2 = chartHeight – padding – yScale(pInt, maxY, chartHeight – 2 * padding); // Point related to P_int at Q_int

var dwlX3 = padding + xScale(qe, maxX, chartWidth – 2 * padding);
var dwlY3 = chartHeight – padding – yScale(pe, maxY, chartHeight – 2 * padding); // Equilibrium point

// The DWL triangle is bounded by:
// – The supply curve
// – The demand curve
// – The vertical line at Q_int representing quantity reduction from Qe.
// Vertices:
// 1. (Q_int, Producer Price at Q_int)
// 2. (Q_int, Consumer Price at Q_int) –> This is P_int if P_int P_producer at Q_int)
// This happens when intervention creates a wedge.
if (PW > 0 && Q_at_Pp >= 0) { // Ensure valid quantity
var dwlV1_x = padding + xScale(qInt, maxX, chartWidth – 2 * padding);
var dwlV1_y = chartHeight – padding – yScale(producerPriceAtQint, maxY, chartHeight – 2 * padding);

var dwlV2_x = padding + xScale(qInt, maxX, chartWidth – 2 * padding);
var dwlV2_y = chartHeight – padding – yScale(pInt, maxY, chartHeight – 2 * padding);

var dwlV3_x = padding + xScale(Q_at_Pp, maxX, chartWidth – 2 * padding);
var dwlV3_y = chartHeight – padding – yScale(producerPriceAtQint, maxY, chartHeight – 2 * padding); // Same price as V1

// Only draw if Q_at_Pp is relevant (e.g., positive and potentially forming a triangle)
if(Q_at_Pp > 0) {
ctx.beginPath();
ctx.fillStyle = ‘rgba(255, 99, 132, 0.3)’; // Semi-transparent red for DWL area
ctx.moveTo(dwlV1_x, dwlV1_y);
ctx.lineTo(dwlV2_x, dwlV2_y);
ctx.lineTo(dwlV3_x, dwlV3_y);
ctx.closePath();
ctx.fill();
}
}
}

// Update the calculation and drawing function to call drawChartCanvas
function calculateDeadweightLoss() {
// … (validation and calculation logic remains the same) …

// Get values
var qe = parseFloat(document.getElementById(‘quantityDemandedAtEquilibrium’).value);
var pe = parseFloat(document.getElementById(‘priceDemandedAtEquilibrium’).value);
var pInt = parseFloat(document.getElementById(‘priceWithIntervention’).value);
var qsInt = parseFloat(document.getElementById(‘quantitySuppliedAtIntervention’).value);
var qdInt = parseFloat(document.getElementById(‘quantityDemandedAtIntervention’).value);

var qInt = Math.min(qsInt, qdInt);
var quantityReduction = qe – qInt;
if (quantityReduction 0 && slope_s > 0) ? qInt * slope_s : 0;
var priceWedgeValue = Math.max(0, pInt – producerPriceApprox);

var deadweightLoss = 0.5 * priceWedgeValue * quantityReduction;
var totalSurplusLossValue = deadweightLoss;

// Display Results
document.getElementById(‘mainResult’).innerText = ‘$’ + deadweightLoss.toFixed(2);
document.getElementById(‘quantityTradedInt’).innerText = qInt.toFixed(2);
document.getElementById(‘priceWedge’).innerText = ‘$’ + priceWedgeValue.toFixed(2);
document.getElementById(‘totalSurplusLoss’).innerText = ‘$’ + totalSurplusLossValue.toFixed(2);
document.getElementById(‘resultsDiv’).style.display = ‘block’;

// — REDRAW CHART —
// Need to pass all relevant values to drawChartCanvas
drawChartCanvas(qe, qInt, pe, pInt, priceWedgeValue, quantityReduction);
}

// Initial call on load to draw the chart with default values
document.addEventListener(‘DOMContentLoaded’, function() {
// Ensure canvas element exists
if (document.getElementById(‘dwlChart’)) {
calculateDeadweightLoss(); // This will trigger drawing the chart
} else {
console.error(“Canvas element with ID ‘dwlChart’ not found.”);
}

// Attach input event listeners AFTER initial calculation
var formInputs = document.querySelectorAll(‘#dwlForm input[type=”number”]’);
for (var i = 0; i < formInputs.length; i++) {
formInputs[i].addEventListener('input', function() {
document.getElementById('resultsDiv').style.display = 'none'; // Hide results while typing
// Re-validate and calculate if inputs are valid
var allValid = true;
allValid = validateInput('quantityDemandedAtEquilibrium', 'errorQuantityDemandedAtEquilibrium', 0) && allValid;
allValid = validateInput('priceDemandedAtEquilibrium', 'errorPriceDemandedAtEquilibrium', 0) && allValid;
allValid = validateInput('priceWithIntervention', 'errorPriceWithIntervention', 0) && allValid;
allValid = validateInput('quantitySuppliedAtIntervention', 'errorQuantitySuppliedAtIntervention', 0) && allValid;
allValid = validateInput('quantityDemandedAtIntervention', 'errorQuantityDemandedAtIntervention', 0) && allValid;

if(allValid) {
calculateDeadweightLoss();
} else {
// Clear canvas if inputs become invalid
var canvas = document.getElementById('dwlChart');
if (canvas) {
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
}
});
}
});

Leave a Comment