Skip to content

Instantly share code, notes, and snippets.

@MKRhere
Last active July 26, 2022 05:51
Show Gist options
  • Save MKRhere/39f81b6ac411c1ae4d8e4236af70efd2 to your computer and use it in GitHub Desktop.
Save MKRhere/39f81b6ac411c1ae4d8e4236af70efd2 to your computer and use it in GitHub Desktop.
tax.india.mkr.pw source
import { tax } from "./incomeTax.mjs";
const data = Object.assign(
Array(100_000)
.fill(null)
.map((_, i) => i * 100)
.map(x => ({ x, y: tax(x) })),
{ x: "income", y: "tax" },
);
const margin = { top: 20, right: 30, bottom: 30, left: 80 };
const height = 500;
const width = 1000;
const line = d3
.line()
.defined(d => !isNaN(d.y))
.x(d => x(d.x))
.y(d => y(d.y));
const x = d3
.scaleLinear()
.domain(d3.extent(data, d => d.x))
.range([margin.left, width - margin.right]);
const y = d3
.scaleLinear()
.domain(d3.extent(data, d => d.y))
.range([height - margin.bottom, margin.top]);
const xAxis = g =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x))
.call(g => g.select(".domain").remove())
.call(g =>
g
.select(".tick:last-of-type text")
.clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.x),
);
const yAxis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
.call(g =>
g
.select(".tick:last-of-type text")
.clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y),
);
const svg = d3
.select("#income-tax-graph")
.append("svg")
.attr("viewBox", [0, 0, width, height]);
svg.append("g").call(xAxis);
svg.append("g").call(yAxis);
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("d", line);
const SLAB_25 = 2_50_000;
const SLAB_50 = 5_00_000;
const SLAB_75 = 7_50_000;
const SLAB_100 = 10_00_000;
const SLAB_125 = 12_50_000;
const SLAB_150 = 15_00_000;
const SLAB_500 = 50_00_000;
const SUR_SLAB_1000 = 1_00_00_000;
const SUR_SLAB_2000 = 2_00_00_000;
const SUR_SLAB_5000 = 5_00_00_000;
const withSurcharge = (
income,
base,
surchargeRatio,
prevSlab,
taxOnPrevSlab,
) => {
const plusSurcharge = base * surchargeRatio;
const diffIncome = income - prevSlab;
const diffTax = plusSurcharge - taxOnPrevSlab;
return diffTax > diffIncome
? plusSurcharge - (diffTax - diffIncome)
: plusSurcharge;
};
const baseTax = income => {
// if (income <= SLAB_25) return 0;
// if (income <= SLAB_50) return income * 0.05;
// gov provides rebate for 250k-500k slab
if (income <= SLAB_50) return 0;
if (income <= SLAB_75) return 12_500 + (income - SLAB_50) * 0.1;
if (income <= SLAB_100) return 37_500 + (income - SLAB_75) * 0.15;
if (income <= SLAB_125) return 75_000 + (income - SLAB_100) * 0.2;
if (income <= SLAB_150) return 1_25_000 + (income - SLAB_125) * 0.25;
return 1_87_500 + (income - SLAB_150) * 0.3;
};
const upperTax = income => {
const baseHI = baseTax(income);
if (income <= SUR_SLAB_1000)
return withSurcharge(income, baseHI, 1.1, SLAB_500, baseTax(SLAB_500));
if (income <= SUR_SLAB_2000)
return withSurcharge(
income,
baseHI,
1.15,
SUR_SLAB_1000,
baseTax(SUR_SLAB_1000) * 1.1,
);
if (income <= SUR_SLAB_5000)
return withSurcharge(
income,
baseHI,
1.25,
SUR_SLAB_2000,
baseTax(SUR_SLAB_2000) * 1.15,
);
// above 5Cr
return withSurcharge(
income,
baseHI,
1.37,
SUR_SLAB_5000,
baseTax(SUR_SLAB_5000) * 1.25,
);
};
export const tax = income => {
if (income <= SLAB_500) return baseTax(income) * 1.04;
return upperTax(income) * 1.04;
};
<!DOCTYPE html>
<head>
<title>Income tax calculator for new tax regime 2021-22 (India)</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<h1>Income tax calculator for new tax regime 2021-22 (India)</h1>
<div id="income-tax-graph"></div>
<div class="inputs">
<label>Enter income <input type="text" id="income-input" /></label>
<div id="income-output"></div>
</div>
<script src="https://d3js.org/d3.v4.js"></script>
<script src="/d3.mjs" type="module"></script>
<script src="/input.mjs" type="module"></script>
</body>
import { tax } from "./incomeTax.mjs";
const input = document.querySelector("#income-input");
const output = document.querySelector("#income-output");
const round10 = num => {
num = Math.round(num);
const d = num % 10;
if (d < 5) return num - d;
return num + 10 - d;
};
input.addEventListener("input", e => {
const value = e.target.value.replace(/[,_]/g, "");
const income = parseInt(value);
if (!income) return;
const t = round10(tax(round10(income)));
output.textContent = t
? "Your new tax regime liability would be: " + new Intl.NumberFormat("en-IN").format(t)
: "You owe no tax!";
});
:root {
font-family: sans-serif;
}
h1 {
text-align: center;
}
#income-tax-graph {
max-width: 80vw;
margin: auto;
}
.inputs {
margin-block: 5rem;
display: flex;
flex-direction: column;
gap: 1rem;
align-items: center;
justify-content: center;
width: 100%;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment