Test

#tax-incidence-app {
font-family: system-ui, -apple-system, BlinkMacSystemFont, “Segoe UI”, sans-serif;
max-width: 1100px;
margin: 24px auto;
padding: 20px;
border: 1px solid #d0d7de;
border-radius: 14px;
background: #ffffff;
color: #1f2328;
line-height: 1.45;
}

#tax-incidence-app h2 {
margin: 0 0 8px 0;
font-size: 28px;
color: #0b2f5b;
}

#tax-incidence-app .subtitle {
margin-bottom: 18px;
color: #57606a;
font-size: 16px;
}

#tax-incidence-app .grid {
display: grid;
grid-template-columns: 320px 1fr;
gap: 20px;
}

#tax-incidence-app .panel {
border: 1px solid #d0d7de;
border-radius: 12px;
padding: 16px;
background: #f6f8fa;
}

#tax-incidence-app label {
display: block;
margin: 14px 0 6px 0;
font-weight: 600;
}

#tax-incidence-app input[type=”range”] {
width: 100%;
}

#tax-incidence-app .value {
font-weight: 700;
color: #0b2f5b;
}

#tax-incidence-app .formula {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
background: #ffffff;
border: 1px solid #d0d7de;
border-radius: 8px;
padding: 10px;
margin: 8px 0;
font-size: 14px;
}

#tax-incidence-app table {
width: 100%;
border-collapse: collapse;
margin-top: 14px;
background: #ffffff;
font-size: 14px;
}

#tax-incidence-app th,
#tax-incidence-app td {
border: 1px solid #d0d7de;
padding: 8px;
text-align: right;
}

#tax-incidence-app th:first-child,
#tax-incidence-app td:first-child {
text-align: left;
}

#tax-incidence-app th {
background: #eaeef2;
}

#tax-incidence-app .note {
margin-top: 14px;
padding: 12px;
background: #fff8c5;
border: 1px solid #eac54f;
border-radius: 10px;
font-size: 15px;
}

#tax-incidence-app .graph-wrap {
background: #ffffff;
border: 1px solid #d0d7de;
border-radius: 12px;
padding: 12px;
}

#tax-incidence-app svg {
width: 100%;
height: auto;
display: block;
}

#tax-incidence-app .small {
font-size: 13px;
color: #57606a;
}

@media (max-width: 850px) {
#tax-incidence-app .grid {
grid-template-columns: 1fr;
}
}

Tassa per unità e incidenza fiscale

Simulazione per un corso di Principi di economia politica.
Il grafico mostra domanda, offerta, gettito fiscale e perdita secca.

Parametri

Domanda: Qd = a – bP
Offerta: Qs = c + dP
Tassa per unità: t

a, intercetta della domanda: 100

b, pendenza della domanda: 10

c, intercetta dell’offerta: 20

d, pendenza dell’offerta: 10

t, tassa per unità: 2

Risultati

Voce Senza tassa Con tassa Variazione
Definizioni: Pc è il prezzo pagato dai consumatori. Ps è il prezzo ricevuto dai venditori.
La tassa crea un cuneo: Pc – Ps = t.

(function () {
const el = id => document.getElementById(id);

const inputs = [“a”, “b”, “c”, “d”, “t”].map(id => el(id));

function fmt(x) {
if (!isFinite(x)) return “-“;
const rounded = Math.round(x * 100) / 100;
return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(2);
}

function money(x) {
return fmt(x) + ” €”;
}

function qDemand(a, b, p) {
return a – b * p;
}

function pDemand(a, b, q) {
return (a – q) / b;
}

function pSupply(c, d, q) {
return (q – c) / d;
}

function compute(a, b, c, d, t) {
const p0 = (a – c) / (b + d);
const q0 = a – b * p0;

const ps = (a – c – b * t) / (b + d);
const pc = ps + t;
const q1 = a – b * pc;

const valid = p0 >= 0 && q0 >= 0 && ps >= 0 && pc >= 0 && q1 >= 0;

const revenue = valid ? t * q1 : 0;
const dQ = valid ? q0 – q1 : 0;
const dwl = valid ? 0.5 * t * dQ : 0;

const consumerBurden = valid ? pc – p0 : 0;
const producerBurden = valid ? p0 – ps : 0;

return { p0, q0, ps, pc, q1, revenue, dQ, dwl, consumerBurden, producerBurden, valid };
}

function drawGraph(a, b, c, d, t, r) {
const svg = el(“graph”);
svg.innerHTML = “”;

const W = 760;
const H = 520;
const m = { left: 72, right: 32, top: 38, bottom: 72 };
const plotW = W – m.left – m.right;
const plotH = H – m.top – m.bottom;

const qMaxRaw = Math.max(a, r.q0, r.q1, 100);
const pMaxRaw = Math.max(a / b, pSupply(c, d, qMaxRaw), r.pc, r.p0, 10);

const qMax = Math.ceil(qMaxRaw / 10) * 10;
const pMax = Math.ceil((pMaxRaw + 1) / 2) * 2;

const x = q => m.left + (q / qMax) * plotW;
const y = p => m.top + plotH – (p / pMax) * plotH;

function line(x1, y1, x2, y2, stroke, width, dash) {
const node = document.createElementNS(“http://www.w3.org/2000/svg”, “line”);
node.setAttribute(“x1”, x1);
node.setAttribute(“y1”, y1);
node.setAttribute(“x2”, x2);
node.setAttribute(“y2”, y2);
node.setAttribute(“stroke”, stroke);
node.setAttribute(“stroke-width”, width || 2);
if (dash) node.setAttribute(“stroke-dasharray”, dash);
svg.appendChild(node);
}

function text(content, xPos, yPos, size, fill, anchor, weight) {
const node = document.createElementNS(“http://www.w3.org/2000/svg”, “text”);
node.textContent = content;
node.setAttribute(“x”, xPos);
node.setAttribute(“y”, yPos);
node.setAttribute(“font-size”, size || 14);
node.setAttribute(“fill”, fill || “#1f2328”);
node.setAttribute(“text-anchor”, anchor || “start”);
node.setAttribute(“font-family”, “system-ui, -apple-system, Segoe UI, sans-serif”);
if (weight) node.setAttribute(“font-weight”, weight);
svg.appendChild(node);
}

function circle(cx, cy, radius, fill) {
const node = document.createElementNS(“http://www.w3.org/2000/svg”, “circle”);
node.setAttribute(“cx”, cx);
node.setAttribute(“cy”, cy);
node.setAttribute(“r”, radius);
node.setAttribute(“fill”, fill);
svg.appendChild(node);
}

function polygon(points, fill, stroke) {
const node = document.createElementNS(“http://www.w3.org/2000/svg”, “polygon”);
node.setAttribute(“points”, points.map(p => p.join(“,”)).join(” “));
node.setAttribute(“fill”, fill);
node.setAttribute(“stroke”, stroke || “none”);
node.setAttribute(“stroke-width”, “1.5”);
svg.appendChild(node);
}

function rect(xPos, yPos, w, h, fill, stroke) {
const node = document.createElementNS(“http://www.w3.org/2000/svg”, “rect”);
node.setAttribute(“x”, xPos);
node.setAttribute(“y”, yPos);
node.setAttribute(“width”, w);
node.setAttribute(“height”, h);
node.setAttribute(“fill”, fill);
node.setAttribute(“stroke”, stroke || “none”);
node.setAttribute(“stroke-width”, “1.5”);
svg.appendChild(node);
}

// Assi
line(m.left, m.top + plotH, m.left + plotW, m.top + plotH, “#24292f”, 2);
line(m.left, m.top, m.left, m.top + plotH, “#24292f”, 2);

// Frecce assi
polygon([[m.left + plotW, m.top + plotH], [m.left + plotW – 10, m.top + plotH – 5], [m.left + plotW – 10, m.top + plotH + 5]], “#24292f”);
polygon([[m.left, m.top], [m.left – 5, m.top + 10], [m.left + 5, m.top + 10]], “#24292f”);

text(“Quantità Q”, m.left + plotW – 10, H – 26, 15, “#24292f”, “end”, “600”);
text(“Prezzo P”, 16, m.top + 8, 15, “#24292f”, “start”, “600”);

// Griglia e tacche
const qStep = qMax / 5;
for (let i = 0; i <= 5; i++) {
const q = i * qStep;
line(x(q), m.top, x(q), m.top + plotH, "#eaeef2", 1);
text(fmt(q), x(q), m.top + plotH + 22, 12, "#57606a", "middle");
}

const pStep = pMax / 5;
for (let i = 0; i 0 && r.q1 > 0) {
rect(x(0), y(r.pc), x(r.q1) – x(0), y(r.ps) – y(r.pc), “rgba(255, 212, 0, 0.45)”, “#9a6700”);
text(“Gettito = t × Q”, x(r.q1 / 2), y((r.pc + r.ps) / 2) – 4, 14, “#7d4e00”, “middle”, “700”);
text(money(r.revenue), x(r.q1 / 2), y((r.pc + r.ps) / 2) + 16, 14, “#7d4e00”, “middle”, “700”);
}

// Perdita secca: triangolo tra Q1 e Q0, domanda e offerta
if (t > 0 && r.dQ > 0) {
polygon(
[
[x(r.q1), y(r.pc)],
[x(r.q1), y(r.ps)],
[x(r.q0), y(r.p0)]
],
“rgba(251, 143, 57, 0.45)”,
“#bc4c00”
);
text(“Perdita secca”, x((r.q1 + r.q0) / 2) + 12, y(r.p0) + 42, 14, “#bc4c00”, “start”, “700”);
text(money(r.dwl), x((r.q1 + r.q0) / 2) + 12, y(r.p0) + 62, 14, “#bc4c00”, “start”, “700”);
}

// Linee equilibrio senza tassa
line(x(r.q0), y(0), x(r.q0), y(r.p0), “#57606a”, 1.5, “6 5”);
line(x(0), y(r.p0), x(r.q0), y(r.p0), “#57606a”, 1.5, “6 5”);
circle(x(r.q0), y(r.p0), 6, “#24292f”);

text(“Equilibrio senza tassa”, x(r.q0) + 10, y(r.p0) – 22, 14, “#24292f”, “start”, “700”);
text(“P* = ” + fmt(r.p0) + “, Q* = ” + fmt(r.q0), x(r.q0) + 10, y(r.p0) – 4, 13, “#24292f”);

// Linee equilibrio con tassa
line(x(r.q1), y(0), x(r.q1), y(r.pc), “#24292f”, 1.5, “6 5”);
line(x(0), y(r.pc), x(r.q1), y(r.pc), “#0969da”, 1.5, “6 5”);
line(x(0), y(r.ps), x(r.q1), y(r.ps), “#cf222e”, 1.5, “6 5”);

circle(x(r.q1), y(r.pc), 6, “#0969da”);
circle(x(r.q1), y(r.ps), 6, “#cf222e”);

// Cuneo fiscale
if (t > 0) {
line(x(r.q1) + 14, y(r.pc), x(r.q1) + 14, y(r.ps), “#24292f”, 2);
line(x(r.q1) + 8, y(r.pc), x(r.q1) + 20, y(r.pc), “#24292f”, 2);
line(x(r.q1) + 8, y(r.ps), x(r.q1) + 20, y(r.ps), “#24292f”, 2);
text(“t = ” + fmt(t), x(r.q1) + 24, y((r.pc + r.ps) / 2) + 5, 14, “#24292f”, “start”, “700”);
}

text(“Pc = ” + fmt(r.pc), x(0) + 8, y(r.pc) – 8, 14, “#0969da”, “start”, “700”);
text(“Ps = ” + fmt(r.ps), x(0) + 8, y(r.ps) + 18, 14, “#cf222e”, “start”, “700”);
text(“Q con tassa = ” + fmt(r.q1), x(r.q1), m.top + plotH + 44, 14, “#24292f”, “middle”, “700”);
}

function update() {
const a = Number(el(“a”).value);
const b = Number(el(“b”).value);
const c = Number(el(“c”).value);
const d = Number(el(“d”).value);
const t = Number(el(“t”).value);

el(“aVal”).textContent = fmt(a);
el(“bVal”).textContent = fmt(b);
el(“cVal”).textContent = fmt(c);
el(“dVal”).textContent = fmt(d);
el(“tVal”).textContent = fmt(t);

const r = compute(a, b, c, d, t);

drawGraph(a, b, c, d, t, r);

const table = el(“resultsTable”);

if (!r.valid) {
table.innerHTML = `

Con questi parametri l’equilibrio con tassa non è valido: prezzo o quantità diventano negativi.
Riduci la tassa oppure modifica domanda e offerta.

`;
el(“calculationBox”).innerHTML = “”;
el(“interpretation”).innerHTML = “Parametri non validi per una rappresentazione economica standard.”;
return;
}

table.innerHTML = `

Prezzo pagato dai consumatori ${money(r.p0)} ${money(r.pc)} ${money(r.consumerBurden)} Prezzo ricevuto dai venditori ${money(r.p0)} ${money(r.ps)} -${money(r.producerBurden)} Quantità scambiata ${fmt(r.q0)} ${fmt(r.q1)} -${fmt(r.dQ)} Gettito fiscale 0 € ${money(r.revenue)} +${money(r.revenue)} Perdita secca 0 € ${money(r.dwl)} +${money(r.dwl)}

`;

el(“calculationBox”).innerHTML = `
Equilibrio senza tassa:
P* = (a – c) / (b + d) = (${fmt(a)} – ${fmt(c)}) / (${fmt(b)} + ${fmt(d)}) = ${fmt(r.p0)}
Q* = a – bP* = ${fmt(a)} – ${fmt(b)} × ${fmt(r.p0)} = ${fmt(r.q0)}

Con tassa t = ${fmt(t)}:
Pc = Ps + t
Ps = (a – c – bt) / (b + d) = ${fmt(r.ps)}
Pc = ${fmt(r.pc)}
Q con tassa = ${fmt(r.q1)}

Gettito fiscale = t × Q = ${fmt(t)} × ${fmt(r.q1)} = ${money(r.revenue)}
Perdita secca = 1/2 × t × (Q* – Q con tassa) = 1/2 × ${fmt(t)} × (${fmt(r.q0)} – ${fmt(r.q1)}) = ${money(r.dwl)}
`;

el(“interpretation”).innerHTML = `
La tassa crea un cuneo tra il prezzo pagato dai consumatori e il prezzo ricevuto dai venditori.
In questo caso i consumatori pagano ${money(r.consumerBurden)} in più per unità, mentre i venditori ricevono ${money(r.producerBurden)} in meno per unità.
Il gettito è ${money(r.revenue)} e la perdita secca è ${money(r.dwl)}.
`;
}

inputs.forEach(input => input.addEventListener(“input”, update));
update();
})();