Note(2): 一个JavaScript的贷款计算器
抽时间对照着案例撸了一遍,学到了蛮多东西,也有很多疑问,其中有个疑问仍是没有撸明白
graph.width = graph.width; //所谓的巧妙用法?
好了废话不多说,贴出源码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript Loan Calcualtor</title> <style> .output { font-weight: bold } #payment { text-decoration: underline } #graph { border: solid black 1px } th, td { vertical-align: top } </style> <script> "user strict"; //如果浏览器支持的话,则开启ECMAScript 5的严格模式 // 查找文档中用于输入输出的元素 function $(id) { return document.getElementById(id); } function calculate() { //假设所有的输入都是合法的, 将从input元素中获取输入数据 //将百分比格式转换为小数格式, 并从年利率转换为月利率 //将年度赔付转换为月度赔付 var amount = $("amount"), apr = $("apr"), years = $("years"), zipcode = $("zipcode"), payments = $("payment"), total = $("total"), totalInterest = $("totalInterest"), principal = parseFloat(amount.value), interest = parseFloat(apr.value) / 100 / 12, payment = parseFloat(years.value) * 12; //现在计算月度赔付的数据 var x = Math.pow(1 + interest, payment), monthly = (principal * x * interest) / (x - 1); if (isFinite(monthly)) { //四舍五入到小数点后两位数字 payments.innerHTML = monthly.toFixed(2); total.innerHTML = (monthly * payment).toFixed(2); totalInterest.innerHTML = ((monthly * payment) - principal).toFixed(2); //将用户输入的数据保存下来,这样在下次访问的时候也能取到数据 save(amount.value, apr.value, years.value, zipcode.value); try { //捕获这段代码抛出的所有异常 getLenders(amount.value, apr.value, years.value, zipcode.value); } catch (e) {/* 忽略这些异常 */ } //最后用图标展示贷款余额、利息和资产收益 chart(principal, interest, monthly, payment); } else { payment.innerHTML = ""; total.innerHTML = ""; totalInterest.innerHTML = ""; chart(); } } function save(amount, apr, years, zipcode) { if (window.localStorage) { //只有在浏览器支持的时候才运行这里的代码 localStorage.loan_amount = amount; localStorage.loan_apr = apr; localStorage.loan_years = years; localStorage.loan_zipcode = zipcode; } } window.onload = function () { //如果浏览器支持本地存储并且上次保存的值是存在的 if (window.localStorage && localStorage.lan_amount) { document.getElementById("amount").value = localStorage.loan_amount; document.getElementById("apr").value = localStorage.loan_apr; document.getElementById("years").value = localStorage.loan_years; document.getElementById("zipcode").value = localStorage.loan_zipcode; } } function getLenders(amount, apr, years, zipcode) { if (window.XMLHttpRequest) return; var ad = document.getElementById("lenders"); if (!ad) return; var url = "getLenders.php" + "?amt=" + encodeURIComponent(amount) + "&apr=" + encodeURIComponent(apr) + "&yrs=" + encodeURIComponent(years) + "&zip=" + encodeURIComponent(zipcode); var req = new XMLHttpRequest(); req.open("GET", url); req.send(null); //不带任何正文发送这个请求 req.onreadystatechange = function () { if (req.readyState == 4 && req.status == 200) { var respones = req.responseText; var lenders = JSON.pares(response); //将其解析为js数组 var list = ""; for (var i = 0; i < lenders.length; i++) { list += "<li><a href=' " + lenders[i].url + " '>" + lenders[i].name + "</a>"; } ad.innerHTML = "<ul>" + list + "</ul>" } } } function chart(principal, interest, monthly, payment) { var graph = document.getElementById("graph"); //如果不传入参数,或者浏览器不支持画布,则直接返回 if (arguments.length == 0 || !graph.getContext) return; //graph.width = graph.width; //所谓的巧妙用法? //获得画布元素的"context"对象,这个对象定义了一组绘画API var g = graph.getContext("2d"); var width = graph.width, height = graph.height; //将付款数字和美元数据转换为像素 function paymentToX(n) { return n * width / payment; } function amountToY(a) { return height - (a * height / (monthly * payment * 1.05)); } //画线 // 付款数据是一条从(0,0)到() g.moveTo(paymentToX(0), amountToY(0)); //起点 g.lineTo(paymentToX(payment), amountToY(monthly * payment)); g.lineTo(paymentToX(payment), amountToY(0)); g.closePath(); g.fillStyle = "#f88"; //亮红色 g.fill(); g.font = "bold 12px sans-serif"; //自定义一种字体 g.fillText("Total Interest Payments", 20, 20); //将文字绘制到图例中 //很多资产数据并不是线性的,很难将其反映至图表中 var equity = 0; g.beginPath(); g.moveTo(paymentToX(0), amountToY(0)); for (var p = 1; p <= payment; p++) { //计算出每一笔赔付的利息 var thisMonthsInterest = (principal - equity) * interest; equity += (monthly - thisMonthsInterest); g.lineTo(paymentToX(p), amountToY(equity)); } g.lineTo(paymentToX(payment), amountToY(0)); g.closePath(); g.fillStyle = "green"; g.fill(); g.fillText("Total Equity", 20, 35); //再次循环, 余额数据显示未黑色粗线条 var bal = principal; g.beginPath(); g.moveTo(paymentToX(0), amountToY(bal)); for (var p = 1; p <= payment; p++) { var thisMonthsInterest = bal * interest; bal -= (monthly - thisMonthsInterest); g.lineTo(paymentToX(p), amountToY(bal)); } g.lineWidth = 3; g.stroke(); g.fillStyle = "black"; g.fillText("Loan Balance", 20, 50); //将年度数据在X轴做标记 g.textAlign = "center"; var y = amountToY(0); for (var year = 1; year * 12 <= payment; year++) { var x = paymentToX(year * 12); g.fillRect(x - 0.5, y - 3, 1, 3); //开始绘制标记 if (year == 1) g.fillText("Year", x, y - 5); if (year % 5 == 0 && year * 12 !== payment) { g.fillText(String(year), x, y - 5); } } //将赔付数额标记在右边界 g.textAlign = "right"; g.textBaseline = "middle"; //文字垂直居中 var ticks = [monthly * payment, principal]; var rightEdge = paymentToX(payment); for (var i = 0; i < ticks.length; i++) { var y = amountToY(ticks[i]); g.fillRect(rightEdge - 3, y - 0.5, 3, 1); g.fillText(String(ticks[i].toFixed(0)), rightEdge - 5, y); } } </script> </head> <body> <table> <tr> <th>Enter Loan Data:</th> <td></td> <th>Loan Balance, Cumulative Equity, and Interest Payments</th> </tr> <tr> <td>Amount of the loan ($):</td> <td><input id="amount" onchange="calculate()"></td> <td rowspan=8> <canvas id="graph" width="400" height="250"></canvas> </td> </tr> <tr> <td>Annual interest (%):</td> <td><input id="apr" onchange="calculate()"></td> </tr> <tr> <td>Repayment period (years):</td> <td><input id="years" onchanges="calculate"></td> </tr> <tr> <td>Zipcode (to find lenders):</td> <td><input id="zipcode" onchange="calculate()"></td> </tr> <tr> <th>Approximate Payments:</th> <td> <button onclick="calculate()">Calculate</button> </td> </tr> <tr> <td>Monthly payment:</td> <td>$<span class="output" id="payment"></span></td> </tr> <tr> <td>Total payment:</td> <td>$<span class="output" id="total"></span></td> </tr> <tr> <td>Total interest:</td> <td>$<span class="output" id="totalInterest"></span></td> </tr> <tr> <th>Sponsors:</th> <td colspan=2>Apply for your loan with one of these fine lenders: <div id="lenders"></div> </td> </tr> </table> </body> </html>
贴上最终效果图:
扔在起点摸索中,欢迎大佬解答疑惑。