roundSector.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import { normalizeArcAngles } from '../../core/PathProxy';
  2. var PI = Math.PI;
  3. var PI2 = PI * 2;
  4. var mathSin = Math.sin;
  5. var mathCos = Math.cos;
  6. var mathACos = Math.acos;
  7. var mathATan2 = Math.atan2;
  8. var mathAbs = Math.abs;
  9. var mathSqrt = Math.sqrt;
  10. var mathMax = Math.max;
  11. var mathMin = Math.min;
  12. var e = 1e-4;
  13. function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
  14. var x10 = x1 - x0;
  15. var y10 = y1 - y0;
  16. var x32 = x3 - x2;
  17. var y32 = y3 - y2;
  18. var t = y32 * x10 - x32 * y10;
  19. if (t * t < e) {
  20. return;
  21. }
  22. t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
  23. return [x0 + t * x10, y0 + t * y10];
  24. }
  25. function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) {
  26. var x01 = x0 - x1;
  27. var y01 = y0 - y1;
  28. var lo = (clockwise ? cr : -cr) / mathSqrt(x01 * x01 + y01 * y01);
  29. var ox = lo * y01;
  30. var oy = -lo * x01;
  31. var x11 = x0 + ox;
  32. var y11 = y0 + oy;
  33. var x10 = x1 + ox;
  34. var y10 = y1 + oy;
  35. var x00 = (x11 + x10) / 2;
  36. var y00 = (y11 + y10) / 2;
  37. var dx = x10 - x11;
  38. var dy = y10 - y11;
  39. var d2 = dx * dx + dy * dy;
  40. var r = radius - cr;
  41. var s = x11 * y10 - x10 * y11;
  42. var d = (dy < 0 ? -1 : 1) * mathSqrt(mathMax(0, r * r * d2 - s * s));
  43. var cx0 = (s * dy - dx * d) / d2;
  44. var cy0 = (-s * dx - dy * d) / d2;
  45. var cx1 = (s * dy + dx * d) / d2;
  46. var cy1 = (-s * dx + dy * d) / d2;
  47. var dx0 = cx0 - x00;
  48. var dy0 = cy0 - y00;
  49. var dx1 = cx1 - x00;
  50. var dy1 = cy1 - y00;
  51. if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) {
  52. cx0 = cx1;
  53. cy0 = cy1;
  54. }
  55. return {
  56. cx: cx0,
  57. cy: cy0,
  58. x01: -ox,
  59. y01: -oy,
  60. x11: cx0 * (radius / r - 1),
  61. y11: cy0 * (radius / r - 1)
  62. };
  63. }
  64. export function buildPath(ctx, shape) {
  65. var radius = mathMax(shape.r, 0);
  66. var innerRadius = mathMax(shape.r0 || 0, 0);
  67. var hasRadius = radius > 0;
  68. var hasInnerRadius = innerRadius > 0;
  69. if (!hasRadius && !hasInnerRadius) {
  70. return;
  71. }
  72. if (!hasRadius) {
  73. radius = innerRadius;
  74. innerRadius = 0;
  75. }
  76. if (innerRadius > radius) {
  77. var tmp = radius;
  78. radius = innerRadius;
  79. innerRadius = tmp;
  80. }
  81. var clockwise = !!shape.clockwise;
  82. var startAngle = shape.startAngle;
  83. var endAngle = shape.endAngle;
  84. var arc;
  85. if (startAngle === endAngle) {
  86. arc = 0;
  87. }
  88. else {
  89. var tmpAngles = [startAngle, endAngle];
  90. normalizeArcAngles(tmpAngles, !clockwise);
  91. arc = mathAbs(tmpAngles[0] - tmpAngles[1]);
  92. }
  93. var x = shape.cx;
  94. var y = shape.cy;
  95. var cornerRadius = shape.cornerRadius || 0;
  96. var innerCornerRadius = shape.innerCornerRadius || 0;
  97. if (!(radius > e)) {
  98. ctx.moveTo(x, y);
  99. }
  100. else if (arc > PI2 - e) {
  101. ctx.moveTo(x + radius * mathCos(startAngle), y + radius * mathSin(startAngle));
  102. ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
  103. if (innerRadius > e) {
  104. ctx.moveTo(x + innerRadius * mathCos(endAngle), y + innerRadius * mathSin(endAngle));
  105. ctx.arc(x, y, innerRadius, endAngle, startAngle, clockwise);
  106. }
  107. }
  108. else {
  109. var halfRd = mathAbs(radius - innerRadius) / 2;
  110. var cr = mathMin(halfRd, cornerRadius);
  111. var icr = mathMin(halfRd, innerCornerRadius);
  112. var cr0 = icr;
  113. var cr1 = cr;
  114. var xrs = radius * mathCos(startAngle);
  115. var yrs = radius * mathSin(startAngle);
  116. var xire = innerRadius * mathCos(endAngle);
  117. var yire = innerRadius * mathSin(endAngle);
  118. var xre = void 0;
  119. var yre = void 0;
  120. var xirs = void 0;
  121. var yirs = void 0;
  122. if (cr > e || icr > e) {
  123. xre = radius * mathCos(endAngle);
  124. yre = radius * mathSin(endAngle);
  125. xirs = innerRadius * mathCos(startAngle);
  126. yirs = innerRadius * mathSin(startAngle);
  127. if (arc < PI) {
  128. var it_1 = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire);
  129. if (it_1) {
  130. var x0 = xrs - it_1[0];
  131. var y0 = yrs - it_1[1];
  132. var x1 = xre - it_1[0];
  133. var y1 = yre - it_1[1];
  134. var a = 1 / mathSin(mathACos((x0 * x1 + y0 * y1) / (mathSqrt(x0 * x0 + y0 * y0) * mathSqrt(x1 * x1 + y1 * y1))) / 2);
  135. var b = mathSqrt(it_1[0] * it_1[0] + it_1[1] * it_1[1]);
  136. cr0 = mathMin(icr, (innerRadius - b) / (a - 1));
  137. cr1 = mathMin(cr, (radius - b) / (a + 1));
  138. }
  139. }
  140. }
  141. if (!(arc > e)) {
  142. ctx.moveTo(x + xrs, y + yrs);
  143. }
  144. else if (cr1 > e) {
  145. var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, cr1, clockwise);
  146. var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, cr1, clockwise);
  147. ctx.moveTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
  148. if (cr1 < cr) {
  149. ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
  150. }
  151. else {
  152. ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
  153. ctx.arc(x, y, radius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), !clockwise);
  154. ctx.arc(x + ct1.cx, y + ct1.cy, cr1, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
  155. }
  156. }
  157. else {
  158. ctx.moveTo(x + xrs, y + yrs);
  159. ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
  160. }
  161. if (!(innerRadius > e) || !(arc > e)) {
  162. ctx.lineTo(x + xire, y + yire);
  163. }
  164. else if (cr0 > e) {
  165. var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -cr0, clockwise);
  166. var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -cr0, clockwise);
  167. ctx.lineTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
  168. if (cr0 < icr) {
  169. ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
  170. }
  171. else {
  172. ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
  173. ctx.arc(x, y, innerRadius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), clockwise);
  174. ctx.arc(x + ct1.cx, y + ct1.cy, cr0, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
  175. }
  176. }
  177. else {
  178. ctx.lineTo(x + xire, y + yire);
  179. ctx.arc(x, y, innerRadius, endAngle, startAngle, clockwise);
  180. }
  181. }
  182. ctx.closePath();
  183. }