JSFiddle - React, Tailwind, and code Playground

by Josh Pullen

CSS

html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
}

JavaScript

import { h, Component, render } from "https://esm.sh/preact";
import { signal, computed } from "https://esm.sh/@preact/signals";
import htm from "https://esm.sh/htm";

const html = htm.bind(h);

const rate = signal(7);
const payment = signal(500);

function balance(amount, rate, payment, years) {
  return (
    amount * (1 + rate / 12) ** (12 * years) -
    payment * (((1 + rate / 12) ** (12 * years) - 1) / (rate / 12))
  );
}

const balanceValues = computed(() => {
  let values = [];
  for (let year = 0; year <= 15; year++) {
    values.push([year, balance(50000, rate.value / 100, payment.value, year)]);
  }
  return values;
});

const balancePolylineStr = computed(() => {
  let xRange = [0, 400];
  let yRange = [0, 400];

  let yearRange = [0, 15];
  let balanceRange = [0, 50000];

  const mapRange = (value, valueRange, targetRange) => {
    const t = (value - valueRange[0]) / (valueRange[1] - valueRange[0]);
    return t * (targetRange[1] - targetRange[0]) + targetRange[0];
  };

  return balanceValues.value
    .map(([year, balance]) => {
      const x = mapRange(year, yearRange, xRange);
      const y = mapRange(balance, balanceRange, yRange);
      return `${x},${400 - y}`;
    })
    .join(" ");
});

const yearsToPayOff = computed(() => {
  if (payment.value <= (50000 * rate.value) / 12 / 100) {
    return "NEVER";
  }

  const months =
    Math.log(
      payment.value / (payment.value - (50000 * rate.value) / 12 / 100)
    ) / Math.log(1 + rate.value / 12 / 100);
  return months / 12;
});

function App(props) {
  return html`
    <div>
      <input
        type="range"
        min="2"
        max="12"
        step="0.1"
        value=${rate}
        onInput=${(event) => {
          rate.value = Number(event.target.value);
        }}
      />
      Rate: ${rate}%
    </div>
  `;
  
  return html`
    <div>Loan amount: $50,000</div>
    <div>
      <input
        type="range"
        min="2"
        max="12"
        step="0.1"
        value=${rate}
       ...