Published
Edited
Jul 29, 2020
1 star
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
let svg;
if (this) {
svg = d3.select(this);
} else {
svg = d3.select(DOM.svg(width, height));

svg.append("g").call(xAxis);

svg.append("g").call(yAxis);

svg
.append("path")
.attr('class', 'balance')
.attr("fill", "none")
.attr("stroke", "red");

svg
.append("path")
.attr('class', 'baseline')
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-dasharray", "4, 4");
}

svg
.select('.balance')
.transition()
.attr("d", balance(data.payments));

svg
.select('.baseline')
.transition()
.attr("d", baseline(data.payments));

return svg.node();
}
Insert cell
Insert cell
Insert cell
data.payments.length - 1
Insert cell
x = d3.scaleLinear()
.domain([0, mortgage.years.value])
.range([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear()
.domain([data.payments[0].balance, 0])
.range([margin.top, height- margin.bottom])
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom().scale(x).ticks(Math.min(data.payments.length, 30)))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
Insert cell
balance = d3.line()
.x((d, i) => x(i + ((d.partial / 12) || 1) - 1))
.y(d => y(d.balance))
Insert cell
baseline = d3.line()
.x((d, i) => x(i))
.y(d => y(d.baseline))
Insert cell
data = {
const monthlyRatePct = mortgage.rate.value / 1200
const monthlyPayment = monthlyRatePct === 0 ? mortgage.amount.value / mortgage.years.value / 12 :
mortgage.amount.value * monthlyRatePct / (1 - Math.pow(1 / (1 + monthlyRatePct), mortgage.years.value * 12))
let balance = mortgage.amount.value
let baseline = mortgage.amount.value
let payments = [{ balance, baseline }]
let partial

for (let year = 0; year < mortgage.years.value; year++) {
for (let month = 1; month <= 12; month++) {
let interestMonth = balance * monthlyRatePct
balance -= monthlyPayment + mortgage.overpayment.value - interestMonth
baseline -= monthlyPayment - (baseline * monthlyRatePct)

if (balance <= 0) {
balance = 0;
if (partial === undefined && month !== 12) {
partial = month
}
}
}

payments.push({ baseline, balance, partial})
if (partial) partial = 0;
}
return { monthlyPayment, payments }
}

Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more