fill-path.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. function decasteljau(points, t) {
  2. var left = [];
  3. var right = [];
  4. function recurse(points, t) {
  5. if (points.length === 1) {
  6. left.push(points[0]);
  7. right.push(points[0]);
  8. } else {
  9. var middlePoints = [];
  10. for (var i = 0; i < points.length - 1; i++) {
  11. if (i === 0) {
  12. left.push(points[0]);
  13. }
  14. if (i === points.length - 2) {
  15. right.push(points[i + 1]);
  16. }
  17. middlePoints[i] = [(1 - t) * points[i][0] + t * points[i + 1][0], (1 - t) * points[i][1] + t * points[i + 1][1]];
  18. }
  19. recurse(middlePoints, t);
  20. }
  21. }
  22. if (points.length) {
  23. recurse(points, t);
  24. }
  25. return { left: left, right: right.reverse() };
  26. }
  27. function splitCurve(start, end, count) {
  28. var points = [[start[1], start[2]]];
  29. count = count || 2;
  30. var segments = [];
  31. if (end[0] === 'A') {
  32. points.push(end[6]);
  33. points.push(end[7]);
  34. } else if (end[0] === 'C') {
  35. points.push([end[1], end[2]]);
  36. points.push([end[3], end[4]]);
  37. points.push([end[5], end[6]]);
  38. } else if (end[0] === 'S' || end[0] === 'Q') {
  39. points.push([end[1], end[2]]);
  40. points.push([end[3], end[4]]);
  41. } else {
  42. points.push([end[1], end[2]]);
  43. }
  44. var leftSegments = points;
  45. var t = 1 / count;
  46. for (var i = 0; i < count - 1; i++) {
  47. var rt = t / (1 - t * i);
  48. var split = decasteljau(leftSegments, rt);
  49. segments.push(split.left);
  50. leftSegments = split.right;
  51. }
  52. segments.push(leftSegments);
  53. var result = segments.map(function (segment) {
  54. var cmd = [];
  55. if (segment.length === 4) {
  56. cmd.push('C');
  57. cmd = cmd.concat(segment[2]);
  58. }
  59. if (segment.length >= 3) {
  60. if (segment.length === 3) {
  61. cmd.push('Q');
  62. }
  63. cmd = cmd.concat(segment[1]);
  64. }
  65. if (segment.length === 2) {
  66. cmd.push('L');
  67. }
  68. cmd = cmd.concat(segment[segment.length - 1]);
  69. return cmd;
  70. });
  71. return result;
  72. }
  73. function splitSegment(start, end, count) {
  74. if (count === 1) {
  75. return [[].concat(start)];
  76. }
  77. var segments = [];
  78. if (end[0] === 'L' || end[0] === 'C' || end[0] === 'Q') {
  79. segments = segments.concat(splitCurve(start, end, count));
  80. } else {
  81. var temp = [].concat(start);
  82. if (temp[0] === 'M') {
  83. temp[0] = 'L';
  84. }
  85. for (var i = 0; i <= count - 1; i++) {
  86. segments.push(temp);
  87. }
  88. }
  89. return segments;
  90. }
  91. module.exports = function fillPath(source, target) {
  92. if (source.length === 1) {
  93. return source;
  94. }
  95. var sourceLen = source.length - 1;
  96. var targetLen = target.length - 1;
  97. var ratio = sourceLen / targetLen;
  98. var segmentsToFill = [];
  99. if (source.length === 1 && source[0][0] === 'M') {
  100. for (var i = 0; i < targetLen - sourceLen; i++) {
  101. source.push(source[0]);
  102. }
  103. return source;
  104. }
  105. for (var _i = 0; _i < targetLen; _i++) {
  106. var index = Math.floor(ratio * _i);
  107. segmentsToFill[index] = (segmentsToFill[index] || 0) + 1;
  108. }
  109. var filled = segmentsToFill.reduce(function (filled, count, i) {
  110. if (i === sourceLen) {
  111. return filled.concat(source[sourceLen]);
  112. }
  113. return filled.concat(splitSegment(source[i], source[i + 1], count));
  114. }, []);
  115. filled.unshift(source[0]);
  116. if (target[targetLen] === 'Z' || target[targetLen] === 'z') {
  117. filled.push('Z');
  118. }
  119. return filled;
  120. };