Bezier.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. const Bezier = function (pointArr, allTime = 2) {
  2. let _this = {}
  3. // 曲线点集合,曲线总长,上一个点,当前时间
  4. let _pointLists, totalLength, prevPos, currentRunTime;
  5. // 运行时间
  6. let _runTime = allTime;
  7. let _pointArr = pointArr;
  8. // 重置数据
  9. let resetData = function () {
  10. // 点集合
  11. _pointLists = [];
  12. // 线段总长度
  13. totalLength = currentRunTime = 0;
  14. // 初始位置
  15. prevPos = {
  16. x: pointArr[0].x,
  17. y: pointArr[0].y,
  18. length: 0,
  19. }
  20. }
  21. //阶乘
  22. function factorial(i) {
  23. let n = 1;
  24. for (let j = 1; j <= i; j++)
  25. n *= j;
  26. return n;
  27. }
  28. // ------------------------【核心代码】---------------------------
  29. let ComputeBezier = function (dt, runTime) {
  30. // 把时间从 [0,runTime] 映射到 [0,1] 之间
  31. let t = currentRunTime / runTime;
  32. var x = 0, y = 0;
  33. //控制点数组
  34. var n = _pointArr.length - 1;
  35. _pointArr.forEach((item, index) => {
  36. if (!index) {
  37. x += item.x * Math.pow((1 - t), n - index) * Math.pow(t, index)
  38. y += item.y * Math.pow((1 - t), n - index) * Math.pow(t, index)
  39. } else {
  40. //factorial为阶乘函数
  41. x += factorial(n) / factorial(index) / factorial(n - index) * item.x * Math.pow((1 - t), n - index) * Math.pow(t, index)
  42. y += factorial(n) / factorial(index) / factorial(n - index) * item.y * Math.pow((1 - t), n - index) * Math.pow(t, index)
  43. }
  44. })
  45. // // 二阶贝塞尔曲线公式 (t => [0,1])
  46. // var x = Math.pow(1 - t, 2) * _startPos.x
  47. // + 2 * t * (1 - t) * _controlPos.x
  48. // + Math.pow(t, 2) * _endPos.x;
  49. // var y = Math.pow(1 - t, 2) * _startPos.y
  50. // + 2 * t * (1 - t) * _controlPos.y
  51. // + Math.pow(t, 2) * _endPos.y;
  52. // console.log(`x:${x},y:${y}`);
  53. // 计算两点距离
  54. let length = Math.sqrt(Math.pow(prevPos.x - x, 2) + Math.pow(prevPos.y - y, 2));
  55. let v2 = { x, y, length };
  56. // 存储当前节点
  57. _pointLists.push(v2);
  58. prevPos = v2;
  59. // 累计长度
  60. totalLength += length;
  61. // 累计时间
  62. currentRunTime += dt;
  63. }
  64. // 切割贝塞尔曲线
  65. _this.getPoints = function (count = 10) {
  66. resetData();
  67. // 分割时间
  68. let dt = _runTime / count;
  69. // 开始分割曲线
  70. for (var i = 0, len = count + 1; i < len; i++) {
  71. ComputeBezier(dt, _runTime);
  72. }
  73. return _pointLists
  74. }
  75. _this.getCurveLength = function () {
  76. return totalLength;
  77. }
  78. return _this;
  79. }
  80. module.exports = Bezier;