Cubic Bézier curve and its middle point (svg)

Display a cubic Bézier curve, compute and display its middle point, generate the corresponding svg code.

by Simon Hi

HTML

<h1>Cubic Bézier curve and its middle point</h1>
<svg id="svgRef" width="250" height="250">
	<path id="pRef" d="M 75,75 c 20,180 180,20 -5,-5" fill="transparent" stroke="blue" stroke-width="10" />
	<circle id="cRef" cx="0" cy="0" r="10" fill="transparent" stroke="blue" stroke-width="10" />
</svg>
<br>
<div class="control">
  <span>M:</span>
  <input id="mx" type="text" onkeyup="updateSvg()">
  <input id="my" type="text" onkeyup="updateSvg()"><br>
  <span>c1:</span>
  <input id="c1x" type="text" onkeyup="updateSvg()">
  <input id="c1y" type="text" onkeyup="updateSvg()"><br>
  <span>c2:</span>
  <input id="c2x" type="text" onkeyup="updateSvg()">
  <input id="c2y" type="text" onkeyup="updateSvg()"><br>
  <span>c3:</span>
  <input id="c3x" type="text" onkeyup="updateSvg()">
  <input id="c3y" type="text" onkeyup="updateSvg()"><br>
</div>
<div id="trace"></div>

CSS

body {
  text-align: center;
}

svg {
  border: 10px solid blue;
}

#control span {
  display: inline-block;
  width: 2em;
  text-align: right;
  margin-right: 0.5em;
}

#trace {
  display: table;
  margin: 1em auto;
  text-align: left;
}

#trace span:nth-of-type(2),
#trace span:nth-of-type(3) {
  padding-left: 2em;
}

JavaScript

// compute coordinates of the middle point of a cubic Bezier curve
// need two functions: cubicBezierCurvePoint and cubicBezierCurvesMiddle
function cubicBezierCurvePoint(t, c) {
  // compute relative coordinates of a point on the curve using t and c
  // t is a number between 0 and 1
  // c is an array of 4 points:
  //     the initial point of the curve (always (0,0))
  //     the 2 "handle" points of the curve
  //     the final point of the curve
  var t1, t1_3, t1_3a, t1_3b, t1_3c;
  t1 = 1 - t;
  t1_3 = t1 * t1 * t1;
  t1_3a = (3 * t) * (t1 * t1);
  t1_3b = (3 * (t * t)) * t1;
  t1_3c = (t * t * t);
  return {
    x: (c[0].x * t1_3) + (t1_3a * c[1].x) + (t1_3b * c[2].x) + (t1_3c * c[3].x),
    y: (c[0].y * t1_3) + (t1_3a * c[1].y) + (t1_3b * c[2].y) + (t1_3c * c[3].y)
  };
}

function cubicBezierCurvesMiddle(m, c) {
  var k, km = 1000,
    km2 = (km >> 1),
    len = 0,
    len2, x, y, a = new Array(km + 1);
  // compute curve lengths from start point to any point
  // store relative point coordinates and corresponding length in array a
  for (k = 0; k <= km; k++) {
    a[k] = {
      pt: cubicBezierCurvePoint(k / km, c),
      len: 0
    };
    if (k > 0) {
      x = a[k].pt.x - a[k - 1].pt.x;
      y = a[k].pt.y - a[k - 1].pt.y;
      a[k].len = a[k - 1].len + Math.sqrt(x * x + y * y);
    }
  }
  // retrieve the point which is at a distance of half the whole curve length from start point
  // most of the time, this point is not the one at indice km2 in array a, but it is near it
  len2 = a[km].len / 2;
  if (a[km2].len > len2)
    for (k = km2; k >= 0; k--) {
      if (len2 >= a[k].len) break;
    }
  else
    for (k = km2; k <= km; k++) {
      if (len2 <= a[k].len) break;
    }
  // return absolute coordinates of the point
  return {
    x: Math.round((a[k].pt.x + m.x) * 100) / 100,
    y: Math.round((a[k].pt.y + m.y) * 100) / 100
  };
}

// manage the data form and update the svg graphic
// need two functions: getVal and updateSvg
function getVal(id)...