Skip to content

Commit

Permalink
JS Modernization; Credit Simulator; Update math.js
Browse files Browse the repository at this point in the history
  • Loading branch information
TCB13 committed Oct 24, 2024
1 parent 1121608 commit 6471a4b
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 86 deletions.
4 changes: 1 addition & 3 deletions INCLUDED_LICENSES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@
/**
* math.js
* https://github.com/josdejong/mathjs
* Licensed under Apache License 2.0 (https://github.com/josdejong/mathjs/blob/develop/LICENSE)
*
* Math.js is an extensive math library for JavaScript and Node.js,
* It features real and complex numbers, units, matrices, a large set of
* mathematical functions, and a flexible expression parser.
*
* @version 5.9.0
* @date 2019-05-08
*
* @license
* Copyright (C) 2013-2019 Jos de Jong <[email protected]>
*
Expand Down
3 changes: 2 additions & 1 deletion cache.manifest
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CACHE MANIFEST

# Version 0.0.2
# Version 1.3.0

NETWORK: *

Expand All @@ -16,5 +16,6 @@ popper.min.js
style.css
favicons/favicon.ico
favicons/icon.svg
functions/credit.js

FALLBACK:
119 changes: 119 additions & 0 deletions functions/credit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
export class Credit {

static docs = {
name: "credit",
category: "Advanced Functions",
syntax: [
"credit(principal, interest_rate, remaining_terms)",
"credit(principal, interest_rate, remaining_terms, extra_payment)",
],
description: "Simulate your credit/mortgage/loan repayment using this function.",
examples: [
"credit(150000, 2.5, 50)",
"credit(150000, 2.5, 50, 35000)"
],
seealso: []
}

static paymentCalc(principal, interest, terms) {
interest = interest / 100 / 12;
const termPaymentTotal = (principal * interest * Math.pow(1 + interest, terms)) / (Math.pow(1 + interest, terms) - 1);
const termPaymentInterest = principal * interest;
return {
termPaymentTotal,
termPaymentInterest,
termPaymentCapital: termPaymentTotal - termPaymentInterest,
terms,
total: termPaymentTotal * terms
};
}

static termCalc(newPrincipal, termPaymentTotal, interest) {
const fInterest = interest / 100 / 12;
const n = Math.log10((termPaymentTotal / fInterest) / ((termPaymentTotal / fInterest) - newPrincipal)) / Math.log10(1 + fInterest);
return Credit.paymentCalc(newPrincipal, interest, n);
}

static formatNumber(num, fractionDigits = 2) {
return num.toFixed(fractionDigits).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1 ").trim();
}

static simulate(principal, interest, terms, extraPayment) {
if (principal === undefined || interest === undefined || terms === undefined) {
throw Error("One or more arguments are missing. Syntax:\n " + Credit.docs.syntax[0] + "\n " + Credit.docs.syntax[1]);
}
if (extraPayment > principal) {
throw Error("The extra payment can't be bigger than the principal");
}

const indent = " ";
let rendered = "\n";
const baseLoan = Credit.paymentCalc(principal, interest, terms);

let data = [
["> Principal", Credit.formatNumber(principal)],
["> Interest Rate", Credit.formatNumber(interest)],
["> Remaining Terms", Credit.formatNumber(baseLoan.terms, 0)]
];

if (extraPayment) {
data.push(["> Extra Payment", Credit.formatNumber(extraPayment)]);
}

data.push(...[
[],
["Credit Simulation:"],
[indent + "Term Interest Payment", Credit.formatNumber(baseLoan.termPaymentInterest)],
[indent + "Term Capital Payment", Credit.formatNumber(baseLoan.termPaymentCapital)],
[indent + "Term Total Payment", Credit.formatNumber(baseLoan.termPaymentTotal)],
[indent + "Total", Credit.formatNumber(baseLoan.total)]
]);

rendered += Credit.renderOutput(data, 28);

if (extraPayment) {
const newLoanKeepTerms = Credit.paymentCalc(principal - extraPayment, interest, terms);
const newLoanKeepMonthly = Credit.termCalc(principal - extraPayment, baseLoan.termPaymentTotal, interest);
const extraData = [
["Extra Payment Simulation"],
[indent + "Strategy - Term Number:"],
[indent + indent + "Remaining Terms", Credit.formatNumber(newLoanKeepTerms.terms, 0)],
[indent + indent + "Term Interest Payment", Credit.formatNumber(newLoanKeepTerms.termPaymentInterest)],
[indent + indent + "Term Capital Payment", Credit.formatNumber(newLoanKeepTerms.termPaymentCapital)],
[indent + indent + "Term Total Payment", Credit.formatNumber(newLoanKeepTerms.termPaymentTotal), Credit.formatNumber((newLoanKeepTerms.termPaymentTotal - baseLoan.termPaymentTotal))],
[indent + indent + "Total", Credit.formatNumber(newLoanKeepTerms.total), Credit.formatNumber((newLoanKeepTerms.total - baseLoan.total))],
[indent + "Strategy - Term Payment:"],
[indent + indent + "Remaining Terms", Credit.formatNumber(newLoanKeepMonthly.terms, 0), Credit.formatNumber((newLoanKeepMonthly.terms - baseLoan.terms), 0)],
[indent + indent + "Term Interest Payment", Credit.formatNumber(newLoanKeepMonthly.termPaymentInterest)],
[indent + indent + "Term Capital Payment", Credit.formatNumber(newLoanKeepMonthly.termPaymentCapital)],
[indent + indent + "Term Total Payment", Credit.formatNumber(newLoanKeepMonthly.termPaymentTotal)],
[indent + indent + "Total", Credit.formatNumber(newLoanKeepMonthly.total), Credit.formatNumber((newLoanKeepMonthly.total - baseLoan.total))],
];
rendered += "\n" + Credit.renderOutput(extraData, 33);
}
rendered += "\n";
return rendered;
}

static renderOutput(lines, maxChars = 50) {
let output = "";
lines.forEach(function (line) {
if (line[0] !== undefined) {
if (line.length === 1 && line[0] === "\\-") {
output += "-------------------------------------";
} else {
output += line.length === 1 ? "<strong>" + line[0] + "</strong>" : line[0];
}
}
if (line[1] !== undefined) {
output += " ".repeat(maxChars - line[0].length) + line[1];
}
if (line[2] !== undefined) {
output += "\t " + line[2];
}
output += "\n";
});
return output;
}

}
9 changes: 4 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
<html lang="en" manifest="/cache.manifest">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="viewport-fit=cover, user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<meta name="viewport" content="viewport-fit=cover, user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<title>TBCalc</title>

<!-- This favicon order ensures modern browsers always pick the SVG -->
Expand Down Expand Up @@ -43,7 +42,7 @@
<script src="popper.min.js"></script>
<script src="bootstrap.min.js"></script>
<script src="math.min.js"></script>
<script src="main.js"></script>
<script type="module" src="main.js"></script>
</head>
<body>

Expand Down Expand Up @@ -211,8 +210,8 @@ <h1>Settings</h1>
</form>
<div class="border-top my-4 pt-2 legal">
<p>
<span>TBCalc v1.2 - www.tcb13.com</span><br>
Copyright © TCB13 (Tadeu Bento) 2022.<br>
<span>TBCalc v1.3 - www.tcb13.com</span><br>
Copyright © TCB13 (Tadeu Bento) 2022-2024.<br>
<a rel="license" target="_blank" href="https://tbcalc.tcb13.com/LICENSE.txt">Licensed under GPLv3.</a><br>
<a target="_blank" href="https://tbcalc.tcb13.com/INCLUDED_LICENSES.txt">This project uses open-source libraries.</a>
</p>
Expand Down
49 changes: 28 additions & 21 deletions main.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
TBCalc v1.2 - Console Calculator
Copyright (C) 2022 TCB13 (Tadeu Bento)
TBCalc v1.3 - Console Calculator
Copyright (C) 2022-2024 TCB13 (Tadeu Bento)
https://tbcalc.tcb13.com | https://tcb13.com | https://tadeubento.com
This program is free software: you can redistribute it and/or modify
Expand All @@ -16,6 +16,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Credit} from "./functions/credit.js";

let settings = {
open_help: true,
Expand All @@ -28,7 +29,8 @@ math.import({
tbcalc: "Welcome to TBCalc!",
TBCalc: "Welcome to TBCalc!",
clear: () => calc.reset(),
reset: () => calc.reset()
reset: () => calc.reset(),
credit: (...args) => Credit.simulate(...args)
});

window.onload = () => {
Expand Down Expand Up @@ -237,7 +239,7 @@ class TBCalc {

this.lines.push(line);

if (line.code.substr(0, 2) === " ") {
if (line.code.startsWith(" ")) {
line.indent = line.code.match(/\s+/)[0].match(/\s\s/g).length;
}

Expand Down Expand Up @@ -275,7 +277,7 @@ class TBCalc {
line.parsed = math.parse(line.code);
line.compiled = cached.parsed.compile();
} else {
line.result = line.compiled.eval(scope);
line.result = line.compiled.evaluate(scope);

}

Expand All @@ -298,6 +300,7 @@ class TBCalc {

scope.last = line.result;
}

});
}

Expand Down Expand Up @@ -383,14 +386,11 @@ class TBCalc {
return;
}

replacement = replacement.substr(0, replacement.length - 1);

let newSelectionStart = this.selectionStart + 2;
let newSelectionEnd = this.selectionEnd + affected * 2;

this.inputEl.setSelectionRange(selectionStart, selectionEnd);
this.replaceSelection(replacement);
this.inputEl.setSelectionRange(newSelectionStart, newSelectionEnd);
this.postIndent(
replacement, selectionStart, selectionEnd,
this.selectionStart + 2,
this.selectionEnd + affected * 2
);
}

removeIndent() {
Expand All @@ -404,12 +404,12 @@ class TBCalc {
if (!line.selected) {
return false;
}
if (line.code.substr(0, 2) !== " ") {
if (!line.code.startsWith(" ")) {
return;
}

affected++;
replacement += line.code.substr(2) + "\n";
replacement += line.code.slice(2) + "\n";

if (line.positionStart <= selectionStart) {
selectionStart = line.positionStart;
Expand All @@ -424,18 +424,22 @@ class TBCalc {
return;
}

replacement = replacement.substr(0, replacement.length - 1);

const newSelectionStart = this.selectionStart - 2;
const newSelectionEnd = this.selectionEnd - affected * 2;
this.postIndent(
replacement, selectionStart, selectionEnd,
this.selectionStart - 2,
this.selectionEnd - affected * 2
);
}

postIndent(replacement, selectionStart, selectionEnd, newSelectionStart, newSelectionEnd) {
replacement = replacement.slice(0, -1);
this.inputEl.setSelectionRange(selectionStart, selectionEnd);
this.replaceSelection(replacement);
this.inputEl.setSelectionRange(newSelectionStart, newSelectionEnd);
}

repaint() {
var html = "";
let html = "";
let compensatoryInputText = "";

this.lines.forEach((line, index) => {
Expand Down Expand Up @@ -492,6 +496,7 @@ class TBCalc {
} else if (parameterCnt > 1) {
data += " expects " + parameterCnt + " arguments";
}
data += ", type 'help(" + line.result.name + ")' for more";
}

if (line.selected) {
Expand All @@ -504,12 +509,14 @@ class TBCalc {
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");

const outputLineCount = (data.match(/\n/g) || []).length;

let lineHtml = "<div class=\"" + type + "\">";
lineHtml += "<span class=\"code\" data-code=\"" + code + "\"></span>";
lineHtml += "<span class=\"hint\" data-prefix=\"" + prefix + "\">" + data + "</span>";
lineHtml += "</div>";

compensatoryInputText = "\n".repeat((data.match(/\n/g) || []).length);
compensatoryInputText = "\n".repeat(outputLineCount);
html += lineHtml;
});

Expand Down
58 changes: 3 additions & 55 deletions math.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion style.css
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ body {
width: 100%;
}

p, a, a:link, a:hover, a:active, a:visited, a:focus,
p, a, a:link, a:hover, a:active, a:visited, a:focus,
.actions button, .actions button:hover, .actions button:active, .actions button:focus {
color: var(--app-text-color);
outline: 0;
Expand Down

0 comments on commit 6471a4b

Please sign in to comment.