我的 JavaScript 无法正常工作或未连接

My JavaScript is Not working Correctly or is not connecting

我正在尝试制作一个带有直方图的 Intrest 计算器 我在网上找到了这些脚本,因为我是 javaScript 的新手。 所以我想要的输出是这样的Desired Outpyt 我得到的输出是 comming output 所以我真的需要一些帮助 第一,带有 + 和 - 符号的蓝色按钮太疯狂了。 其次,直方图没有显示。

所以请帮助我,我将不胜感激。

我已从该站点复制粘贴代码

https://codingdiksha.com/build-a-compound-interest-calculator-using-chart-js-in-html5-css3-and-javascript/

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.3/css/bootstrap.css" >
<meta charset="UTF-8">
<title>Savings Calculator</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="initial_deposit">Initial Deposit</label>
<div class="row">
<div class="input-group col-md-6 col-sm-8">
<div class="input-group-prepend">
<button class="btn btn-primary" type="button" data-counter="sub" data-field="initial_deposit">−</button>
</div>
<input class="form-control text-center" id="initial_deposit" type="text" name="initial_deposit" min="100" max="1000000" step="100" value="00" data-value="5000" data-prepend="$">
<div class="input-group-append">
<button class="btn btn-primary" type="button" data-counter="add" data-field="initial_deposit">+</button>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="contribution_amount">Contributions</label>
<div class="row">
<div class="input-group col-md-6 col-sm-8">
<div class="input-group-prepend">
<button class="btn btn-primary" type="button" data-counter="sub" data-field="contribution_amount">−</button>
</div>
<input class="form-control text-center" id="contribution_amount" type="text" name="contribution_amount" min="0" max="10000" step="50" value="0" data-value="100" data-prepend="$">
<div class="input-group-append">
<button class="btn btn-primary" type="button" data-counter="add" data-field="contribution_amount">+</button>
</div>
</div>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" id="contribution_period_monthly" type="radio" name="contribution_period" value="12" checked>
<label class="form-check-label" for="contribution_period_monthly">monthly</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" id="contribution_period_annually" type="radio" name="contribution_period" value="1">
<label class="form-check-label" for="contribution_period_annually">annually</label>
</div>
</div>
<div class="form-group">
<label for="investment_timespan">Investment Time Span</label>
<div class="row">
<div class="col-md-6 col-sm-8">
<input class="form-control" id="investment_timespan" type="range" name="investment_timespan" min="2" max="50" step="1" value="5">
</div>
</div>
<span id="investment_timespan_text">5 years</span>
</div>
<div class="form-group">
<label for="estimated_return">Estimated Rate of Return</label>
<div class="row">
<div class="input-group col-md-6 col-sm-8">
<div class="input-group-prepend">
<button class="btn btn-primary" type="button" data-counter="sub" data-field="estimated_return">−</button>
</div>
<input class="form-control text-center" id="estimated_return" type="text" name="estimated_return" min="0" max="50" step="0.25" value="5.00%" data-value="5.00" data-append="%">
<div class="input-group-append">
<button class="btn btn-primary" type="button" data-counter="add" data-field="estimated_return">+</button>
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-sm-12">
<div>Compound Frequency</div>
<div class="form-check form-check-inline">
<input class="form-check-input" id="compound_period_daily" type="radio" name="compound_period" value="365">
<label class="form-check-label" for="compound_period_daily">daily</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" id="compound_period_monthly" type="radio" name="compound_period" value="12" checked>
<label class="form-check-label" for="compound_period_monthly">monthly</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" id="compound_period_annually" type="radio" name="compound_period" value="1">
<label class="form-check-label" for="compound_period_annually">annually</label>
</div>
</div>
</div>
</div>
<div class="col-md-6 text-center">
<div>Future Balance</div>
<div class="h3" id="future_balance">?</div>
<canvas id="myChart"></canvas>
</div>
</div>
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.3/css/bootstrap.css"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.js">    </script>
</html>

Script.js

(function () {
var initial_deposit = document.querySelector('#initial_deposit'),
contribution_amount = document.querySelector('#contribution_amount'),
investment_timespan = document.querySelector('#investment_timespan'),
investment_timespan_text = document.querySelector('#investment_timespan_text'),
estimated_return = document.querySelector('#estimated_return'),
future_balance = document.querySelector('#future_balance');
function updateValue(element, action) {
var min = parseFloat(element.getAttribute('min')),
max = parseFloat(element.getAttribute('max')),
step = parseFloat(element.getAttribute('step')) || 1,
oldValue = element.dataset.value || element.defaultValue || 0,
newValue = parseFloat(element.value.replace(/$/, ''));
if (isNaN(parseFloat(newValue))) {
newValue = oldValue;
} else {
if (action == 'add') {
newValue += step;
} else if (action == 'sub') {
newValue -= step;
}       
newValue = newValue < min ? min : newValue > max ? max : newValue;
}
element.dataset.value = newValue;
element.value = (element.dataset.prepend || '') + newValue + (element.dataset.append || '');
updateChart();
}
function getChartData() {
var P = parseFloat(initial_deposit.dataset.value), // Principal
r = parseFloat(estimated_return.dataset.value / 100), // Annual Interest Rate
c = parseFloat(contribution_amount.dataset.value), // Contribution Amount
n = parseInt(document.querySelector('[name="compound_period"]:checked').value), // Compound Period
n2 = parseInt(document.querySelector('[name="contribution_period"]:checked').value), // Contribution Period
t = parseInt(investment_timespan.value), // Investment Time Span
currentYear = (new Date()).getFullYear()
;
var labels = [];
for (var year = currentYear; year < currentYear + t; year++) {
labels.push(year);
}
var principal_dataset = {
label: 'Total Principal',
backgroundColor: 'rgb(0, 123, 255)',
data: []
};
var interest_dataset = {
label: "Total Interest",
backgroundColor: 'rgb(23, 162, 184)',
data: []
};
for (var i = 1; i <= t; i++) {
var principal = P + ( c * n2 * i ),
interest = 0,
balance = principal;
if (r) {
var x = Math.pow(1 + r / n, n * i),
compound_interest = P * x,
contribution_interest = c * (x - 1) / (r / n2);
interest = (compound_interest + contribution_interest - principal).toFixed(0)
balance = (compound_interest + contribution_interest).toFixed(0);
}
future_balance.innerHTML = '$' + balance;
principal_dataset.data.push(principal);
interest_dataset.data.push(interest);
}
return {
labels: labels,
datasets: [principal_dataset, interest_dataset]
}
}
function updateChart() {
var data = getChartData();
chart.data.labels = data.labels;
chart.data.datasets[0].data = data.datasets[0].data;
chart.data.datasets[1].data = data.datasets[1].data;
chart.update();
}
initial_deposit.addEventListener('change', function () {
updateValue(this);
});
contribution_amount.addEventListener('change', function () {
updateValue(this);
});
estimated_return.addEventListener('change', function () {
updateValue(this);
});
investment_timespan.addEventListener('change', function () {
investment_timespan_text.innerHTML = this.value + ' years';
updateChart();
});
investment_timespan.addEventListener('input', function () {
investment_timespan_text.innerHTML = this.value + ' years';
});
var radios = document.querySelectorAll('[name="contribution_period"], [name="compound_period"]');
for (var j = 0; j < radios.length; j++) {
radios[j].addEventListener('change', updateChart);
}
var buttons = document.querySelectorAll('[data-counter]');
for (var i = 0; i < buttons.length; i++) {
var button = buttons[i];
button.addEventListener('click', function () {
var field = document.querySelector('[name="' + this.dataset.field + '"]'),
action = this.dataset.counter;
if (field) {
updateValue(field, action);
}
});
}
var ctx = document.getElementById('myChart').getContext('2d'),
chart = new Chart(ctx, {
type: 'bar',
data: getChartData(),
options: {
legend: {
display: false
},
tooltips: {
mode: 'index',
intersect: false,
callbacks: {
label: function (tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].label + ': $' + tooltipItem.yLabel;
}
}
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
scaleLabel: {
display: true,
labelString: 'Year'
}
}],
yAxes: [{
stacked: true,
ticks: {
callback: function (value) {
return '$' + value;
}
},
scaleLabel: {
display: true,
labelString: 'Balance'
}
}]
}
}
});
})();

你需要做四件事


  1. 添加bootstrap.min.css

  1. 替换

    future_balance.innerHTML = ' + balance;

    future_balance.innerHTML = '' + balance;

    第 74 行


  1. 替换

    return data.datasets[tooltipItem.datasetIndex].label + ': + tooltipItem.yLabel;

    return data.datasets[tooltipItem.datasetIndex].label + ':' + tooltipItem.yLabel;

    第 148 行


  1. 替换

    return ' + value;

    return '' + value;

    第 166 行

(function() {
  var initial_deposit = document.querySelector('#initial_deposit'),
    contribution_amount = document.querySelector('#contribution_amount'),
    investment_timespan = document.querySelector('#investment_timespan'),
    investment_timespan_text = document.querySelector('#investment_timespan_text'),
    estimated_return = document.querySelector('#estimated_return'),
    future_balance = document.querySelector('#future_balance');

  function updateValue(element, action) {
    var min = parseFloat(element.getAttribute('min')),
      max = parseFloat(element.getAttribute('max')),
      step = parseFloat(element.getAttribute('step')) || 1,
      oldValue = element.dataset.value || element.defaultValue || 0,
      newValue = parseFloat(element.value.replace(/$/, ''));

    if (isNaN(parseFloat(newValue))) {
      newValue = oldValue;
    } else {
      if (action == 'add') {
        newValue += step;
      } else if (action == 'sub') {
        newValue -= step;
      }

      newValue = newValue < min ? min : newValue > max ? max : newValue;
    }

    element.dataset.value = newValue;
    element.value = (element.dataset.prepend || '') + newValue + (element.dataset.append || '');

    updateChart();
  }

  function getChartData() {
    var P = parseFloat(initial_deposit.dataset.value), // Principal
      r = parseFloat(estimated_return.dataset.value / 100), // Annual Interest Rate
      c = parseFloat(contribution_amount.dataset.value), // Contribution Amount
      n = parseInt(document.querySelector('[name="compound_period"]:checked').value), // Compound Period
      n2 = parseInt(document.querySelector('[name="contribution_period"]:checked').value), // Contribution Period
      t = parseInt(investment_timespan.value), // Investment Time Span
      currentYear = (new Date()).getFullYear();

    var labels = [];
    for (var year = currentYear; year < currentYear + t; year++) {
      labels.push(year);
    }

    var principal_dataset = {
      label: 'Total Principal',
      backgroundColor: 'rgb(0, 123, 255)',
      data: []
    };

    var interest_dataset = {
      label: "Total Interest",
      backgroundColor: 'rgb(23, 162, 184)',
      data: []
    };

    for (var i = 1; i <= t; i++) {
      var principal = P + (c * n2 * i),
        interest = 0,
        balance = principal;

      if (r) {
        var x = Math.pow(1 + r / n, n * i),
          compound_interest = P * x,
          contribution_interest = c * (x - 1) / (r / n2);
        interest = (compound_interest + contribution_interest - principal).toFixed(0)
        balance = (compound_interest + contribution_interest).toFixed(0);
      }

      future_balance.innerHTML = '' + balance;
      principal_dataset.data.push(principal);
      interest_dataset.data.push(interest);
    }

    return {
      labels: labels,
      datasets: [principal_dataset, interest_dataset]
    }
  }

  function updateChart() {
    var data = getChartData();

    chart.data.labels = data.labels;
    chart.data.datasets[0].data = data.datasets[0].data;
    chart.data.datasets[1].data = data.datasets[1].data;
    chart.update();
  }

  initial_deposit.addEventListener('change', function() {
    updateValue(this);
  });

  contribution_amount.addEventListener('change', function() {
    updateValue(this);
  });

  estimated_return.addEventListener('change', function() {
    updateValue(this);
  });

  investment_timespan.addEventListener('change', function() {
    investment_timespan_text.innerHTML = this.value + ' years';
    updateChart();
  });

  investment_timespan.addEventListener('input', function() {
    investment_timespan_text.innerHTML = this.value + ' years';
  });

  var radios = document.querySelectorAll('[name="contribution_period"], [name="compound_period"]');
  for (var j = 0; j < radios.length; j++) {
    radios[j].addEventListener('change', updateChart);
  }

  var buttons = document.querySelectorAll('[data-counter]');
  for (var i = 0; i < buttons.length; i++) {
    var button = buttons[i];

    button.addEventListener('click', function() {
      var field = document.querySelector('[name="' + this.dataset.field + '"]'),
        action = this.dataset.counter;

      if (field) {
        updateValue(field, action);
      }
    });
  }

  var ctx = document.getElementById('myChart').getContext('2d'),
    chart = new Chart(ctx, {
      type: 'bar',
      data: getChartData(),
      options: {
        legend: {
          display: false
        },
        tooltips: {
          mode: 'index',
          intersect: false,
          callbacks: {
            label: function(tooltipItem, data) {
              return data.datasets[tooltipItem.datasetIndex].label + ':' + tooltipItem.yLabel;
            }
          }
        },
        responsive: true,
        scales: {
          xAxes: [{
            stacked: true,
            scaleLabel: {
              display: true,
              labelString: 'Year'
            }
          }],
          yAxes: [{
            stacked: true,
            ticks: {
              callback: function(value) {
                return '' + value;
              }
            },
            scaleLabel: {
              display: true,
              labelString: 'Balance'
            }
          }]
        }
      }
    });

})();
body {
  margin-top: 60px;
}
<div class="container">
  <div class="row">
    <div class="col-md-6">
      <div class="form-group">
        <label for="initial_deposit">Initial Deposit</label>
        <div class="row">
          <div class="input-group col-md-6 col-sm-8">
            <div class="input-group-prepend">
              <button class="btn btn-primary" type="button" data-counter="sub" data-field="initial_deposit">−</button>
            </div>
            <input class="form-control text-center" id="initial_deposit" type="text" name="initial_deposit" min="100" max="1000000" step="100" value="00" data-value="5000" data-prepend="$">
            <div class="input-group-append">
              <button class="btn btn-primary" type="button" data-counter="add" data-field="initial_deposit">+</button>
            </div>
          </div>
        </div>
      </div>

      <div class="form-group">
        <label for="contribution_amount">Contributions</label>
        <div class="row">
          <div class="input-group col-md-6 col-sm-8">
            <div class="input-group-prepend">
              <button class="btn btn-primary" type="button" data-counter="sub" data-field="contribution_amount">−</button>
            </div>
            <input class="form-control text-center" id="contribution_amount" type="text" name="contribution_amount" min="0" max="10000" step="50" value="0" data-value="100" data-prepend="$">
            <div class="input-group-append">
              <button class="btn btn-primary" type="button" data-counter="add" data-field="contribution_amount">+</button>
            </div>
          </div>
        </div>

        <div class="form-check form-check-inline">
          <input class="form-check-input" id="contribution_period_monthly" type="radio" name="contribution_period" value="12" checked>
          <label class="form-check-label" for="contribution_period_monthly">monthly</label>
        </div>

        <div class="form-check form-check-inline">
          <input class="form-check-input" id="contribution_period_annually" type="radio" name="contribution_period" value="1">
          <label class="form-check-label" for="contribution_period_annually">annually</label>
        </div>
      </div>

      <div class="form-group">
        <label for="investment_timespan">Investment Time Span</label>
        <div class="row">
          <div class="col-md-6 col-sm-8">
            <input class="form-control" id="investment_timespan" type="range" name="investment_timespan" min="2" max="50" step="1" value="5">
          </div>
        </div>
        <span id="investment_timespan_text">5 years</span>
      </div>

      <div class="form-group">
        <label for="estimated_return">Estimated Rate of Return</label>
        <div class="row">
          <div class="input-group col-md-6 col-sm-8">
            <div class="input-group-prepend">
              <button class="btn btn-primary" type="button" data-counter="sub" data-field="estimated_return">−</button>
            </div>
            <input class="form-control text-center" id="estimated_return" type="text" name="estimated_return" min="0" max="50" step="0.25" value="5.00%" data-value="5.00" data-append="%">
            <div class="input-group-append">
              <button class="btn btn-primary" type="button" data-counter="add" data-field="estimated_return">+</button>
            </div>
          </div>
        </div>
      </div>

      <div class="form-group row">
        <div class="col-sm-12">
          <div>Compound Frequency</div>
          <div class="form-check form-check-inline">
            <input class="form-check-input" id="compound_period_daily" type="radio" name="compound_period" value="365">
            <label class="form-check-label" for="compound_period_daily">daily</label>
          </div>

          <div class="form-check form-check-inline">
            <input class="form-check-input" id="compound_period_monthly" type="radio" name="compound_period" value="12" checked>
            <label class="form-check-label" for="compound_period_monthly">monthly</label>
          </div>

          <div class="form-check form-check-inline">
            <input class="form-check-input" id="compound_period_annually" type="radio" name="compound_period" value="1">
            <label class="form-check-label" for="compound_period_annually">annually</label>
          </div>
        </div>
      </div>
    </div>
    <div class="col-md-6 text-center">
      <div>Future Balance</div>
      <div class="h3" id="future_balance">?</div>
      <canvas id="myChart"></canvas>
    </div>
  </div>
</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.3/css/bootstrap.css"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.js"></script>

这些事情在你的尝试中是错误的

  1. Bootstrap 引用应该是 link 而不是 script。你的代码应该是

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.3/css/bootstrap.css" rel="stylesheet"/>

而不是

<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.3/css/bootstrap.css"></script>
  1. 确保您的 HTML HIERARCHY 正常

    <head>
    <link href="link to file" rel="stylesheet">
    </head>
    <body>
    your code
    <script src="">
    </body>
    
  2. 您的图表无法正常工作,因为您在 Javascript 代码中存在语法错误。 第 74,148,166

    行有未关闭的 ''
future_balance.innerHTML = ' + balance; //74
return data.datasets[tooltipItem.datasetIndex].label + ': + tooltipItem.yLabel;//148
return ' + value;//166

将它们处理为

future_balance.innerHTML = '' + balance; //74
return data.datasets[tooltipItem.datasetIndex].label + ':' + tooltipItem.yLabel;//148
return '' + value;//166

这是您的工作代码

如果您想在此处复制粘贴 运行 代码

<head>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.3/css/bootstrap.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-6">
                <div class="form-group">
                    <label for="initial_deposit">Initial Deposit</label>
                    <div class="row">
                        <div class="input-group col-md-6 col-sm-8">
                            <div class="input-group-prepend">
                                <button class="btn btn-primary" type="button" data-counter="sub" data-field="initial_deposit">−</button>
                            </div>
                            <input class="form-control text-center" id="initial_deposit" type="text" name="initial_deposit" min="100" max="1000000" step="100" value="00" data-value="5000" data-prepend="$">
                            <div class="input-group-append">
                                <button class="btn btn-primary" type="button" data-counter="add" data-field="initial_deposit">+</button>
                            </div>
                        </div>
                    </div>
                </div>
    
                <div class="form-group">
                    <label for="contribution_amount">Contributions</label>
                    <div class="row">
                        <div class="input-group col-md-6 col-sm-8">
                            <div class="input-group-prepend">
                                <button class="btn btn-primary" type="button" data-counter="sub" data-field="contribution_amount">−</button>
                            </div>
                            <input class="form-control text-center" id="contribution_amount" type="text" name="contribution_amount" min="0" max="10000" step="50" value="0" data-value="100" data-prepend="$">
                            <div class="input-group-append">
                                <button class="btn btn-primary" type="button" data-counter="add" data-field="contribution_amount">+</button>
                            </div>
                        </div>
                    </div>
    
                    <div class="form-check form-check-inline">
                        <input class="form-check-input" id="contribution_period_monthly" type="radio" name="contribution_period" value="12" checked>
                        <label class="form-check-label" for="contribution_period_monthly">monthly</label>
                    </div>
    
                    <div class="form-check form-check-inline">
                        <input class="form-check-input" id="contribution_period_annually" type="radio" name="contribution_period" value="1">
                        <label class="form-check-label" for="contribution_period_annually">annually</label>
                    </div>
                </div>
    
                <div class="form-group">
                    <label for="investment_timespan">Investment Time Span</label>
                    <div class="row">
                        <div class="col-md-6 col-sm-8">
                            <input class="form-control" id="investment_timespan" type="range" name="investment_timespan" min="2" max="50" step="1" value="5">
                        </div>
                    </div>
                    <span id="investment_timespan_text">5 years</span>
                </div>
    
                <div class="form-group">
                    <label for="estimated_return">Estimated Rate of Return</label>
                    <div class="row">
                        <div class="input-group col-md-6 col-sm-8">
                            <div class="input-group-prepend">
                                <button class="btn btn-primary" type="button" data-counter="sub" data-field="estimated_return">−</button>
                            </div>
                            <input class="form-control text-center" id="estimated_return" type="text" name="estimated_return" min="0" max="50" step="0.25" value="5.00%" data-value="5.00" data-append="%">
                            <div class="input-group-append">
                                <button class="btn btn-primary" type="button" data-counter="add" data-field="estimated_return">+</button>
                            </div>
                        </div>
                    </div>
                </div>
    
                <div class="form-group row">
                    <div class="col-sm-12">
                        <div>Compound Frequency</div>
                        <div class="form-check form-check-inline">
                            <input class="form-check-input" id="compound_period_daily" type="radio" name="compound_period" value="365">
                            <label class="form-check-label" for="compound_period_daily">daily</label>
                        </div>
    
                        <div class="form-check form-check-inline">
                            <input class="form-check-input" id="compound_period_monthly" type="radio" name="compound_period" value="12" checked>
                            <label class="form-check-label" for="compound_period_monthly">monthly</label>
                        </div>
    
                        <div class="form-check form-check-inline">
                            <input class="form-check-input" id="compound_period_annually" type="radio" name="compound_period" value="1">
                            <label class="form-check-label" for="compound_period_annually">annually</label>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-md-6 text-center">
                <div>Future Balance</div>
                <div class="h3" id="future_balance">?</div>
                <canvas id="myChart"></canvas>
            </div>
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.js"></script>
<script>
    (function() {
  var initial_deposit = document.querySelector('#initial_deposit'),
    contribution_amount = document.querySelector('#contribution_amount'),
    investment_timespan = document.querySelector('#investment_timespan'),
    investment_timespan_text = document.querySelector('#investment_timespan_text'),
    estimated_return = document.querySelector('#estimated_return'),
    future_balance = document.querySelector('#future_balance');

  function updateValue(element, action) {
    var min = parseFloat(element.getAttribute('min')),
      max = parseFloat(element.getAttribute('max')),
      step = parseFloat(element.getAttribute('step')) || 1,
      oldValue = element.dataset.value || element.defaultValue || 0,
      newValue = parseFloat(element.value.replace(/$/, ''));

    if (isNaN(parseFloat(newValue))) {
      newValue = oldValue;
    } else {
      if (action == 'add') {
        newValue += step;
      } else if (action == 'sub') {
        newValue -= step;
      }

      newValue = newValue < min ? min : newValue > max ? max : newValue;
    }

    element.dataset.value = newValue;
    element.value = (element.dataset.prepend || '') + newValue + (element.dataset.append || '');

    updateChart();
  }

  function getChartData() {
    var P = parseFloat(initial_deposit.dataset.value), // Principal
      r = parseFloat(estimated_return.dataset.value / 100), // Annual Interest Rate
      c = parseFloat(contribution_amount.dataset.value), // Contribution Amount
      n = parseInt(document.querySelector('[name="compound_period"]:checked').value), // Compound Period
      n2 = parseInt(document.querySelector('[name="contribution_period"]:checked').value), // Contribution Period
      t = parseInt(investment_timespan.value), // Investment Time Span
      currentYear = (new Date()).getFullYear();

    var labels = [];
    for (var year = currentYear; year < currentYear + t; year++) {
      labels.push(year);
    }

    var principal_dataset = {
      label: 'Total Principal',
      backgroundColor: 'rgb(0, 123, 255)',
      data: []
    };

    var interest_dataset = {
      label: "Total Interest",
      backgroundColor: 'rgb(23, 162, 184)',
      data: []
    };

    for (var i = 1; i <= t; i++) {
      var principal = P + (c * n2 * i),
        interest = 0,
        balance = principal;

      if (r) {
        var x = Math.pow(1 + r / n, n * i),
          compound_interest = P * x,
          contribution_interest = c * (x - 1) / (r / n2);
        interest = (compound_interest + contribution_interest - principal).toFixed(0)
        balance = (compound_interest + contribution_interest).toFixed(0);
      }

      future_balance.innerHTML = '' +
      balance;
      principal_dataset.data.push(principal);
      interest_dataset.data.push(interest);
    }

    return {
      labels: labels,
      datasets: [principal_dataset, interest_dataset]
    }
  }

  function updateChart() {
    var data = getChartData();

    chart.data.labels = data.labels;
    chart.data.datasets[0].data = data.datasets[0].data;
    chart.data.datasets[1].data = data.datasets[1].data;
    chart.update();
  }

  initial_deposit.addEventListener('change', function() {
    updateValue(this);
  });

  contribution_amount.addEventListener('change', function() {
    updateValue(this);
  });

  estimated_return.addEventListener('change', function() {
    updateValue(this);
  });

  investment_timespan.addEventListener('change', function() {
    investment_timespan_text.innerHTML = this.value + ' years';
    updateChart();
  });

  investment_timespan.addEventListener('input', function() {
    investment_timespan_text.innerHTML = this.value + ' years';
  });

  var radios = document.querySelectorAll('[name="contribution_period"], [name="compound_period"]');
  for (var j = 0; j < radios.length; j++) {
    radios[j].addEventListener('change', updateChart);
  }
  var buttons = document.querySelectorAll('[data-counter]');
  for (var i = 0; i < buttons.length; i++) {
    var button = buttons[i];
    button.addEventListener('click', function() {
     var field = document.querySelector('[name="' + this.dataset.field + '"]'),
       action = this.dataset.counter;

     if (field) {
       updateValue(field, action);
     }
    });
  }

  var ctx = document.getElementById('myChart').getContext('2d'),
    chart = new Chart(ctx, {
      type: 'bar',
      data: getChartData(),
      options: {
        legend: {
          display: false
        },
        tooltips: {
          mode: 'index',
          intersect: false,
          callbacks: {
            label: function(tooltipItem, data) {
              return data.datasets[tooltipItem.datasetIndex].label + ':'  +
              tooltipItem.yLabel;
            }
          }
        },
        responsive: true,
        scales: {
          xAxes: [{
            stacked: true,
            scaleLabel: {
              display: true,
              labelString: 'Year'
            }
          }],
          yAxes: [{
            stacked: true,
            ticks: {
              callback: function(value) {
                return '' +
                value;
              }
            },
            scaleLabel: {
              display: true,
              labelString: 'Balance'
            }
          }]
        }
      }
    });

})();
</script>
</body>

请使用 returns 上的符号和分隔符。评论错误并给出更正。

//  return data.datasets[tooltipItem.datasetIndex].label + ': 
//  + tooltipItem.yLabel;

return data.datasets[tooltipItem.datasetIndex].label + ': ' +    tooltipItem.yLabel;

// future_balance.innerHTML = '
// + balance;

future_balance.innerHTML = '$' + balance;


//  return '
// + value;

return '$' + value;