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>

贴上最终效果图:

 

扔在起点摸索中,欢迎大佬解答疑惑。

 

 

posted @ 2018-01-05 15:56  Clown丶Fish  阅读(295)  评论(0编辑  收藏  举报