以下是我找着书打出来的,没有检查,里面包含了我的一些问题,等会我会把解答也写出来
问题会在那里加上5个#号
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript Loan Calculator</title>
<style>
.output {
font-weight:bold;
}
#payment {
text-decoration:underline;
}
#graph {
border: solid black 1px;
}
th, td {
vertical-align:top;
}
</style>
</head>
<body>
<!--
这是一个HTML表格,其中包含了<input>元素可以用来输入数据
程序将在<span>元素中显示计算结果,这些元素都具有类似"interest"和"years"的id
这些id将在表格下面的javascript代码中用到。我们注意到,有一些
input元素定义了"onchange"或"onclick"事件的处理程序,以便用户在输入数据或者点击inputs时
执行指定的javascript代码段
-->
<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(yeaers):</td>
<td><input id="years" onChange="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>
<!--######问题二:像这样的id声明在它的CSS中有没有对这个id的代码,要来有什么用? -->
</tr>
</table>
<!--
随后是javascript代码,这些代码内嵌到一个<script>标签里
通常情况下,这些脚本代码应该放在<head>标签中
将javascript代码放在HTML代码之后仅仅是为了方便理解
-->
<script>
"user strict"
/*
这里的脚本定义了caculate()函数,在HTML代码中绑定事件处理程序时会调用它
这个函数从<input>元素中读取数据,计算贷款赔付信息,并将结果显示在<span>元素中
同样,这里还保存了用户数据,展示了放贷人链接并绘制出了图表
*/
function calculate() {
//查找文档中用于输入输出的元素
var amount = document.getElementById("amount");
var apr = document.getElementById("apr");
var years = document.getElementById("years");
var zipcode = document.getElementById("zipcode");
var payment = document.getElementById("payment");
var total = document.getElementById("total");
var totalinterest = document.getElementById("totalinterest");
//假设所有的输入都是合法的,将从input元素中获取输入的数据
//将百分比格式转换为小数格式,并从年利率转换为月利率
//将年度赔付转化为月度赔付
var principal = parseFloat(amout.value);
var interest = parseFloat(apr.value) / 100 / 12;
var payments = parseFloat(years.value) * 12;
//现在计算月度赔付的数据
var x = Math.pow(i + interest, paymnets);//进行幂次运算
var monthly = (principal * x * interest) / (x - 1);
//如果结果没有超过javascript能表示的数字范围,且用户的输入也正确
//这里所展示的结果就是合法的
if(isFinite(monthly)) {
//将数据填充至输出字段的位置,四舍五入到小数点后两位数字
payment.innerHTML = monthly.toFixed(2);
total.innerHTML = (monthly * payments).toFixed(2);
totalinterest.innerHTML = ((monthly * payments) - 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, payments);
}
else {
//计算结果是不是数字或是无穷大,意味着输入数据是非法还是不完整
//清空之前输入的数据
payment.innerHTML = "";
total.innerHTML = "";
totalinterest.innerHTML = "";
chart();
}
}
/*
将用户的输入保存在localStorage对象的属性中
将这些属性在再次访问的时候还会继续保持在原位置
如果你在浏览器中按照file://URL的方式直接打开本地文件
则无法在某些浏览器中使用储存功能(FireFox)
而通过HTTP打开文件是可行呢
*/
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.loan_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) {
//如果浏览器不支持XMLHttpRequest对象,则退出
if(!window.XMLHttpRequest) {
return;
}
//找到要显示的放贷人的列表
var ad = document.getElementById("lenders");
if(!ad) { //如果返回为空,则退出
return;
}
//将用户的输入数据进行URL编码,并作为查询参数附加在URL里
var url = "getLenders.php" + //使用查询串中的数据
"?amt=" + encodeURLComponent(amount) +
//######问题三:这个amt前面的是问号,而其他的都是&号。。这是为什么呢?
"&apr=" + encodeURLComponent(apr) +
"&yrs=" + encodeURLComponent(years) +
"&zip=" + encodeURLComponent(zipcode);
//通过XMLHttpRequest对象来提取返回数据
var req = new XMLHttpRequest(); //发起一个新的请求
req.open("GET", url); //通过URL发起一个HTTP GET请求
req.send(null); //不带任何正文发送这个请求
//在返回数据之前,注册一个事件处理函数,这个处理函数
//将会在服务器的响应返回至客户端的时候调用
//这种异步编程模型在客户端javascript中是很常见的
req.onreadystatechange = function() {
if(req.readyState == 4 && req.status == 200) {
//######问题四:4和200这两个数字是怎么得来的
//如果代码执行到这里,说明我们得到一个合法且完整的HTTP响应
var response = req.responseText; //响应是以字符串的形式呈现的
var lenders = JSON.parse(response); //将其解析为JS数组
//将数组中的放贷人对象转换成HTML字符床的形式
var list = "";
for(var i = 0; i < lenders.length; i++) {
list += "<li><a href='" + lendgers[i].url + "'>" +
lenders[i].name + "</a>";
}
//将数据在HTML元素中呈现出来
ad.innerHTML = "<ul>" + list + "</ul>";
}
}
}
//在HTML<canvas>元素中用图表展示月度贷款余额、利息和资产收益
//如果不传入参数的话,则清空之前的图表数据
function chart(principal, interest, monthly, payments) {
var graph = document.getElementById("graph");
graph.width = graph.width; //用一种巧妙的方法清除并重置画布
//#####问题五:那个~这样真的可以吗,直接把自己的值赋给自己,感觉结果还是自己哇
//如果不传入参数,或者浏览器不支持画布,则直接返回
if(arguments.length == 0 || !graph.getContext) {
return;
}
//获得画布元素的"context"对象,这个对象定义了一组会话API
var g = graph.getContext("2d");
var width = graph.width, //获得画布的大小
height = graph.height;
//这里的函数的作用是讲付款数字和美元数据转换为像素
function paymentToX(n) {
return n * width/payments;
}
function amountToY(a) {
return height - (a * height / (monthly * payments * 1.05));
}
//#####问题五:我看不明白为什么这样写
//付款数据是一条从(0,0)到(payments, monthly*payments)的直线
g.moveTo(paymentToX(0), amountToY(0)); //从左下方开始
g.lineTo(paymentTox(payments), amountToY(monthly * payments)); //绘制到右上方
g.lineTo(paymentTox(payments), 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.begiPath(); //开始绘制新图形
g.moveTo(paymentToX(0), amountToY(0)); //还是从左下方开始
for(var p = 1; p <= payments; p++) {
//计算出每一笔赔付的利息
var thisMonthsInterest = (principal - equity) * interest;
equity += (monthly - thisMonthsInterest); //得到资产额
g.lineTo(paymentToX(p), amountToY(equity)); //将数据绘制到画布上
}
g.lineTo(paymentToX(payments), amountToY(0)); //将数据线绘制到X轴
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 <= payments; p++) {
var thisMonthsInterest = bal * interest;
bal -= (monthly - thisMonthsInterest); //得到资产值
g.lineTo(paymentToX(p), amountToY(bal)); //将直线连接到某个点
//问题七:这个lineTo又是什么时候定义的?
}
g.lineWidth = 3; //将直线的宽度加粗
g.stroke(); //绘制余额的曲线
g.fillStyle = "black"; //使用黑色字体
g.fillText("Loan Balance", 20, 50); //图例文字
//将年度数据在C轴做标记
g.textAlign = "center"; //将文字居中对齐
var y = amountToY(0); //Y嘴表设为0
for(var year = 1; year * 12 <= payments; year++) { //遍历每年
var x = paymentToX(year * 12); //计算标记位置
g.fillRect(x - 0.5, y - 3, 1, 3) //开始绘制标记
//问题八:又是没有声明这个fillRect就用了
if(year == 1) { //在坐标轴做标记
g.fillText("Year", x, y - 5);
}
if(year % 5 == 0 && year * 12 != payments) {//每5年的数据
g.fillText(String(year), x, y - 5);
}
}
//将赔付数额标记在有边界
g.textAlign = "right"; //文字右对齐
g.textBaseline = "middle"; //文字垂直居中
//问题九:这个texBaseline是什么,CSS中的吗?
var ticks = [monthly * payments, principal]; //我们将要用刀的两个点
var rightEdge = paymentToX(payments); //设置X坐标
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>
</body>
</html>
解答:
- 问:canvas高度宽度为什么能能够不带单位 答:W3CSchool的链接附上点击打开链接,它默认的单位就是像素(PX),当然你也可以加上px,显示效果一样
- 问:HTML中的有些元素的id声明在它的CSS中有没有对这个id的代码,要来有什么用 答:不一定要所有的id都是用在CSS中的哦,像javascript也是可以使用的,这个例子中的calculate()方法中的var amount = document.getElementById("amount");就用到了它的id来获取数据
- 问:这个amt前面的是问号,而其他的都是&号。。这是为什么呢 答:那个问号是用来说明:哎~url,我后面的都是参数哈,你别弄错了(实际上那部分代码并没有执行)
- 问:直接把自己的值赋给自己,感觉结果还是他自己 答:嗯,你说的没有错,还是他自己,width的值有没有变。。。再问:那你为什么说能够清除画布呢? 再答:重新赋值就可以叫做重置了,这个是一个前辈告诉我的,虽然我也不知道他在说什么
- 至于那个把付款数字和美元转换成像素的东西,嗯~也许是一个公式吧,不要在意这些细节
- 连接至开都其实就是将当前点和子路径起始点连接起来,以达到封闭图形的效果点击打开链接,对了这个方法是早就有了的
- 还有问题七。。。lineTo其实也造就有了的。点击打开链接
- 问题八也是一样的fillRect也是早就有了的方法,用来填充一个矩形点击打开链接
- 至于==!它的意思实际上是不恒等(或者说严格不相等),==, 两边值类型不同的时候,要先进行类型转换,再比较。
==,不做类型转换,类型不同的一定不等(摘自点击打开链接)
以下是最终修改运行成功的网页
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript Loan Calculator</title>
<style>
.output {
font-weight:bold;
}
#payment {
text-decoration:underline;
}
#graph {
border: solid black 1px;
}
th, td {
vertical-align:top;
}
</style>
</head>
<body>
<!--
这是一个HTML表格,其中包含了<input>元素可以用来输入数据
程序将在<span>元素中显示计算结果,这些元素都具有类似"interest"和"years"的id
这些id将在表格下面的javascript代码中用到。我们注意到,有一些
input元素定义了"onchange"或"onclick"事件的处理程序,以便用户在输入数据或者点击inputs时
执行指定的javascript代码段
-->
<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="400px" height="250px"></canvas>
<!--######问题一:这个高度宽度为什么能能够不带单位 -->
</td>
</tr>
<tr>
<td>Annual interest(%)</td>
<td><input id="apr" onChange="calculate();"></td>
</tr>
<tr>
<td>Repayment period(yeaers):</td>
<td><input id="years" onChange="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>
<!--######问题二:像这样的id声明在它的CSS中有没有对这个id的代码,要来有什么用? -->
</tr>
</table>
<!--
随后是javascript代码,这些代码内嵌到一个<script>标签里
通常情况下,这些脚本代码应该放在<head>标签中
将javascript代码放在HTML代码之后仅仅是为了方便理解
-->
<script>
"user strict"
/*
这里的脚本定义了caculate()函数,在HTML代码中绑定事件处理程序时会调用它
这个函数从<input>元素中读取数据,计算贷款赔付信息,并将结果显示在<span>元素中
同样,这里还保存了用户数据,展示了放贷人链接并绘制出了图表
*/
function calculate() {
//查找文档中用于输入输出的元素
var amount = document.getElementById("amount");
var apr = document.getElementById("apr");
var years = document.getElementById("years");
var zipcode = document.getElementById("zipcode");
var payment = document.getElementById("payment");
var total = document.getElementById("total");
var totalinterest = document.getElementById("totalinterest");
//假设所有的输入都是合法的,将从input元素中获取输入的数据
//将百分比格式转换为小数格式,并从年利率转换为月利率
//将年度赔付转化为月度赔付
var principal = parseFloat(amount.value);
var interest = parseFloat(apr.value) / 100 / 12;
var payments = parseFloat(years.value) * 12;
//现在计算月度赔付的数据
var x = Math.pow(1 + interest, payments);//进行幂次运算
var monthly = (principal * x * interest) / (x - 1);
//如果结果没有超过javascript能表示的数字范围,且用户的输入也正确
//这里所展示的结果就是合法的
if(isFinite(monthly)) {
//将数据填充至输出字段的位置,四舍五入到小数点后两位数字
payment.innerHTML = monthly.toFixed(2);
total.innerHTML = (monthly * payments).toFixed(2);
totalinterest.innerHTML = ((monthly * payments) - 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, payments);
}
else {
//计算结果是不是数字或是无穷大,意味着输入数据是非法还是不完整
//清空之前输入的数据
payment.innerHTML = "";
total.innerHTML = "";
totalinterest.innerHTML = "";
chart();
}
}
/*
将用户的输入保存在localStorage对象的属性中
将这些属性在再次访问的时候还会继续保持在原位置
如果你在浏览器中按照file://URL的方式直接打开本地文件
则无法在某些浏览器中使用储存功能(FireFox)
而通过HTTP打开文件是可行呢
*/
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.loan_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) {
//如果浏览器不支持XMLHttpRequest对象,则退出
if(!window.XMLHttpRequest) {
return;
}
//找到要显示的放贷人的列表
var ad = document.getElementById("lenders");
if(!ad) { //如果返回为空,则退出
return;
}
//将用户的输入数据进行URL编码,并作为查询参数附加在URL里
var url = "getLenders.php" + //使用查询串中的数据
"?amt=" + encodeURLComponent(amount) +
//######问题三:这个amt前面的是问号,而其他的都是&号。。这是为什么呢?
"&apr=" + encodeURLComponent(apr) +
"&yrs=" + encodeURLComponent(years) +
"&zip=" + encodeURLComponent(zipcode);
//通过XMLHttpRequest对象来提取返回数据
var req = new XMLHttpRequest(); //发起一个新的请求
req.open("GET", url); //通过URL发起一个HTTP GET请求
req.send(null); //不带任何正文发送这个请求
//在返回数据之前,注册一个事件处理函数,这个处理函数
//将会在服务器的响应返回至客户端的时候调用
//这种异步编程模型在客户端javascript中是很常见的
req.onreadystatechange = function() {
if(req.readyState == 4 && req.status == 200) {
//######问题四:4和200这两个数字是怎么得来的
//如果代码执行到这里,说明我们得到一个合法且完整的HTTP响应
var response = req.responseText; //响应是以字符串的形式呈现的
var lenders = JSON.parse(response); //将其解析为JS数组
//将数组中的放贷人对象转换成HTML字符床的形式
var list = "";
for(var i = 0; i < lenders.length; i++) {
list += "<li><a href='" + lendgers[i].url + "'>" +
lenders[i].name + "</a>";
}
//将数据在HTML元素中呈现出来
ad.innerHTML = "<ul>" + list + "</ul>";
}
}
}
//在HTML<canvas>元素中用图表展示月度贷款余额、利息和资产收益
//如果不传入参数的话,则清空之前的图表数据
function chart(principal, interest, monthly, payments) {
var graph = document.getElementById("graph");
graph.width = graph.width; //用一种巧妙的方法清除并重置画布
//#####问题五:那个~这样真的可以吗,直接把自己的值赋给自己,感觉结果还是自己哇
//如果不传入参数,或者浏览器不支持画布,则直接返回
if(arguments.length == 0 || !graph.getContext) {
return;
}
//获得画布元素的"context"对象,这个对象定义了一组会话API
var g = graph.getContext("2d");
var width = graph.width, //获得画布的大小
height = graph.height;
//这里的函数的作用是讲付款数字和美元数据转换为像素
function paymentToX(n) {
return n * width/payments;
}
function amountToY(a) {
return height - (a * height / (monthly * payments * 1.05));
}
//#####问题五:我看不明白为什么这样写
//付款数据是一条从(0,0)到(payments, monthly*payments)的直线
g.moveTo(paymentToX(0), amountToY(0)); //从左下方开始
g.lineTo(paymentToX(payments), amountToY(monthly * payments)); //绘制到右上方
g.lineTo(paymentToX(payments), 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 <= payments; p++) {
//计算出每一笔赔付的利息
var thisMonthsInterest = (principal - equity) * interest;
equity += (monthly - thisMonthsInterest); //得到资产额
g.lineTo(paymentToX(p), amountToY(equity)); //将数据绘制到画布上
}
g.lineTo(paymentToX(payments), amountToY(0)); //将数据线绘制到X轴
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 <= payments; p++) {
var thisMonthsInterest = bal * interest;
bal -= (monthly - thisMonthsInterest); //得到资产值
g.lineTo(paymentToX(p), amountToY(bal)); //将直线连接到某个点
//问题七:这个lineTo又是什么时候定义的?
}
g.lineWidth = 3; //将直线的宽度加粗
g.stroke(); //绘制余额的曲线
g.fillStyle = "black"; //使用黑色字体
g.fillText("Loan Balance", 20, 50); //图例文字
//将年度数据在C轴做标记
g.textAlign = "center"; //将文字居中对齐
var y = amountToY(0); //Y嘴表设为0
for(var year = 1; year * 12 <= payments; year++) { //遍历每年
var x = paymentToX(year * 12); //计算标记位置
g.fillRect(x - 0.5, y - 3, 1, 3); //开始绘制标记
//问题八:又是没有声明这个fillRect就用了
if(year == 1) { //在坐标轴做标记
g.fillText("Year", x, y - 5);
}
if(year % 5 == 0 && year * 12 !== payments) {//每5年的数据
g.fillText(String(year), x, y - 5);
}
}
//将赔付数额标记在有边界
g.textAlign = "right"; //文字右对齐
g.textBaseline = "middle"; //文字垂直居中
//问题九:这个texBaseline是什么,CSS中的吗?
var ticks = [monthly * payments, principal]; //我们将要用刀的两个点
var rightEdge = paymentToX(payments); //设置X坐标
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>
</body>
</html>