Skip to content

Instantly share code, notes, and snippets.

@Guseyn
Created June 20, 2020 10:06
Show Gist options
  • Save Guseyn/2c25e0c9c8ce56b745b01a54156e78a5 to your computer and use it in GitHub Desktop.
Save Guseyn/2c25e0c9c8ce56b745b01a54156e78a5 to your computer and use it in GitHub Desktop.
Bezier curve interpolation as svg path
// Based on this excellent article (https://apoorvaj.io/cubic-bezier-through-four-points/)
const vectorLength = (p1, p2) => {
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2))
}
const middleCurvePoints = (firstPoint, secondPoint, thirdPoint, fourthPoint, alpha, epsilon) => {
const d1 = Math.pow(vectorLength(secondPoint, firstPoint), alpha)
const d2 = Math.pow(vectorLength(thirdPoint, secondPoint), alpha)
const d3 = Math.pow(vectorLength(fourthPoint, thirdPoint), alpha)
const a1 = Math.pow(d1, 2)
const b1 = Math.pow(d2, 2)
const c1 = 2 * a1 + 3 * d1 * d2 + b1
const denominator1 = (3 * d1 * (d1 + d2)) || epsilon
const firstControlPoint = {
x: (a1 * thirdPoint.x - b1 * firstPoint.x + c1 * secondPoint.x) / denominator1,
y: (a1 * thirdPoint.y - b1 * firstPoint.y + c1 * secondPoint.y) / denominator1
}
const a2 = Math.pow(d3, 2)
const b2 = Math.pow(d2, 2)
const c2 = 2 * a2 + 3 * d3 * d2 + b2
const denominator2 = (3 * d3 * (d3 + d2)) || epsilon
const secondControlPoint = {
x: (a2 * secondPoint.x - b2 * fourthPoint.x + c2 * thirdPoint.x) / denominator2,
y: (a2 * secondPoint.y - b2 * fourthPoint.y + c2 * thirdPoint.y) / denominator2
}
return [
secondPoint.x, secondPoint.y,
firstControlPoint.x, firstControlPoint.y,
secondControlPoint.x, secondControlPoint.y,
thirdPoint.x, thirdPoint.y
]
}
module.exports = (firstPoint, secondPoint, thirdPoint, fourthPoint, alpha = 1) => {
// alpha can be also 0.5 or 0 (it's a coefficient of tightness of the line)
const epsilon = 0.0001
const firstPhantomPoint = {
x: firstPoint.x + epsilon * (firstPoint.x - secondPoint.x),
y: firstPoint.y + epsilon * (firstPoint.y - secondPoint.y)
}
const secondPhantomPoint = {
x: thirdPoint.x + epsilon * (thirdPoint.x - fourthPoint.x),
y: thirdPoint.y + epsilon * (thirdPoint.x - fourthPoint.x)
}
const curvePointsBetweenFirstAndSecondPoints = middleCurvePoints(firstPhantomPoint, firstPoint, secondPoint, thirdPoint, alpha, epsilon)
const curvePointsBetweenSecondAndThirdPoints = middleCurvePoints(firstPoint, secondPoint, thirdPoint, fourthPoint, alpha, epsilon)
const curvePointsBetweenThirdAndFourthPoints = middleCurvePoints(secondPoint, thirdPoint, fourthPoint, secondPhantomPoint, alpha, epsilon)
return [
/* 'M',
firstPoint.x, firstPoint.y,
'L',
secondPoint.x, secondPoint.y,
'L',
thirdPoint.x, thirdPoint.y,
'L',
fourthPoint.x, fourthPoint.y, */
'M',
curvePointsBetweenFirstAndSecondPoints[0], curvePointsBetweenFirstAndSecondPoints[1],
'C',
curvePointsBetweenFirstAndSecondPoints[2], curvePointsBetweenFirstAndSecondPoints[3],
curvePointsBetweenFirstAndSecondPoints[4], curvePointsBetweenFirstAndSecondPoints[5],
curvePointsBetweenFirstAndSecondPoints[6], curvePointsBetweenFirstAndSecondPoints[7],
// 'M',
// curvePointsBetweenSecondAndThirdPoints[0], curvePointsBetweenSecondAndThirdPoints[1],
'C',
curvePointsBetweenSecondAndThirdPoints[2], curvePointsBetweenSecondAndThirdPoints[3],
curvePointsBetweenSecondAndThirdPoints[4], curvePointsBetweenSecondAndThirdPoints[5],
curvePointsBetweenSecondAndThirdPoints[6], curvePointsBetweenSecondAndThirdPoints[7],
// 'M',
// curvePointsBetweenThirdAndFourthPoints[0], curvePointsBetweenThirdAndFourthPoints[1],
'C',
curvePointsBetweenThirdAndFourthPoints[2], curvePointsBetweenThirdAndFourthPoints[3],
curvePointsBetweenThirdAndFourthPoints[4], curvePointsBetweenThirdAndFourthPoints[5],
curvePointsBetweenThirdAndFourthPoints[6], curvePointsBetweenThirdAndFourthPoints[7]
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment