Draw.html 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-draw-Draw'>/**
  19. </span> * @class Ext.draw.Draw
  20. * Base Drawing class. Provides base drawing functions.
  21. * @private
  22. */
  23. Ext.define('Ext.draw.Draw', {
  24. /* Begin Definitions */
  25. singleton: true,
  26. requires: ['Ext.draw.Color'],
  27. /* End Definitions */
  28. pathToStringRE: /,?([achlmqrstvxz]),?/gi,
  29. pathCommandRE: /([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig,
  30. pathValuesRE: /(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig,
  31. stopsRE: /^(\d+%?)$/,
  32. radian: Math.PI / 180,
  33. availableAnimAttrs: {
  34. along: &quot;along&quot;,
  35. blur: null,
  36. &quot;clip-rect&quot;: &quot;csv&quot;,
  37. cx: null,
  38. cy: null,
  39. fill: &quot;color&quot;,
  40. &quot;fill-opacity&quot;: null,
  41. &quot;font-size&quot;: null,
  42. height: null,
  43. opacity: null,
  44. path: &quot;path&quot;,
  45. r: null,
  46. rotation: &quot;csv&quot;,
  47. rx: null,
  48. ry: null,
  49. scale: &quot;csv&quot;,
  50. stroke: &quot;color&quot;,
  51. &quot;stroke-opacity&quot;: null,
  52. &quot;stroke-width&quot;: null,
  53. translation: &quot;csv&quot;,
  54. width: null,
  55. x: null,
  56. y: null
  57. },
  58. is: function(o, type) {
  59. type = String(type).toLowerCase();
  60. return (type == &quot;object&quot; &amp;&amp; o === Object(o)) ||
  61. (type == &quot;undefined&quot; &amp;&amp; typeof o == type) ||
  62. (type == &quot;null&quot; &amp;&amp; o === null) ||
  63. (type == &quot;array&quot; &amp;&amp; Array.isArray &amp;&amp; Array.isArray(o)) ||
  64. (Object.prototype.toString.call(o).toLowerCase().slice(8, -1)) == type;
  65. },
  66. ellipsePath: function(sprite) {
  67. var attr = sprite.attr;
  68. return Ext.String.format(&quot;M{0},{1}A{2},{3},0,1,1,{0},{4}A{2},{3},0,1,1,{0},{1}z&quot;, attr.x, attr.y - attr.ry, attr.rx, attr.ry, attr.y + attr.ry);
  69. },
  70. rectPath: function(sprite) {
  71. var attr = sprite.attr;
  72. if (attr.radius) {
  73. return Ext.String.format(&quot;M{0},{1}l{2},0a{3},{3},0,0,1,{3},{3}l0,{5}a{3},{3},0,0,1,{4},{3}l{6},0a{3},{3},0,0,1,{4},{4}l0,{7}a{3},{3},0,0,1,{3},{4}z&quot;, attr.x + attr.radius, attr.y, attr.width - attr.radius * 2, attr.radius, -attr.radius, attr.height - attr.radius * 2, attr.radius * 2 - attr.width, attr.radius * 2 - attr.height);
  74. }
  75. else {
  76. return Ext.String.format(&quot;M{0},{1}L{2},{1},{2},{3},{0},{3}z&quot;, attr.x, attr.y, attr.width + attr.x, attr.height + attr.y);
  77. }
  78. },
  79. // To be deprecated, converts itself (an arrayPath) to a proper SVG path string
  80. path2string: function () {
  81. return this.join(&quot;,&quot;).replace(Ext.draw.Draw.pathToStringRE, &quot;$1&quot;);
  82. },
  83. // Convert the passed arrayPath to a proper SVG path string (d attribute)
  84. pathToString: function(arrayPath) {
  85. return arrayPath.join(&quot;,&quot;).replace(Ext.draw.Draw.pathToStringRE, &quot;$1&quot;);
  86. },
  87. parsePathString: function (pathString) {
  88. if (!pathString) {
  89. return null;
  90. }
  91. var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0},
  92. data = [],
  93. me = this;
  94. if (me.is(pathString, &quot;array&quot;) &amp;&amp; me.is(pathString[0], &quot;array&quot;)) { // rough assumption
  95. data = me.pathClone(pathString);
  96. }
  97. if (!data.length) {
  98. String(pathString).replace(me.pathCommandRE, function (a, b, c) {
  99. var params = [],
  100. name = b.toLowerCase();
  101. c.replace(me.pathValuesRE, function (a, b) {
  102. b &amp;&amp; params.push(+b);
  103. });
  104. if (name == &quot;m&quot; &amp;&amp; params.length &gt; 2) {
  105. data.push([b].concat(Ext.Array.splice(params, 0, 2)));
  106. name = &quot;l&quot;;
  107. b = (b == &quot;m&quot;) ? &quot;l&quot; : &quot;L&quot;;
  108. }
  109. while (params.length &gt;= paramCounts[name]) {
  110. data.push([b].concat(Ext.Array.splice(params, 0, paramCounts[name])));
  111. if (!paramCounts[name]) {
  112. break;
  113. }
  114. }
  115. });
  116. }
  117. data.toString = me.path2string;
  118. return data;
  119. },
  120. mapPath: function (path, matrix) {
  121. if (!matrix) {
  122. return path;
  123. }
  124. var x, y, i, ii, j, jj, pathi;
  125. path = this.path2curve(path);
  126. for (i = 0, ii = path.length; i &lt; ii; i++) {
  127. pathi = path[i];
  128. for (j = 1, jj = pathi.length; j &lt; jj-1; j += 2) {
  129. x = matrix.x(pathi[j], pathi[j + 1]);
  130. y = matrix.y(pathi[j], pathi[j + 1]);
  131. pathi[j] = x;
  132. pathi[j + 1] = y;
  133. }
  134. }
  135. return path;
  136. },
  137. pathClone: function(pathArray) {
  138. var res = [],
  139. j, jj, i, ii;
  140. if (!this.is(pathArray, &quot;array&quot;) || !this.is(pathArray &amp;&amp; pathArray[0], &quot;array&quot;)) { // rough assumption
  141. pathArray = this.parsePathString(pathArray);
  142. }
  143. for (i = 0, ii = pathArray.length; i &lt; ii; i++) {
  144. res[i] = [];
  145. for (j = 0, jj = pathArray[i].length; j &lt; jj; j++) {
  146. res[i][j] = pathArray[i][j];
  147. }
  148. }
  149. res.toString = this.path2string;
  150. return res;
  151. },
  152. pathToAbsolute: function (pathArray) {
  153. if (!this.is(pathArray, &quot;array&quot;) || !this.is(pathArray &amp;&amp; pathArray[0], &quot;array&quot;)) { // rough assumption
  154. pathArray = this.parsePathString(pathArray);
  155. }
  156. var res = [],
  157. x = 0,
  158. y = 0,
  159. mx = 0,
  160. my = 0,
  161. i = 0,
  162. ln = pathArray.length,
  163. r, pathSegment, j, ln2;
  164. // MoveTo initial x/y position
  165. if (ln &amp;&amp; pathArray[0][0] == &quot;M&quot;) {
  166. x = +pathArray[0][1];
  167. y = +pathArray[0][2];
  168. mx = x;
  169. my = y;
  170. i++;
  171. res[0] = [&quot;M&quot;, x, y];
  172. }
  173. for (; i &lt; ln; i++) {
  174. r = res[i] = [];
  175. pathSegment = pathArray[i];
  176. if (pathSegment[0] != pathSegment[0].toUpperCase()) {
  177. r[0] = pathSegment[0].toUpperCase();
  178. switch (r[0]) {
  179. // Elliptical Arc
  180. case &quot;A&quot;:
  181. r[1] = pathSegment[1];
  182. r[2] = pathSegment[2];
  183. r[3] = pathSegment[3];
  184. r[4] = pathSegment[4];
  185. r[5] = pathSegment[5];
  186. r[6] = +(pathSegment[6] + x);
  187. r[7] = +(pathSegment[7] + y);
  188. break;
  189. // Vertical LineTo
  190. case &quot;V&quot;:
  191. r[1] = +pathSegment[1] + y;
  192. break;
  193. // Horizontal LineTo
  194. case &quot;H&quot;:
  195. r[1] = +pathSegment[1] + x;
  196. break;
  197. case &quot;M&quot;:
  198. // MoveTo
  199. mx = +pathSegment[1] + x;
  200. my = +pathSegment[2] + y;
  201. default:
  202. j = 1;
  203. ln2 = pathSegment.length;
  204. for (; j &lt; ln2; j++) {
  205. r[j] = +pathSegment[j] + ((j % 2) ? x : y);
  206. }
  207. }
  208. }
  209. else {
  210. j = 0;
  211. ln2 = pathSegment.length;
  212. for (; j &lt; ln2; j++) {
  213. res[i][j] = pathSegment[j];
  214. }
  215. }
  216. switch (r[0]) {
  217. // ClosePath
  218. case &quot;Z&quot;:
  219. x = mx;
  220. y = my;
  221. break;
  222. // Horizontal LineTo
  223. case &quot;H&quot;:
  224. x = r[1];
  225. break;
  226. // Vertical LineTo
  227. case &quot;V&quot;:
  228. y = r[1];
  229. break;
  230. // MoveTo
  231. case &quot;M&quot;:
  232. pathSegment = res[i];
  233. ln2 = pathSegment.length;
  234. mx = pathSegment[ln2 - 2];
  235. my = pathSegment[ln2 - 1];
  236. default:
  237. pathSegment = res[i];
  238. ln2 = pathSegment.length;
  239. x = pathSegment[ln2 - 2];
  240. y = pathSegment[ln2 - 1];
  241. }
  242. }
  243. res.toString = this.path2string;
  244. return res;
  245. },
  246. // TO BE DEPRECATED
  247. pathToRelative: function (pathArray) {
  248. if (!this.is(pathArray, &quot;array&quot;) || !this.is(pathArray &amp;&amp; pathArray[0], &quot;array&quot;)) {
  249. pathArray = this.parsePathString(pathArray);
  250. }
  251. var res = [],
  252. x = 0,
  253. y = 0,
  254. mx = 0,
  255. my = 0,
  256. start = 0,
  257. r,
  258. pa,
  259. i,
  260. j,
  261. k,
  262. len,
  263. ii,
  264. jj,
  265. kk;
  266. if (pathArray[0][0] == &quot;M&quot;) {
  267. x = pathArray[0][1];
  268. y = pathArray[0][2];
  269. mx = x;
  270. my = y;
  271. start++;
  272. res.push([&quot;M&quot;, x, y]);
  273. }
  274. for (i = start, ii = pathArray.length; i &lt; ii; i++) {
  275. r = res[i] = [];
  276. pa = pathArray[i];
  277. if (pa[0] != pa[0].toLowerCase()) {
  278. r[0] = pa[0].toLowerCase();
  279. switch (r[0]) {
  280. case &quot;a&quot;:
  281. r[1] = pa[1];
  282. r[2] = pa[2];
  283. r[3] = pa[3];
  284. r[4] = pa[4];
  285. r[5] = pa[5];
  286. r[6] = +(pa[6] - x).toFixed(3);
  287. r[7] = +(pa[7] - y).toFixed(3);
  288. break;
  289. case &quot;v&quot;:
  290. r[1] = +(pa[1] - y).toFixed(3);
  291. break;
  292. case &quot;m&quot;:
  293. mx = pa[1];
  294. my = pa[2];
  295. default:
  296. for (j = 1, jj = pa.length; j &lt; jj; j++) {
  297. r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
  298. }
  299. }
  300. } else {
  301. r = res[i] = [];
  302. if (pa[0] == &quot;m&quot;) {
  303. mx = pa[1] + x;
  304. my = pa[2] + y;
  305. }
  306. for (k = 0, kk = pa.length; k &lt; kk; k++) {
  307. res[i][k] = pa[k];
  308. }
  309. }
  310. len = res[i].length;
  311. switch (res[i][0]) {
  312. case &quot;z&quot;:
  313. x = mx;
  314. y = my;
  315. break;
  316. case &quot;h&quot;:
  317. x += +res[i][len - 1];
  318. break;
  319. case &quot;v&quot;:
  320. y += +res[i][len - 1];
  321. break;
  322. default:
  323. x += +res[i][len - 2];
  324. y += +res[i][len - 1];
  325. }
  326. }
  327. res.toString = this.path2string;
  328. return res;
  329. },
  330. // Returns a path converted to a set of curveto commands
  331. path2curve: function (path) {
  332. var me = this,
  333. points = me.pathToAbsolute(path),
  334. ln = points.length,
  335. attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
  336. i, seg, segLn, point;
  337. for (i = 0; i &lt; ln; i++) {
  338. points[i] = me.command2curve(points[i], attrs);
  339. if (points[i].length &gt; 7) {
  340. points[i].shift();
  341. point = points[i];
  342. while (point.length) {
  343. Ext.Array.splice(points, i++, 0, [&quot;C&quot;].concat(Ext.Array.splice(point, 0, 6)));
  344. }
  345. Ext.Array.erase(points, i, 1);
  346. ln = points.length;
  347. i--;
  348. }
  349. seg = points[i];
  350. segLn = seg.length;
  351. attrs.x = seg[segLn - 2];
  352. attrs.y = seg[segLn - 1];
  353. attrs.bx = parseFloat(seg[segLn - 4]) || attrs.x;
  354. attrs.by = parseFloat(seg[segLn - 3]) || attrs.y;
  355. }
  356. return points;
  357. },
  358. interpolatePaths: function (path, path2) {
  359. var me = this,
  360. p = me.pathToAbsolute(path),
  361. p2 = me.pathToAbsolute(path2),
  362. attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
  363. attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
  364. fixArc = function (pp, i) {
  365. if (pp[i].length &gt; 7) {
  366. pp[i].shift();
  367. var pi = pp[i];
  368. while (pi.length) {
  369. Ext.Array.splice(pp, i++, 0, [&quot;C&quot;].concat(Ext.Array.splice(pi, 0, 6)));
  370. }
  371. Ext.Array.erase(pp, i, 1);
  372. ii = Math.max(p.length, p2.length || 0);
  373. }
  374. },
  375. fixM = function (path1, path2, a1, a2, i) {
  376. if (path1 &amp;&amp; path2 &amp;&amp; path1[i][0] == &quot;M&quot; &amp;&amp; path2[i][0] != &quot;M&quot;) {
  377. Ext.Array.splice(path2, i, 0, [&quot;M&quot;, a2.x, a2.y]);
  378. a1.bx = 0;
  379. a1.by = 0;
  380. a1.x = path1[i][1];
  381. a1.y = path1[i][2];
  382. ii = Math.max(p.length, p2.length || 0);
  383. }
  384. },
  385. i, ii,
  386. seg, seg2, seglen, seg2len;
  387. for (i = 0, ii = Math.max(p.length, p2.length || 0); i &lt; ii; i++) {
  388. p[i] = me.command2curve(p[i], attrs);
  389. fixArc(p, i);
  390. (p2[i] = me.command2curve(p2[i], attrs2));
  391. fixArc(p2, i);
  392. fixM(p, p2, attrs, attrs2, i);
  393. fixM(p2, p, attrs2, attrs, i);
  394. seg = p[i];
  395. seg2 = p2[i];
  396. seglen = seg.length;
  397. seg2len = seg2.length;
  398. attrs.x = seg[seglen - 2];
  399. attrs.y = seg[seglen - 1];
  400. attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x;
  401. attrs.by = parseFloat(seg[seglen - 3]) || attrs.y;
  402. attrs2.bx = (parseFloat(seg2[seg2len - 4]) || attrs2.x);
  403. attrs2.by = (parseFloat(seg2[seg2len - 3]) || attrs2.y);
  404. attrs2.x = seg2[seg2len - 2];
  405. attrs2.y = seg2[seg2len - 1];
  406. }
  407. return [p, p2];
  408. },
  409. //Returns any path command as a curveto command based on the attrs passed
  410. command2curve: function (pathCommand, d) {
  411. var me = this;
  412. if (!pathCommand) {
  413. return [&quot;C&quot;, d.x, d.y, d.x, d.y, d.x, d.y];
  414. }
  415. if (pathCommand[0] != &quot;T&quot; &amp;&amp; pathCommand[0] != &quot;Q&quot;) {
  416. d.qx = d.qy = null;
  417. }
  418. switch (pathCommand[0]) {
  419. case &quot;M&quot;:
  420. d.X = pathCommand[1];
  421. d.Y = pathCommand[2];
  422. break;
  423. case &quot;A&quot;:
  424. pathCommand = [&quot;C&quot;].concat(me.arc2curve.apply(me, [d.x, d.y].concat(pathCommand.slice(1))));
  425. break;
  426. case &quot;S&quot;:
  427. pathCommand = [&quot;C&quot;, d.x + (d.x - (d.bx || d.x)), d.y + (d.y - (d.by || d.y))].concat(pathCommand.slice(1));
  428. break;
  429. case &quot;T&quot;:
  430. d.qx = d.x + (d.x - (d.qx || d.x));
  431. d.qy = d.y + (d.y - (d.qy || d.y));
  432. pathCommand = [&quot;C&quot;].concat(me.quadratic2curve(d.x, d.y, d.qx, d.qy, pathCommand[1], pathCommand[2]));
  433. break;
  434. case &quot;Q&quot;:
  435. d.qx = pathCommand[1];
  436. d.qy = pathCommand[2];
  437. pathCommand = [&quot;C&quot;].concat(me.quadratic2curve(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[3], pathCommand[4]));
  438. break;
  439. case &quot;L&quot;:
  440. pathCommand = [&quot;C&quot;].concat(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[1], pathCommand[2]);
  441. break;
  442. case &quot;H&quot;:
  443. pathCommand = [&quot;C&quot;].concat(d.x, d.y, pathCommand[1], d.y, pathCommand[1], d.y);
  444. break;
  445. case &quot;V&quot;:
  446. pathCommand = [&quot;C&quot;].concat(d.x, d.y, d.x, pathCommand[1], d.x, pathCommand[1]);
  447. break;
  448. case &quot;Z&quot;:
  449. pathCommand = [&quot;C&quot;].concat(d.x, d.y, d.X, d.Y, d.X, d.Y);
  450. break;
  451. }
  452. return pathCommand;
  453. },
  454. quadratic2curve: function (x1, y1, ax, ay, x2, y2) {
  455. var _13 = 1 / 3,
  456. _23 = 2 / 3;
  457. return [
  458. _13 * x1 + _23 * ax,
  459. _13 * y1 + _23 * ay,
  460. _13 * x2 + _23 * ax,
  461. _13 * y2 + _23 * ay,
  462. x2,
  463. y2
  464. ];
  465. },
  466. rotate: function (x, y, rad) {
  467. var cos = Math.cos(rad),
  468. sin = Math.sin(rad),
  469. X = x * cos - y * sin,
  470. Y = x * sin + y * cos;
  471. return {x: X, y: Y};
  472. },
  473. arc2curve: function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
  474. // for more information of where this Math came from visit:
  475. // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
  476. var me = this,
  477. PI = Math.PI,
  478. radian = me.radian,
  479. _120 = PI * 120 / 180,
  480. rad = radian * (+angle || 0),
  481. res = [],
  482. math = Math,
  483. mcos = math.cos,
  484. msin = math.sin,
  485. msqrt = math.sqrt,
  486. mabs = math.abs,
  487. masin = math.asin,
  488. xy, cos, sin, x, y, h, rx2, ry2, k, cx, cy, f1, f2, df, c1, s1, c2, s2,
  489. t, hx, hy, m1, m2, m3, m4, newres, i, ln, f2old, x2old, y2old;
  490. if (!recursive) {
  491. xy = me.rotate(x1, y1, -rad);
  492. x1 = xy.x;
  493. y1 = xy.y;
  494. xy = me.rotate(x2, y2, -rad);
  495. x2 = xy.x;
  496. y2 = xy.y;
  497. cos = mcos(radian * angle);
  498. sin = msin(radian * angle);
  499. x = (x1 - x2) / 2;
  500. y = (y1 - y2) / 2;
  501. h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
  502. if (h &gt; 1) {
  503. h = msqrt(h);
  504. rx = h * rx;
  505. ry = h * ry;
  506. }
  507. rx2 = rx * rx;
  508. ry2 = ry * ry;
  509. k = (large_arc_flag == sweep_flag ? -1 : 1) *
  510. msqrt(mabs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x)));
  511. cx = k * rx * y / ry + (x1 + x2) / 2;
  512. cy = k * -ry * x / rx + (y1 + y2) / 2;
  513. f1 = masin(((y1 - cy) / ry).toFixed(7));
  514. f2 = masin(((y2 - cy) / ry).toFixed(7));
  515. f1 = x1 &lt; cx ? PI - f1 : f1;
  516. f2 = x2 &lt; cx ? PI - f2 : f2;
  517. if (f1 &lt; 0) {
  518. f1 = PI * 2 + f1;
  519. }
  520. if (f2 &lt; 0) {
  521. f2 = PI * 2 + f2;
  522. }
  523. if (sweep_flag &amp;&amp; f1 &gt; f2) {
  524. f1 = f1 - PI * 2;
  525. }
  526. if (!sweep_flag &amp;&amp; f2 &gt; f1) {
  527. f2 = f2 - PI * 2;
  528. }
  529. }
  530. else {
  531. f1 = recursive[0];
  532. f2 = recursive[1];
  533. cx = recursive[2];
  534. cy = recursive[3];
  535. }
  536. df = f2 - f1;
  537. if (mabs(df) &gt; _120) {
  538. f2old = f2;
  539. x2old = x2;
  540. y2old = y2;
  541. f2 = f1 + _120 * (sweep_flag &amp;&amp; f2 &gt; f1 ? 1 : -1);
  542. x2 = cx + rx * mcos(f2);
  543. y2 = cy + ry * msin(f2);
  544. res = me.arc2curve(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
  545. }
  546. df = f2 - f1;
  547. c1 = mcos(f1);
  548. s1 = msin(f1);
  549. c2 = mcos(f2);
  550. s2 = msin(f2);
  551. t = math.tan(df / 4);
  552. hx = 4 / 3 * rx * t;
  553. hy = 4 / 3 * ry * t;
  554. m1 = [x1, y1];
  555. m2 = [x1 + hx * s1, y1 - hy * c1];
  556. m3 = [x2 + hx * s2, y2 - hy * c2];
  557. m4 = [x2, y2];
  558. m2[0] = 2 * m1[0] - m2[0];
  559. m2[1] = 2 * m1[1] - m2[1];
  560. if (recursive) {
  561. return [m2, m3, m4].concat(res);
  562. }
  563. else {
  564. res = [m2, m3, m4].concat(res).join().split(&quot;,&quot;);
  565. newres = [];
  566. ln = res.length;
  567. for (i = 0; i &lt; ln; i++) {
  568. newres[i] = i % 2 ? me.rotate(res[i - 1], res[i], rad).y : me.rotate(res[i], res[i + 1], rad).x;
  569. }
  570. return newres;
  571. }
  572. },
  573. // TO BE DEPRECATED
  574. rotateAndTranslatePath: function (sprite) {
  575. var alpha = sprite.rotation.degrees,
  576. cx = sprite.rotation.x,
  577. cy = sprite.rotation.y,
  578. dx = sprite.translation.x,
  579. dy = sprite.translation.y,
  580. path,
  581. i,
  582. p,
  583. xy,
  584. j,
  585. res = [];
  586. if (!alpha &amp;&amp; !dx &amp;&amp; !dy) {
  587. return this.pathToAbsolute(sprite.attr.path);
  588. }
  589. dx = dx || 0;
  590. dy = dy || 0;
  591. path = this.pathToAbsolute(sprite.attr.path);
  592. for (i = path.length; i--;) {
  593. p = res[i] = path[i].slice();
  594. if (p[0] == &quot;A&quot;) {
  595. xy = this.rotatePoint(p[6], p[7], alpha, cx, cy);
  596. p[6] = xy.x + dx;
  597. p[7] = xy.y + dy;
  598. } else {
  599. j = 1;
  600. while (p[j + 1] != null) {
  601. xy = this.rotatePoint(p[j], p[j + 1], alpha, cx, cy);
  602. p[j] = xy.x + dx;
  603. p[j + 1] = xy.y + dy;
  604. j += 2;
  605. }
  606. }
  607. }
  608. return res;
  609. },
  610. // TO BE DEPRECATED
  611. rotatePoint: function (x, y, alpha, cx, cy) {
  612. if (!alpha) {
  613. return {
  614. x: x,
  615. y: y
  616. };
  617. }
  618. cx = cx || 0;
  619. cy = cy || 0;
  620. x = x - cx;
  621. y = y - cy;
  622. alpha = alpha * this.radian;
  623. var cos = Math.cos(alpha),
  624. sin = Math.sin(alpha);
  625. return {
  626. x: x * cos - y * sin + cx,
  627. y: x * sin + y * cos + cy
  628. };
  629. },
  630. pathDimensions: function (path) {
  631. if (!path || !(path + &quot;&quot;)) {
  632. return {x: 0, y: 0, width: 0, height: 0};
  633. }
  634. path = this.path2curve(path);
  635. var x = 0,
  636. y = 0,
  637. X = [],
  638. Y = [],
  639. i = 0,
  640. ln = path.length,
  641. p, xmin, ymin, dim;
  642. for (; i &lt; ln; i++) {
  643. p = path[i];
  644. if (p[0] == &quot;M&quot;) {
  645. x = p[1];
  646. y = p[2];
  647. X.push(x);
  648. Y.push(y);
  649. }
  650. else {
  651. dim = this.curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
  652. X = X.concat(dim.min.x, dim.max.x);
  653. Y = Y.concat(dim.min.y, dim.max.y);
  654. x = p[5];
  655. y = p[6];
  656. }
  657. }
  658. xmin = Math.min.apply(0, X);
  659. ymin = Math.min.apply(0, Y);
  660. return {
  661. x: xmin,
  662. y: ymin,
  663. path: path,
  664. width: Math.max.apply(0, X) - xmin,
  665. height: Math.max.apply(0, Y) - ymin
  666. };
  667. },
  668. intersectInside: function(path, cp1, cp2) {
  669. return (cp2[0] - cp1[0]) * (path[1] - cp1[1]) &gt; (cp2[1] - cp1[1]) * (path[0] - cp1[0]);
  670. },
  671. intersectIntersection: function(s, e, cp1, cp2) {
  672. var p = [],
  673. dcx = cp1[0] - cp2[0],
  674. dcy = cp1[1] - cp2[1],
  675. dpx = s[0] - e[0],
  676. dpy = s[1] - e[1],
  677. n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0],
  678. n2 = s[0] * e[1] - s[1] * e[0],
  679. n3 = 1 / (dcx * dpy - dcy * dpx);
  680. p[0] = (n1 * dpx - n2 * dcx) * n3;
  681. p[1] = (n1 * dpy - n2 * dcy) * n3;
  682. return p;
  683. },
  684. intersect: function(subjectPolygon, clipPolygon) {
  685. var me = this,
  686. i = 0,
  687. ln = clipPolygon.length,
  688. cp1 = clipPolygon[ln - 1],
  689. outputList = subjectPolygon,
  690. cp2, s, e, point, ln2, inputList, j;
  691. for (; i &lt; ln; ++i) {
  692. cp2 = clipPolygon[i];
  693. inputList = outputList;
  694. outputList = [];
  695. s = inputList[inputList.length - 1];
  696. j = 0;
  697. ln2 = inputList.length;
  698. for (; j &lt; ln2; j++) {
  699. e = inputList[j];
  700. if (me.intersectInside(e, cp1, cp2)) {
  701. if (!me.intersectInside(s, cp1, cp2)) {
  702. outputList.push(me.intersectIntersection(s, e, cp1, cp2));
  703. }
  704. outputList.push(e);
  705. }
  706. else if (me.intersectInside(s, cp1, cp2)) {
  707. outputList.push(me.intersectIntersection(s, e, cp1, cp2));
  708. }
  709. s = e;
  710. }
  711. cp1 = cp2;
  712. }
  713. return outputList;
  714. },
  715. bezier : function (a, b, c, d, x) {
  716. if (x === 0) {
  717. return a;
  718. }
  719. else if (x === 1) {
  720. return d;
  721. }
  722. var du = 1 - x,
  723. d3 = du * du * du,
  724. r = x / du;
  725. return d3 * (a + r * (3 * b + r * (3 * c + d * r)));
  726. },
  727. bezierDim : function (a, b, c, d) {
  728. var points = [], r,
  729. A, top, C, delta, bottom, s,
  730. min, max, i;
  731. // The min and max happens on boundary or b' == 0
  732. if (a + 3 * c == d + 3 * b) {
  733. r = a - b;
  734. r /= 2 * (a - b - b + c);
  735. if ( r &lt; 1 &amp;&amp; r &gt; 0) {
  736. points.push(r);
  737. }
  738. } else {
  739. // b'(x) / -3 = (a-3b+3c-d)x^2+ (-2a+4b-2c)x + (a-b)
  740. // delta = -4 (-b^2+a c+b c-c^2-a d+b d)
  741. A = a - 3 * b + 3 * c - d;
  742. top = 2 * (a - b - b + c);
  743. C = a - b;
  744. delta = top * top - 4 * A * C;
  745. bottom = A + A;
  746. if (delta === 0) {
  747. r = top / bottom;
  748. if (r &lt; 1 &amp;&amp; r &gt; 0) {
  749. points.push(r);
  750. }
  751. } else if (delta &gt; 0) {
  752. s = Math.sqrt(delta);
  753. r = (s + top) / bottom;
  754. if (r &lt; 1 &amp;&amp; r &gt; 0) {
  755. points.push(r);
  756. }
  757. r = (top - s) / bottom;
  758. if (r &lt; 1 &amp;&amp; r &gt; 0) {
  759. points.push(r);
  760. }
  761. }
  762. }
  763. min = Math.min(a, d);
  764. max = Math.max(a, d);
  765. for (i = 0; i &lt; points.length; i++) {
  766. min = Math.min(min, this.bezier(a, b, c, d, points[i]));
  767. max = Math.max(max, this.bezier(a, b, c, d, points[i]));
  768. }
  769. return [min, max];
  770. },
  771. curveDim: function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
  772. var x = this.bezierDim(p1x, c1x, c2x, p2x),
  773. y = this.bezierDim(p1y, c1y, c2y, p2y);
  774. return {
  775. min: {
  776. x: x[0],
  777. y: y[0]
  778. },
  779. max: {
  780. x: x[1],
  781. y: y[1]
  782. }
  783. };
  784. },
  785. <span id='Ext-draw-Draw-method-getAnchors'> /**
  786. </span> * @private
  787. *
  788. * Calculates bezier curve control anchor points for a particular point in a path, with a
  789. * smoothing curve applied. The smoothness of the curve is controlled by the 'value' parameter.
  790. * Note that this algorithm assumes that the line being smoothed is normalized going from left
  791. * to right; it makes special adjustments assuming this orientation.
  792. *
  793. * @param {Number} prevX X coordinate of the previous point in the path
  794. * @param {Number} prevY Y coordinate of the previous point in the path
  795. * @param {Number} curX X coordinate of the current point in the path
  796. * @param {Number} curY Y coordinate of the current point in the path
  797. * @param {Number} nextX X coordinate of the next point in the path
  798. * @param {Number} nextY Y coordinate of the next point in the path
  799. * @param {Number} value A value to control the smoothness of the curve; this is used to
  800. * divide the distance between points, so a value of 2 corresponds to
  801. * half the distance between points (a very smooth line) while higher values
  802. * result in less smooth curves. Defaults to 4.
  803. * @return {Object} Object containing x1, y1, x2, y2 bezier control anchor points; x1 and y1
  804. * are the control point for the curve toward the previous path point, and
  805. * x2 and y2 are the control point for the curve toward the next path point.
  806. */
  807. getAnchors: function (prevX, prevY, curX, curY, nextX, nextY, value) {
  808. value = value || 4;
  809. var M = Math,
  810. PI = M.PI,
  811. halfPI = PI / 2,
  812. abs = M.abs,
  813. sin = M.sin,
  814. cos = M.cos,
  815. atan = M.atan,
  816. control1Length, control2Length, control1Angle, control2Angle,
  817. control1X, control1Y, control2X, control2Y, alpha;
  818. // Find the length of each control anchor line, by dividing the horizontal distance
  819. // between points by the value parameter.
  820. control1Length = (curX - prevX) / value;
  821. control2Length = (nextX - curX) / value;
  822. // Determine the angle of each control anchor line. If the middle point is a vertical
  823. // turnaround then we force it to a flat horizontal angle to prevent the curve from
  824. // dipping above or below the middle point. Otherwise we use an angle that points
  825. // toward the previous/next target point.
  826. if ((curY &gt;= prevY &amp;&amp; curY &gt;= nextY) || (curY &lt;= prevY &amp;&amp; curY &lt;= nextY)) {
  827. control1Angle = control2Angle = halfPI;
  828. } else {
  829. control1Angle = atan((curX - prevX) / abs(curY - prevY));
  830. if (prevY &lt; curY) {
  831. control1Angle = PI - control1Angle;
  832. }
  833. control2Angle = atan((nextX - curX) / abs(curY - nextY));
  834. if (nextY &lt; curY) {
  835. control2Angle = PI - control2Angle;
  836. }
  837. }
  838. // Adjust the calculated angles so they point away from each other on the same line
  839. alpha = halfPI - ((control1Angle + control2Angle) % (PI * 2)) / 2;
  840. if (alpha &gt; halfPI) {
  841. alpha -= PI;
  842. }
  843. control1Angle += alpha;
  844. control2Angle += alpha;
  845. // Find the control anchor points from the angles and length
  846. control1X = curX - control1Length * sin(control1Angle);
  847. control1Y = curY + control1Length * cos(control1Angle);
  848. control2X = curX + control2Length * sin(control2Angle);
  849. control2Y = curY + control2Length * cos(control2Angle);
  850. // One last adjustment, make sure that no control anchor point extends vertically past
  851. // its target prev/next point, as that results in curves dipping above or below and
  852. // bending back strangely. If we find this happening we keep the control angle but
  853. // reduce the length of the control line so it stays within bounds.
  854. if ((curY &gt; prevY &amp;&amp; control1Y &lt; prevY) || (curY &lt; prevY &amp;&amp; control1Y &gt; prevY)) {
  855. control1X += abs(prevY - control1Y) * (control1X - curX) / (control1Y - curY);
  856. control1Y = prevY;
  857. }
  858. if ((curY &gt; nextY &amp;&amp; control2Y &lt; nextY) || (curY &lt; nextY &amp;&amp; control2Y &gt; nextY)) {
  859. control2X -= abs(nextY - control2Y) * (control2X - curX) / (control2Y - curY);
  860. control2Y = nextY;
  861. }
  862. return {
  863. x1: control1X,
  864. y1: control1Y,
  865. x2: control2X,
  866. y2: control2Y
  867. };
  868. },
  869. /* Smoothing function for a path. Converts a path into cubic beziers. Value defines the divider of the distance between points.
  870. * Defaults to a value of 4.
  871. */
  872. smooth: function (originalPath, value) {
  873. var path = this.path2curve(originalPath),
  874. newp = [path[0]],
  875. x = path[0][1],
  876. y = path[0][2],
  877. j,
  878. points,
  879. i = 1,
  880. ii = path.length,
  881. beg = 1,
  882. mx = x,
  883. my = y,
  884. cx = 0,
  885. cy = 0,
  886. pathi,
  887. pathil,
  888. pathim,
  889. pathiml,
  890. pathip,
  891. pathipl,
  892. begl;
  893. for (; i &lt; ii; i++) {
  894. pathi = path[i];
  895. pathil = pathi.length;
  896. pathim = path[i - 1];
  897. pathiml = pathim.length;
  898. pathip = path[i + 1];
  899. pathipl = pathip &amp;&amp; pathip.length;
  900. if (pathi[0] == &quot;M&quot;) {
  901. mx = pathi[1];
  902. my = pathi[2];
  903. j = i + 1;
  904. while (path[j][0] != &quot;C&quot;) {
  905. j++;
  906. }
  907. cx = path[j][5];
  908. cy = path[j][6];
  909. newp.push([&quot;M&quot;, mx, my]);
  910. beg = newp.length;
  911. x = mx;
  912. y = my;
  913. continue;
  914. }
  915. if (pathi[pathil - 2] == mx &amp;&amp; pathi[pathil - 1] == my &amp;&amp; (!pathip || pathip[0] == &quot;M&quot;)) {
  916. begl = newp[beg].length;
  917. points = this.getAnchors(pathim[pathiml - 2], pathim[pathiml - 1], mx, my, newp[beg][begl - 2], newp[beg][begl - 1], value);
  918. newp[beg][1] = points.x2;
  919. newp[beg][2] = points.y2;
  920. }
  921. else if (!pathip || pathip[0] == &quot;M&quot;) {
  922. points = {
  923. x1: pathi[pathil - 2],
  924. y1: pathi[pathil - 1]
  925. };
  926. } else {
  927. points = this.getAnchors(pathim[pathiml - 2], pathim[pathiml - 1], pathi[pathil - 2], pathi[pathil - 1], pathip[pathipl - 2], pathip[pathipl - 1], value);
  928. }
  929. newp.push([&quot;C&quot;, x, y, points.x1, points.y1, pathi[pathil - 2], pathi[pathil - 1]]);
  930. x = points.x2;
  931. y = points.y2;
  932. }
  933. return newp;
  934. },
  935. findDotAtSegment: function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
  936. var t1 = 1 - t;
  937. return {
  938. x: Math.pow(t1, 3) * p1x + Math.pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + Math.pow(t, 3) * p2x,
  939. y: Math.pow(t1, 3) * p1y + Math.pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + Math.pow(t, 3) * p2y
  940. };
  941. },
  942. <span id='Ext-draw-Draw-method-snapEnds'> /**
  943. </span> * @private
  944. */
  945. snapEnds: function (from, to, stepsMax, prettyNumbers) {
  946. if (Ext.isDate(from)) {
  947. return this.snapEndsByDate(from, to, stepsMax);
  948. }
  949. var step = (to - from) / stepsMax,
  950. level = Math.floor(Math.log(step) / Math.LN10) + 1,
  951. m = Math.pow(10, level),
  952. cur,
  953. modulo = Math.round((step % m) * Math.pow(10, 2 - level)),
  954. interval = [[0, 15], [20, 4], [30, 2], [40, 4], [50, 9], [60, 4], [70, 2], [80, 4], [100, 15]],
  955. stepCount = 0,
  956. value,
  957. weight,
  958. i,
  959. topValue,
  960. topWeight = 1e9,
  961. ln = interval.length;
  962. cur = from = Math.floor(from / m) * m;
  963. if(prettyNumbers){
  964. for (i = 0; i &lt; ln; i++) {
  965. value = interval[i][0];
  966. weight = (value - modulo) &lt; 0 ? 1e6 : (value - modulo) / interval[i][1];
  967. if (weight &lt; topWeight) {
  968. topValue = value;
  969. topWeight = weight;
  970. }
  971. }
  972. step = Math.floor(step * Math.pow(10, -level)) * Math.pow(10, level) + topValue * Math.pow(10, level - 2);
  973. while (cur &lt; to) {
  974. cur += step;
  975. stepCount++;
  976. }
  977. to = +cur.toFixed(10);
  978. }else{
  979. stepCount = stepsMax;
  980. }
  981. return {
  982. from: from,
  983. to: to,
  984. power: level,
  985. step: step,
  986. steps: stepCount
  987. };
  988. },
  989. <span id='Ext-draw-Draw-method-snapEndsByDate'> /**
  990. </span> * snapEndsByDate is a utility method to deduce an appropriate tick configuration for the data set of given
  991. * feature. Refer to {@link #snapEnds}.
  992. *
  993. * @param {Date} from The minimum value in the data
  994. * @param {Date} to The maximum value in the data
  995. * @param {Number} stepsMax The maximum number of ticks
  996. * @param {Boolean} lockEnds If true, the 'from' and 'to' parameters will be used as fixed end values
  997. * and will not be adjusted
  998. * @return {Object} The calculated step and ends info; properties are:
  999. * - from: The result start value, which may be lower than the original start value
  1000. * - to: The result end value, which may be higher than the original end value
  1001. * - step: The value size of each step
  1002. * - steps: The number of steps. NOTE: the steps may not divide the from/to range perfectly evenly;
  1003. * there may be a smaller distance between the last step and the end value than between prior
  1004. * steps, particularly when the `endsLocked` param is true. Therefore it is best to not use
  1005. * the `steps` result when finding the axis tick points, instead use the `step`, `to`, and
  1006. * `from` to find the correct point for each tick.
  1007. */
  1008. snapEndsByDate: function (from, to, stepsMax, lockEnds) {
  1009. var selectedStep = false,
  1010. scales = [
  1011. [Ext.Date.MILLI, [1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500]],
  1012. [Ext.Date.SECOND, [1, 2, 3, 5, 10, 15, 30]],
  1013. [Ext.Date.MINUTE, [1, 2, 3, 5, 10, 20, 30]],
  1014. [Ext.Date.HOUR, [1, 2, 3, 4, 6, 12]],
  1015. [Ext.Date.DAY, [1, 2, 3, 7, 14]],
  1016. [Ext.Date.MONTH, [1, 2, 3, 4, 6]]
  1017. ],
  1018. sLen = scales.length,
  1019. stop = false,
  1020. scale, j, yearDiff, s;
  1021. // Find the most desirable scale
  1022. for (s = 0; s &lt; sLen; s++) {
  1023. scale = scales[s];
  1024. if (!stop) {
  1025. for (j = 0; j &lt; scale[1].length; j++) {
  1026. if (to &lt; Ext.Date.add(from, scale[0], scale[1][j] * stepsMax)) {
  1027. selectedStep = [scale[0], scale[1][j]];
  1028. stop = true;
  1029. break;
  1030. }
  1031. }
  1032. }
  1033. }
  1034. if (!selectedStep) {
  1035. yearDiff = this.snapEnds(from.getFullYear(), to.getFullYear() + 1, stepsMax, lockEnds);
  1036. selectedStep = [Date.YEAR, Math.round(yearDiff.step)];
  1037. }
  1038. return this.snapEndsByDateAndStep(from, to, selectedStep, lockEnds);
  1039. },
  1040. <span id='Ext-draw-Draw-method-snapEndsByDateAndStep'> /**
  1041. </span> * snapEndsByDateAndStep is a utility method to deduce an appropriate tick configuration for the data set of given
  1042. * feature and specific step size.
  1043. * @param {Date} from The minimum value in the data
  1044. * @param {Date} to The maximum value in the data
  1045. * @param {Array} step An array with two components: The first is the unit of the step (day, month, year, etc). The second one is the number of units for the step (1, 2, etc.).
  1046. * @param {Boolean} lockEnds If true, the 'from' and 'to' parameters will be used as fixed end values
  1047. * and will not be adjusted
  1048. */
  1049. snapEndsByDateAndStep: function(from, to, step, lockEnds) {
  1050. var fromStat = [from.getFullYear(), from.getMonth(), from.getDate(),
  1051. from.getHours(), from.getMinutes(), from.getSeconds(), from.getMilliseconds()],
  1052. steps = 0, testFrom, testTo;
  1053. if (lockEnds) {
  1054. testFrom = from;
  1055. } else {
  1056. switch (step[0]) {
  1057. case Ext.Date.MILLI:
  1058. testFrom = new Date(fromStat[0], fromStat[1], fromStat[2], fromStat[3],
  1059. fromStat[4], fromStat[5], Math.floor(fromStat[6] / step[1]) * step[1]);
  1060. break;
  1061. case Ext.Date.SECOND:
  1062. testFrom = new Date(fromStat[0], fromStat[1], fromStat[2], fromStat[3],
  1063. fromStat[4], Math.floor(fromStat[5] / step[1]) * step[1], 0);
  1064. break;
  1065. case Ext.Date.MINUTE:
  1066. testFrom = new Date(fromStat[0], fromStat[1], fromStat[2], fromStat[3],
  1067. Math.floor(fromStat[4] / step[1]) * step[1], 0, 0);
  1068. break;
  1069. case Ext.Date.HOUR:
  1070. testFrom = new Date(fromStat[0], fromStat[1], fromStat[2],
  1071. Math.floor(fromStat[3] / step[1]) * step[1], 0, 0, 0);
  1072. break;
  1073. case Ext.Date.DAY:
  1074. testFrom = new Date(fromStat[0], fromStat[1],
  1075. Math.floor(fromStat[2] - 1 / step[1]) * step[1] + 1, 0, 0, 0, 0);
  1076. break;
  1077. case Ext.Date.MONTH:
  1078. testFrom = new Date(fromStat[0], Math.floor(fromStat[1] / step[1]) * step[1], 1, 0, 0, 0, 0);
  1079. break;
  1080. default: // Ext.Date.YEAR
  1081. testFrom = new Date(Math.floor(fromStat[0] / step[1]) * step[1], 0, 1, 0, 0, 0, 0);
  1082. break;
  1083. }
  1084. }
  1085. testTo = testFrom;
  1086. // TODO(zhangbei) : We can do it better somehow...
  1087. while (testTo &lt; to) {
  1088. testTo = Ext.Date.add(testTo, step[0], step[1]);
  1089. steps++;
  1090. }
  1091. if (lockEnds) {
  1092. testTo = to;
  1093. }
  1094. return {
  1095. from : +testFrom,
  1096. to : +testTo,
  1097. step : (testTo - testFrom) / steps,
  1098. steps : steps
  1099. };
  1100. },
  1101. sorter: function (a, b) {
  1102. return a.offset - b.offset;
  1103. },
  1104. rad: function(degrees) {
  1105. return degrees % 360 * Math.PI / 180;
  1106. },
  1107. degrees: function(radian) {
  1108. return radian * 180 / Math.PI % 360;
  1109. },
  1110. withinBox: function(x, y, bbox) {
  1111. bbox = bbox || {};
  1112. return (x &gt;= bbox.x &amp;&amp; x &lt;= (bbox.x + bbox.width) &amp;&amp; y &gt;= bbox.y &amp;&amp; y &lt;= (bbox.y + bbox.height));
  1113. },
  1114. parseGradient: function(gradient) {
  1115. var me = this,
  1116. type = gradient.type || 'linear',
  1117. angle = gradient.angle || 0,
  1118. radian = me.radian,
  1119. stops = gradient.stops,
  1120. stopsArr = [],
  1121. stop,
  1122. vector,
  1123. max,
  1124. stopObj;
  1125. if (type == 'linear') {
  1126. vector = [0, 0, Math.cos(angle * radian), Math.sin(angle * radian)];
  1127. max = 1 / (Math.max(Math.abs(vector[2]), Math.abs(vector[3])) || 1);
  1128. vector[2] *= max;
  1129. vector[3] *= max;
  1130. if (vector[2] &lt; 0) {
  1131. vector[0] = -vector[2];
  1132. vector[2] = 0;
  1133. }
  1134. if (vector[3] &lt; 0) {
  1135. vector[1] = -vector[3];
  1136. vector[3] = 0;
  1137. }
  1138. }
  1139. for (stop in stops) {
  1140. if (stops.hasOwnProperty(stop) &amp;&amp; me.stopsRE.test(stop)) {
  1141. stopObj = {
  1142. offset: parseInt(stop, 10),
  1143. color: Ext.draw.Color.toHex(stops[stop].color) || '#ffffff',
  1144. opacity: stops[stop].opacity || 1
  1145. };
  1146. stopsArr.push(stopObj);
  1147. }
  1148. }
  1149. // Sort by pct property
  1150. Ext.Array.sort(stopsArr, me.sorter);
  1151. if (type == 'linear') {
  1152. return {
  1153. id: gradient.id,
  1154. type: type,
  1155. vector: vector,
  1156. stops: stopsArr
  1157. };
  1158. }
  1159. else {
  1160. return {
  1161. id: gradient.id,
  1162. type: type,
  1163. centerX: gradient.centerX,
  1164. centerY: gradient.centerY,
  1165. focalX: gradient.focalX,
  1166. focalY: gradient.focalY,
  1167. radius: gradient.radius,
  1168. vector: vector,
  1169. stops: stopsArr
  1170. };
  1171. }
  1172. }
  1173. });
  1174. </pre>
  1175. </body>
  1176. </html>