## Find Point along Bezier Curve in JavaScript

I adapted this from an excellent C++ example yesterday and wanted to share. This is for an HTML5 game (like) project I’m working on where interpolating along vector art created in Adobe Illustrator is needed (more on that in a future post hopefully!)

Javascript | | copy code | | ? |

01 | |

02 | `///////////////////////////////////////////////////////////////` |

03 | `// JavaScript Implementation of the DeCasteljau Algorithm` |

04 | `// Based on C++ Implementation from ` |

05 | `// http://cubic.org/docs/bezier.htm` |

06 | `// which credits Nils Pipenbrinck aka Submissive/Cubic & $eeN` |

07 | `// this particular implementation written by Mike Randrup Aug 30 2012` |

08 | `///////////////////////////////////////////////////////////////` |

09 | |

10 | `/* Usage:` |

11 | |

12 | ` // A & D are the start and end points of the line` |

13 | ` // B & C are the handle (influence) points` |

14 | |

15 | ` myPointA = bezier.point(40,100);` |

16 | ` myPointB = bezier.point(80,20);` |

17 | ` myPointC = bezier.point(150,180);` |

18 | ` myPointD = bezier.point(260,100);` |

19 | |

20 | ` time = 0.5; // halfway through curve` |

21 | |

22 | ` resultPoint = bezier.calc(` |

23 | ` myPointA, myPointB,` |

24 | ` myPointC, myPointD,` |

25 | ` time` |

26 | ` );` |

27 | |

28 | `*/ ` |

29 | |

30 | |

31 | var bezier = (function(){ |

32 | |

33 | var Point = function (x, y) { |

34 | this.x = x || 0; |

35 | this.y = y || 0; |

36 | return this; |

37 | ` }` |

38 | |

39 | var interpolateLinear = function (pointA, pointB, time) { |

40 | return { |

41 | x: pointA.x + (pointB.x - pointA.x) * time, |

42 | y: pointA.y + (pointB.y - pointA.y) * time, |

43 | ` }` |

44 | ` }` |

45 | |

46 | var bezObj = { |

47 | |

48 | point: function(x, y) { |

49 | return new Point(x, y); |

50 | }, |

51 | |

52 | calc: function(p1, p2, p3, p4, time) { |

53 | var ab = interpolateLinear(p1, p2, time), |

54 | bc = interpolateLinear(p2, p3, time), |

55 | cd = interpolateLinear(p3, p4, time), |

56 | abbc = interpolateLinear(ab, bc, time), |

57 | bccd = interpolateLinear(bc, cd, time); |

58 | |

59 | return interpolateLinear(abbc, bccd, time); |

60 | }, |

61 | |

62 | ` }` |

63 | |

64 | return bezObj; |

65 | |

66 | }()); |

67 | |

68 | console.log("bezier loaded", bezier); |

69 | |

70 | `///////////////////////////////////////////////////////////////` |

71 | `// Also check out http://13thparallel.com/archive/bezier-curves/` |

72 | `// for an alternate bezier option in JavaScript` |

73 | `///////////////////////////////////////////////////////////////` |

74 |

Plotting and animating the resulting curve in a canvas is a good way to see it working. Here is what that might look like.

HTML5 | | copy code | | ? |

01 | |

02 | `<html lang="us-en">` |

03 | |

04 | `<head>` |

05 | <title>Bezier curve test by Mike Randrup</title> |

06 | `</head>` |

07 | |

08 | `<body>` |

09 | |

10 | `<canvas id="output" width="600" height="400"></canvas>` |

11 | |

12 | `<script type="text/javascript" src="bezier.js"></script>` |

13 | `<script type="text/javascript">` |

14 | // the below javascript snippet goes inline here |

15 | `</script></body></html>` |

This snippet goes into the HTML5 markup above. (I needed to separate to fix a problem with my new WordPress code formatting plugin)

Javascript | | copy code | | ? |

01 | |

02 | window.onload = function() { |

03 | |

04 | console.log("main running"); |

05 | |

06 | var i, |

07 | ` t,` |

08 | steps = 200, |

09 | ` resultPoint,` |

10 | |

11 | myPointA = bezier.point(40,100), |

12 | myPointB = bezier.point(80,20), |

13 | myPointC = bezier.point(700,180), |

14 | myPointD = bezier.point(550,100), |

15 | |

16 | canvasEl = document.getElementById("output"), |

17 | canvasContext = canvasEl.getContext("2d"); |

18 | |

19 | var nextFrame = function() { |

20 | moveControlPoints(); |

21 | drawCurve(); |

22 | }; |

23 | |

24 | var moveControlPoints = function() { |

25 | if (myPointA.x>0 && myPointA.x<600) myPointA.x++; |

26 | if (myPointB.x>0 && myPointB.x<600) myPointB.x++; |

27 | |

28 | if (myPointC.y>0 && myPointC.y<400) myPointC.y--; |

29 | if (myPointD.x>0 && myPointD.x<600) myPointD.x--; |

30 | |

31 | }; |

32 | |

33 | var drawCurve = function () { |

34 | canvasContext.fillStyle = "#FFF"; |

35 | canvasContext.fillRect(0,0,600,400); |

36 | |

37 | canvasContext.fillStyle = "#F00"; |

38 | |

39 | for (i=0; i<steps ; i++) { |

40 | t = i / (steps-1); |

41 | |

42 | resultPoint = bezier.calc( |

43 | myPointA, myPointB, |

44 | myPointC, myPointD, |

45 | t |

46 | ); |

47 | |

48 | canvasContext.fillRect(resultPoint.x, resultPoint.y, 2, 2); |

49 | ` }` |

50 | }; |

51 | |

52 | setInterval(nextFrame, 50); // I don't like this here. |

53 | |

54 | |

55 | ` }` |

56 |