curve.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. * 曲线
  3. * */
  4. define(function(require, exports, module) {
  5. var Utils = require('../core/utils'),
  6. CurveUtil = {
  7. /*
  8. * 获取由两个以上的点组成的曲线的平移线
  9. * @param points 曲线上的点的集合, 集合中的点的数量必须大于2
  10. * @return 平移线数组
  11. */
  12. getCurvePanLines: function(points, smoothFactor) {
  13. //计算原始点的中点坐标
  14. var centerPoints = CurveUtil.getCenterPoints(points),
  15. //注意:计算中点连线的中点坐标, 得出平移线
  16. panLines = CurveUtil.getPanLine(points.length, centerPoints);
  17. //平移线移动到顶点
  18. return CurveUtil.getMovedPanLines(points, panLines, smoothFactor);
  19. },
  20. /*
  21. * 计算给定点集合的连线的中点
  22. * @param points
  23. */
  24. getCenterPoints: function(points) {
  25. var centerPoints = {},
  26. key = null;
  27. for (var i = 0, j = 0, len = points.length; i < len; i++) {
  28. //j是下一个点的索引
  29. j = i === (len - 1) ? 0 : i + 1;
  30. key = i + ',' + j;
  31. //计算中点坐标
  32. centerPoints[key] = {
  33. x: (points[i].x + points[j].y) / 2,
  34. y: (points[i].x + points[j].y) / 2
  35. };
  36. }
  37. return centerPoints;
  38. },
  39. /*
  40. * 对getCenterPoints()接口获取到的数据做处理, 计算出各个顶点对应的平移线数据
  41. * @param length 集合中点的个数
  42. * @param points 点集合, 该集合应该是getCenterPoints()接口返回的数据
  43. */
  44. getPanLine: function(length, points) {
  45. var result = {},
  46. //顶点索引
  47. pointIndex = null;
  48. for (var i = 0, j; i < length; i++) {
  49. var point1 = null,
  50. point2 = null;
  51. //计算当前点
  52. j = (i + 1) % length;
  53. //保存当前处理的顶点索引
  54. pointIndex = j;
  55. point1 = points[i + ',' + j];
  56. //计算下一个点
  57. i = j;
  58. j = (i + 1) % length;
  59. point2 = points[i + ',' + j];
  60. result[pointIndex] = {
  61. points: [{
  62. x: point1.x,
  63. y: point1.y
  64. }, {
  65. x: point2.x,
  66. y: point2.y
  67. }],
  68. center: {
  69. x: (point1.x + point2.x) / 2,
  70. y: (point1.y + point2.y) / 2
  71. }
  72. };
  73. //还原i值
  74. i = (pointIndex + length - 1) % length;
  75. }
  76. return result;
  77. },
  78. /*
  79. * 计算平移线移动到顶点后的位置
  80. * @param points 顶点集合
  81. * @param panLines 平移线集合
  82. */
  83. getMovedPanLines: function(points, panLines, smoothFactor) {
  84. var result = {};
  85. Utils.each(points, function(point, index) {
  86. //当前平移线
  87. var currentPanLine = panLines[index],
  88. //平移线中点
  89. center = currentPanLine.center,
  90. //移动距离
  91. distance = {
  92. x: center.x - point.x,
  93. y: center.y - point.y
  94. };
  95. var currentResult = result[index] = {
  96. points: [],
  97. center: {
  98. x: point.x,
  99. y: point.y
  100. }
  101. };
  102. //计算控制点到顶点的距离, 并且应用平滑系数到距离上
  103. Utils.each(currentPanLine.points, function(controlPoint, index) {
  104. var moved = {
  105. x: controlPoint.x - distance.x,
  106. y: controlPoint.y - distance.y
  107. };
  108. var vertex = currentResult.center;
  109. var dx = moved.x - vertex.x;
  110. var dy = moved.y - vertex.y;
  111. moved.x = vertex.x + smoothFactor * dx;
  112. moved.y = vertex.y + smoothFactor * dy;
  113. currentResult.points.push(moved);
  114. });
  115. });
  116. return result;
  117. }
  118. };
  119. return require('../core/class').createClass('Curve', {
  120. base: require('./path'),
  121. mixins: [require('./pointcontainer')],
  122. constructor: function(points, isColse) {
  123. this.callBase();
  124. this.setPoints(points || []);
  125. this.closeState = !!isColse;
  126. this.changeable = true;
  127. this.smoothFactor = 1;
  128. this.update();
  129. },
  130. //当点集合发生变化时采取的动作
  131. onContainerChanged: function() {
  132. if (this.changeable) {
  133. this.update();
  134. }
  135. },
  136. setSmoothFactor: function(factor) {
  137. this.smoothFactor = factor < 0 ? 0 : factor;
  138. this.update();
  139. return this;
  140. },
  141. getSmoothFactor: function() {
  142. return this.smoothFactor;
  143. },
  144. update: function() {
  145. var points = this.getPoints(),
  146. withControlPoints = null,
  147. drawer = this.getDrawer(),
  148. curPoint = null,
  149. curControlPoint = null,
  150. prevControlPoint = null;
  151. drawer.clear();
  152. if (points.length === 0) {
  153. return this;
  154. } else {
  155. drawer.moveTo(points[0]);
  156. }
  157. if (points.length === 1) {
  158. return this;
  159. }
  160. if (points.length === 2) {
  161. drawer.lineTo(points[1]);
  162. return this;
  163. }
  164. //获取已转换过后的带控制点的所有点
  165. withControlPoints = CurveUtil.getCurvePanLines(points, this.getSmoothFactor());
  166. for (var i = 1, len = points.length; i < len; i++) {
  167. //当前顶点
  168. curPoint = withControlPoints[i].center;
  169. //当前控制点
  170. if (this.closeState || i != len - 1) {
  171. curControlPoint = withControlPoints[i].points[0];
  172. } else {
  173. //非闭合状态下最后一个点的处理
  174. curControlPoint = withControlPoints[i].center;
  175. }
  176. if (this.closeState || i != 1) {
  177. prevControlPoint = withControlPoints[i - 1].points[1];
  178. } else {
  179. //非闭合状态下第一个点的处理
  180. prevControlPoint = withControlPoints[i - 1].center;
  181. }
  182. drawer.bezierTo(prevControlPoint.x, prevControlPoint.y,
  183. curControlPoint.x, curControlPoint.y, curPoint.x, curPoint.y);
  184. }
  185. //处理闭合
  186. if (this.closeState) {
  187. curPoint = withControlPoints[0].center;
  188. curControlPoint = withControlPoints[0].points[0];
  189. prevControlPoint = withControlPoints[points.length - 1].points[1];
  190. drawer.bezierTo(prevControlPoint.x, prevControlPoint.y,
  191. curControlPoint.x, curControlPoint.y, curPoint.x, curPoint.y);
  192. }
  193. return this;
  194. },
  195. close: function() {
  196. this.closeState = true;
  197. return this.update();
  198. },
  199. open: function() {
  200. this.closeState = false;
  201. return this.update();
  202. },
  203. isClose: function() {
  204. return !!this.closeState;
  205. }
  206. });
  207. });