randomfox (randomfox) wrote,
randomfox
randomfox

Loan Amortization Calculator in Javascript


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<meta http-equiv="Content-Language" content="en-us" />
<meta http-equiv="imagetoolbar" content="false" />
<meta name="MSSmartTagsPreventParsing" content="true" />
<meta name="author" content="Po Shan Cheah" />

<title>Loan Amortization calculator</title>

<script type="text/javascript">

function clearOutput() {
    var output = document.getElementById("output");
    while (output.firstChild)
	output.removeChild(output.firstChild);
}

// Write a string to the output area.
function write(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    output.appendChild(txt);
}

// Write a string with a newline to the output area.
function writeln(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    var newline = document.createElement("br");
    output.appendChild(txt);
    output.appendChild(newline);
}

// Write a string in red to signify an error.
function errorln(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    var newline = document.createElement("br");
    var span = document.createElement("span");
    // setAttribute("class" ...) does not work in IE.
    span.className = "error";
    span.appendChild(txt);
    span.appendChild(newline);
    output.appendChild(span);
}

// Format floating point number in fixed-point notation.
function fixedfmt(num, decimals) {
    // Number.toFixed is a Javascript 1.5 feature, 
    // so we need to test for it here.
    return num.toFixed ? num.toFixed(decimals) : num;
}

function fmtmoney(num) {
    if (Math.abs(num) < 0.005)
	num = 0;
    return "$" + fixedfmt(num, 2);
}

function fmtpct(num) {
    return fixedfmt(num * 100, 2) + "%";
}

function flushright(s, width) {
    var str = s.toString();
    var pad = width - str.length;
    for (var i = 0; i < pad; ++i)
	str = " " + str;
    return str;
}

// Get numbers from the input fields.
function getInput() {
    var field;
    var obj = new Object();

    field = document.getElementById("principal");
    obj.principal = parseFloat(field.value);
    if (isNaN(obj.principal) || obj.principal <= 0) {
	errorln("Invalid principal amount '" + field.value + 
		"'. Need a positive number.");
	return false;
    }

    field = document.getElementById("amortperiod");
    obj.amortperiod = parseFloat(field.value);
    if (isNaN(obj.amortperiod) || obj.amortperiod <= 0) {
	errorln("Invalid amortization period '" + field.value + 
		"'. Need a positive number.");
	return false;
    }

    field = document.getElementById("paymentsperyear");
    obj.payperyear = parseInt(field.value);
    if (isNaN(obj.payperyear) || obj.payperyear <= 0) {
	errorln("Invalid number of payments per year '" + field.value + 
		"'. Need a positive integer.");
	return false;
    }

    field = document.getElementById("interest");
    obj.interest = parseFloat(field.value) / 100;
    if (isNaN(obj.interest) || obj.interest <= 0) {
	errorln("Invalid interest rate '" + field.value + 
		"'. Need a positive number.");
	return false;
    }

    return obj;
}

function main() {
    clearOutput();

    var input = getInput();
    if (!input)
	return false;

    var intrate = input.interest / input.payperyear;
    var numpayments = input.amortperiod * input.payperyear;

    var x = Math.pow(1 + intrate, numpayments);
    var payments = intrate * input.principal * x / (x - 1);

    writeln("Payments       = " + fmtmoney(payments));
    writeln("Total payments = " + fmtmoney(payments * numpayments));
    writeln("Interest cost  = " + 
	    fmtmoney(payments * numpayments - input.principal));
    writeln("");

    var balance = input.principal;
    var sumint = 0;
    var sumprin = 0;
    var sumpay = 0;

    writeln("Period     Payment    Interest   Principal   " + 
	    "Total Pay   Total Int  Total Prin     Balance");
    for (var i = 1; i <= numpayments; ++i) {
	sumpay += payments;

	var thisint = balance * intrate;
	sumint += thisint;

	var thisprin = payments - thisint;
	sumprin += thisprin;

	balance -= thisprin;

	writeln(flushright(i, 6) + "  " + 
		flushright(fmtmoney(payments), 10) + "  " + 
		flushright(fmtmoney(thisint), 10) + "  " + 
		flushright(fmtmoney(thisprin), 10) + "  " + 
		flushright(fmtmoney(sumpay), 10) + "  " + 
		flushright(fmtmoney(sumint), 10) + "  " + 
		flushright(fmtmoney(sumprin), 10) + "  " + 
		flushright(fmtmoney(balance), 10));
    }
}
</script>

<style type="text/css">
body {
    background: #fff none;
    color: #000;
    font: normal 14px Tahoma, Verdana, Arial, Helvetica, sans-serif;
}

.error {
    color: red;
}

#output {
    white-space: pre;
    font: normal 14px monospace;
}
</style>
</head>

<body>
    <h1>Loan Amortization calculator</h1>
    <noscript>
	<span class="error">
	    The Loan Amortization calculator requires a browser that supports Javascript.<br />
	    Your browser either does not support Javascript or it has Javascript disabled. If you wish to run the solver, please upgrade your browser or enable Javascript support.<br />&nbsp;<br />
	</span>
    </noscript>

    <script type="text/javascript">
<!--
// Test for W3C DOM API.
if (document.getElementById) {
}
else {
    document.write('<span class="error">The Loan Amortization calculator requires a browser that supports the W3C DOM API.<br \/>Your browser does not support this API. If you wish to run the solver, please upgrade your browser. The latest versions of Mozilla Firefox, Opera, and Internet Explorer have support for this API.<br \/>&nbsp;<br \/><\/span>');
}
// -->
    </script>

    <form action="#" onsubmit="main(); return false;">
	<table cellpadding="5">
	    <tr>
		<td><label for="principal">Principal:</label></td>
		<td><input type="text" name="principal" id="principal" size="20" value="50" /></td>
	    </tr>
	    <tr>
		<td><label for="amortperiod">Amortization Period:<br /><small>(in years)</small></label></td>
		<td><input type="text" name="amortperiod" id="amortperiod" size="20" value="3" /></td>
	    </tr>
	    <tr>
		<td><label for="paymentsperyear">Payments per year:<br /><small>(monthly = 12, weekly = 52)</small></label></td>
		<td><input type="text" name="paymentsperyear" id="paymentsperyear" size="20" value="12" /></td>
	    </tr>
	    <tr>
		<td><label for="interest">Interest rate:</label></td>
		<td><input type="text" name="interest" id="interest" size="20" value="20" /></td>
	    </tr>
	    <tr>
		<td colspan="2"><input type="submit" value="Calculate!" /></td>
	    </tr>
	</table>
    </form>

    <hr />
    <div id="output">
    </div>
</body>
</html>
<!--
Last updated: August 24, 2006
-->
<!-- vim:set tw=0: -->

Subscribe
Comments for this post were disabled by the author