JSFiddle - React, Tailwind, and code Playground

by Josh Pullen

HTML

<button id="updateBtn">Update</button><br />

CSS

canvas {
  border: 1px solid black;
}

JavaScript

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

canvas.width = 600;
canvas.height = 400;
document.body.append(canvas);

const data = [
	[1, 2],
  [2, 4],
  [4, 4],
  [8, 8],
  [9, 6],
  [10, 9]
];

const graphScale = 30;

function drawDataPoints() {
	for (let i = 0; i < data.length; i++) {
  	const point = data[i];
    
    ctx.beginPath();
    ctx.arc(
    	point[0] * graphScale,
      canvas.height - point[1] * graphScale,
      0.2 * graphScale,
      0, 2 * Math.PI
    );
    ctx.fill();
  }
}

// These the the function parameters a and b in y = ax + b
// We will tweak them over time
let parameters = [0, 0, 0];

function line(x, [a, b, c] = parameters) {
  return a * x**2 + b * x + c;
}

function drawLine() {
	ctx.lineWidth = 10;
  ctx.strokeStyle = "blue";

	ctx.beginPath();
  ctx.moveTo(0, canvas.height - line(0) * graphScale);
  for (let i = 0; i <= 1; i += 0.1) {
  	ctx.lineTo(i * canvas.width, canvas.height - line(i * canvas.width / graphScale) * graphScale);
  }
  ctx.stroke();
}

function computeError(params = parameters) {
	let error = 0;
  for (let i = 0; i < data.length; i++) {
  	const point = data[i];
    error += (point[1] - line(point[0], params)) ** 2;
  }
  return error;
}

function fakeDerivative(func, x) {
	const x1 = x - 0.00001;
  const x2 = x + 0.00001;
  
  const y1 = func(x1);
  const y2 = func(x2);
  
  return (y2 - y1) / (x2 - x1);
}

function updateParameters(speed) {
	function paramsWithValue(index, value) {
  	let result = [...parameters];
    result[index] = value;
    return result;
  }

	let derivatives = [];
  for (let i = 0; i < parameters.length; i++) {
  	derivatives.push(fakeDerivative(
    	v => computeError(paramsWithValue(i, v)),
      parameters[i]
		));
  }
  
  for (let i = 0; i < parameters.length; i++) {
  	parameters[i] += -speed * Math.sqrt(Math.abs(derivatives[i])) * Math.sign(derivatives[i]);
 ...