JSFiddle - React, Tailwind, and code Playground

by Joshua

HTML

<textarea>
[
{"x":0,"y":0},
{"x":10,"y":100},
{"x":90,"y":50},
{"x":300,"y":100},
{"x":400,"y":0}
]
</textarea>

<svg width="400" height="400">
	<path d="" fill="none" stroke="#000" stroke-width="2px" />
</svg>

CSS

textarea {
    display:block;
    width:400px; height:200px;
}

JavaScript

var svg_helper = {
	point: function(x, y){
		if((typeof x !== 'undefined') && (typeof y !== 'undefined')){
			var ar = {x:x, y:y};
		} else {
			var ar = [];
			for(var i=0; i<x; i++)
				ar.push({});
		}
		return ar;
	},
	curve: {
		get_control_points: function(knots){
			function get_first_control_points(rhs){
				var n = rhs.length;
				var x = []; // solution vector.
				var tmp = []; // temp workspace.

				var b = 2.0;
				x[0] = rhs[0] / b;
				for (var i = 1; i < n; i++) // decomposition and forward substitution.
				{
					tmp[i] = 1 / b;
					b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
					x[i] = (rhs[i] - x[i - 1]) / b;
				}
				for (var i = 1; i < n; i++)
					x[n - i - 1] -= tmp[n - i] * x[n - i]; // backsubstitution.

				return x;
			}

			if (!knots || n < 1)
				return false;

			var first_control_points,
				second_control_points,
				n = knots.length - 1;

			if (n == 1)
			{ // straight line
				first_control_points = new svg_helper.point(1);
				// 3p1 = 2p0 + p3
				first_control_points[0].x = (2 * knots[0].x + knots[1].x) / 3;
				first_control_points[0].y = (2 * knots[0].y + knots[1].y) / 3;
				second_control_points = new svg_helper.point(1);
				// p2 = 2p1 – p0
				second_control_points[0].x = 2 *
					first_control_points[0].x - knots[0].x;
				second_control_points[0].y = 2 *
					first_control_points[0].y - knots[0].y;
			} else {

				// calculate first bezier control points
				// right hand side vector
				var rhs = [];

				// set right hand side x values
				for (var i = 1; i < n - 1; ++i)
					rhs[i] = 4 * knots[i].x + 2 * knots[i + 1].x;
				rhs[0] = knots[0].x + 2 * knots[1].x;
				rhs[n - 1] = (8 * knots[n - 1].x + knots[n].x) / 2.0;
				// get first control points x-values
				var x = get_first_control_points(rhs);

				// set right hand side y values
				for (var i = 1; i < n - 1; ++i)
					rhs[i] = 4 * knots[i].y + 2 * knots[i + 1].y;
				rhs[0] = knots[0].y + 2 * knots[1].y;
				rhs[n - 1] = (8 * knots[n - 1].y + knots[n].y)...