arc.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. if (!dojo._hasResource["dojox.gfx.arc"]) { // _hasResource checks added by
  2. // build. Do not use _hasResource
  3. // directly in your code.
  4. dojo._hasResource["dojox.gfx.arc"] = true;
  5. dojo.provide("dojox.gfx.arc");
  6. dojo.require("dojox.gfx.matrix");
  7. (function() {
  8. var m = dojox.gfx.matrix, unitArcAsBezier = function(alpha) {
  9. // summary: return a start point, 1st and 2nd control points, and an
  10. // end point of
  11. // a an arc, which is reflected on the x axis
  12. // alpha: Number: angle in radians, the arc will be 2 * angle size
  13. var cosa = Math.cos(alpha), sina = Math.sin(alpha), p2 = {
  14. x : cosa + (4 / 3) * (1 - cosa),
  15. y : sina - (4 / 3) * cosa * (1 - cosa) / sina
  16. };
  17. return { // Object
  18. s : {
  19. x : cosa,
  20. y : -sina
  21. },
  22. c1 : {
  23. x : p2.x,
  24. y : -p2.y
  25. },
  26. c2 : p2,
  27. e : {
  28. x : cosa,
  29. y : sina
  30. }
  31. };
  32. }, twoPI = 2 * Math.PI, pi4 = Math.PI / 4, pi8 = Math.PI / 8, pi48 = pi4
  33. + pi8, curvePI4 = unitArcAsBezier(pi8);
  34. dojo.mixin(dojox.gfx.arc, {
  35. unitArcAsBezier : unitArcAsBezier,
  36. curvePI4 : curvePI4,
  37. arcAsBezier : function(last, rx, ry, xRotg, large, sweep, x, y) {
  38. // summary: calculates an arc as a series of Bezier curves
  39. // given the last point and a standard set of SVG arc
  40. // parameters,
  41. // it returns an array of arrays of parameters to form a series
  42. // of
  43. // absolute Bezier curves.
  44. // last: Object: a point-like object as a start of the arc
  45. // rx: Number: a horizontal radius for the virtual ellipse
  46. // ry: Number: a vertical radius for the virtual ellipse
  47. // xRotg: Number: a rotation of an x axis of the virtual ellipse
  48. // in degrees
  49. // large: Boolean: which part of the ellipse will be used (the
  50. // larger arc if true)
  51. // sweep: Boolean: direction of the arc (CW if true)
  52. // x: Number: the x coordinate of the end point of the arc
  53. // y: Number: the y coordinate of the end point of the arc
  54. // calculate parameters
  55. large = Boolean(large);
  56. sweep = Boolean(sweep);
  57. var xRot = m._degToRad(xRotg), rx2 = rx * rx, ry2 = ry * ry, pa = m
  58. .multiplyPoint(m.rotate(-xRot), {
  59. x : (last.x - x) / 2,
  60. y : (last.y - y) / 2
  61. }), pax2 = pa.x * pa.x, pay2 = pa.y * pa.y, c1 = Math
  62. .sqrt((rx2 * ry2 - rx2 * pay2 - ry2 * pax2)
  63. / (rx2 * pay2 + ry2 * pax2));
  64. if (isNaN(c1)) {
  65. c1 = 0;
  66. }
  67. var ca = {
  68. x : c1 * rx * pa.y / ry,
  69. y : -c1 * ry * pa.x / rx
  70. };
  71. if (large == sweep) {
  72. ca = {
  73. x : -ca.x,
  74. y : -ca.y
  75. };
  76. }
  77. // the center
  78. var c = m.multiplyPoint(
  79. [m.translate((last.x + x) / 2, (last.y + y) / 2),
  80. m.rotate(xRot)], ca);
  81. // calculate the elliptic transformation
  82. var elliptic_transform = m.normalize([m.translate(c.x, c.y),
  83. m.rotate(xRot), m.scale(rx, ry)]);
  84. // start, end, and size of our arc
  85. var inversed = m.invert(elliptic_transform), sp = m
  86. .multiplyPoint(inversed, last), ep = m.multiplyPoint(
  87. inversed, x, y), startAngle = Math.atan2(sp.y, sp.x), endAngle = Math
  88. .atan2(ep.y, ep.x), theta = startAngle - endAngle; // size
  89. // of
  90. // our
  91. // arc
  92. // in
  93. // radians
  94. if (sweep) {
  95. theta = -theta;
  96. }
  97. if (theta < 0) {
  98. theta += twoPI;
  99. } else if (theta > twoPI) {
  100. theta -= twoPI;
  101. }
  102. // draw curve chunks
  103. var alpha = pi8, curve = curvePI4, step = sweep
  104. ? alpha
  105. : -alpha, result = [];
  106. for (var angle = theta; angle > 0; angle -= pi4) {
  107. if (angle < pi48) {
  108. alpha = angle / 2;
  109. curve = unitArcAsBezier(alpha);
  110. step = sweep ? alpha : -alpha;
  111. angle = 0; // stop the loop
  112. }
  113. var c1, c2, e, M = m.normalize([elliptic_transform,
  114. m.rotate(startAngle + step)]);
  115. if (sweep) {
  116. c1 = m.multiplyPoint(M, curve.c1);
  117. c2 = m.multiplyPoint(M, curve.c2);
  118. e = m.multiplyPoint(M, curve.e);
  119. } else {
  120. c1 = m.multiplyPoint(M, curve.c2);
  121. c2 = m.multiplyPoint(M, curve.c1);
  122. e = m.multiplyPoint(M, curve.s);
  123. }
  124. // draw the curve
  125. result.push([c1.x, c1.y, c2.x, c2.y, e.x, e.y]);
  126. startAngle += 2 * step;
  127. }
  128. return result; // Object
  129. }
  130. });
  131. })();
  132. }