4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
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.
23 Ext.define('Ext.draw.Draw', {
24 /* Begin Definitions */
28 requires: ['Ext.draw.Color'],
32 pathToStringRE: /,?([achlmqrstvxz]),?/gi,
33 pathCommandRE: /([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig,
34 pathValuesRE: /(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig,
36 radian: Math.PI / 180,
39 along: "along",
41 "clip-rect": "csv",
44 fill: "color",
45 "fill-opacity": null,
46 "font-size": null,
49 path: "path",
51 rotation: "csv",
54 scale: "csv",
55 stroke: "color",
56 "stroke-opacity": null,
57 "stroke-width": null,
58 translation: "csv",
64 is: function(o, type) {
65 type = String(type).toLowerCase();
66 return (type == "object" && o === Object(o)) ||
67 (type == "undefined" && typeof o == type) ||
68 (type == "null" && o === null) ||
69 (type == "array" && Array.isArray && Array.isArray(o)) ||
70 (Object.prototype.toString.call(o).toLowerCase().slice(8, -1)) == type;
73 ellipsePath: function(sprite) {
74 var attr = sprite.attr;
75 return Ext.String.format("M{0},{1}A{2},{3},0,1,1,{0},{4}A{2},{3},0,1,1,{0},{1}z", attr.x, attr.y - attr.ry, attr.rx, attr.ry, attr.y + attr.ry);
78 rectPath: function(sprite) {
79 var attr = sprite.attr;
81 return Ext.String.format("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", 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);
84 return Ext.String.format("M{0},{1}l{2},0,0,{3},{4},0z", attr.x, attr.y, attr.width, attr.height, -attr.width);
88 // To be deprecated, converts itself (an arrayPath) to a proper SVG path string
89 path2string: function () {
90 return this.join(",").replace(Ext.draw.Draw.pathToStringRE, "$1");
93 // Convert the passed arrayPath to a proper SVG path string (d attribute)
94 pathToString: function(arrayPath) {
95 return arrayPath.join(",").replace(Ext.draw.Draw.pathToStringRE, "$1");
98 parsePathString: function (pathString) {
102 var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0},
105 if (me.is(pathString, "array") && me.is(pathString[0], "array")) { // rough assumption
106 data = me.pathClone(pathString);
109 String(pathString).replace(me.pathCommandRE, function (a, b, c) {
111 name = b.toLowerCase();
112 c.replace(me.pathValuesRE, function (a, b) {
113 b && params.push(+b);
115 if (name == "m" && params.length > 2) {
116 data.push([b].concat(Ext.Array.splice(params, 0, 2)));
117 name = "l";
118 b = (b == "m") ? "l" : "L";
120 while (params.length >= paramCounts[name]) {
121 data.push([b].concat(Ext.Array.splice(params, 0, paramCounts[name])));
122 if (!paramCounts[name]) {
128 data.toString = me.path2string;
132 mapPath: function (path, matrix) {
136 var x, y, i, ii, j, jj, pathi;
137 path = this.path2curve(path);
138 for (i = 0, ii = path.length; i < ii; i++) {
140 for (j = 1, jj = pathi.length; j < jj-1; j += 2) {
141 x = matrix.x(pathi[j], pathi[j + 1]);
142 y = matrix.y(pathi[j], pathi[j + 1]);
150 pathClone: function(pathArray) {
153 if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { // rough assumption
154 pathArray = this.parsePathString(pathArray);
156 for (i = 0, ii = pathArray.length; i < ii; i++) {
158 for (j = 0, jj = pathArray[i].length; j < jj; j++) {
159 res[i][j] = pathArray[i][j];
162 res.toString = this.path2string;
166 pathToAbsolute: function (pathArray) {
167 if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { // rough assumption
168 pathArray = this.parsePathString(pathArray);
176 ln = pathArray.length,
177 r, pathSegment, j, ln2;
178 // MoveTo initial x/y position
179 if (ln && pathArray[0][0] == "M") {
180 x = +pathArray[0][1];
181 y = +pathArray[0][2];
185 res[0] = ["M", x, y];
187 for (; i < ln; i++) {
189 pathSegment = pathArray[i];
190 if (pathSegment[0] != pathSegment[0].toUpperCase()) {
191 r[0] = pathSegment[0].toUpperCase();
195 r[1] = pathSegment[1];
196 r[2] = pathSegment[2];
197 r[3] = pathSegment[3];
198 r[4] = pathSegment[4];
199 r[5] = pathSegment[5];
200 r[6] = +(pathSegment[6] + x);
201 r[7] = +(pathSegment[7] + y);
205 r[1] = +pathSegment[1] + y;
209 r[1] = +pathSegment[1] + x;
213 mx = +pathSegment[1] + x;
214 my = +pathSegment[2] + y;
217 ln2 = pathSegment.length;
218 for (; j < ln2; j++) {
219 r[j] = +pathSegment[j] + ((j % 2) ? x : y);
225 ln2 = pathSegment.length;
226 for (; j < ln2; j++) {
227 res[i][j] = pathSegment[j];
246 pathSegment = res[i];
247 ln2 = pathSegment.length;
248 mx = pathSegment[ln2 - 2];
249 my = pathSegment[ln2 - 1];
251 pathSegment = res[i];
252 ln2 = pathSegment.length;
253 x = pathSegment[ln2 - 2];
254 y = pathSegment[ln2 - 1];
257 res.toString = this.path2string;
262 pathToRelative: function (pathArray) {
263 if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) {
264 pathArray = this.parsePathString(pathArray);
272 if (pathArray[0][0] == "M") {
278 res.push(["M", x, y]);
280 for (var i = start, ii = pathArray.length; i < ii; i++) {
283 if (pa[0] != pa[0].toLowerCase()) {
284 r[0] = pa[0].toLowerCase();
292 r[6] = +(pa[6] - x).toFixed(3);
293 r[7] = +(pa[7] - y).toFixed(3);
296 r[1] = +(pa[1] - y).toFixed(3);
302 for (var j = 1, jj = pa.length; j < jj; j++) {
303 r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
308 if (pa[0] == "m") {
312 for (var k = 0, kk = pa.length; k < kk; k++) {
316 var len = res[i].length;
323 x += +res[i][len - 1];
326 y += +res[i][len - 1];
329 x += +res[i][len - 2];
330 y += +res[i][len - 1];
333 res.toString = this.path2string;
337 // Returns a path converted to a set of curveto commands
338 path2curve: function (path) {
340 points = me.pathToAbsolute(path),
342 attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
343 i, seg, segLn, point;
345 for (i = 0; i < ln; i++) {
346 points[i] = me.command2curve(points[i], attrs);
347 if (points[i].length > 7) {
350 while (point.length) {
351 Ext.Array.splice(points, i++, 0, ["C"].concat(Ext.Array.splice(point, 0, 6)));
353 Ext.Array.erase(points, i, 1);
358 attrs.x = seg[segLn - 2];
359 attrs.y = seg[segLn - 1];
360 attrs.bx = parseFloat(seg[segLn - 4]) || attrs.x;
361 attrs.by = parseFloat(seg[segLn - 3]) || attrs.y;
366 interpolatePaths: function (path, path2) {
368 p = me.pathToAbsolute(path),
369 p2 = me.pathToAbsolute(path2),
370 attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
371 attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
372 fixArc = function (pp, i) {
373 if (pp[i].length > 7) {
377 Ext.Array.splice(pp, i++, 0, ["C"].concat(Ext.Array.splice(pi, 0, 6)));
379 Ext.Array.erase(pp, i, 1);
380 ii = Math.max(p.length, p2.length || 0);
383 fixM = function (path1, path2, a1, a2, i) {
384 if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
385 Ext.Array.splice(path2, i, 0, ["M", a2.x, a2.y]);
390 ii = Math.max(p.length, p2.length || 0);
393 for (var i = 0, ii = Math.max(p.length, p2.length || 0); i < ii; i++) {
394 p[i] = me.command2curve(p[i], attrs);
396 (p2[i] = me.command2curve(p2[i], attrs2));
398 fixM(p, p2, attrs, attrs2, i);
399 fixM(p2, p, attrs2, attrs, i);
403 seg2len = seg2.length;
404 attrs.x = seg[seglen - 2];
405 attrs.y = seg[seglen - 1];
406 attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x;
407 attrs.by = parseFloat(seg[seglen - 3]) || attrs.y;
408 attrs2.bx = (parseFloat(seg2[seg2len - 4]) || attrs2.x);
409 attrs2.by = (parseFloat(seg2[seg2len - 3]) || attrs2.y);
410 attrs2.x = seg2[seg2len - 2];
411 attrs2.y = seg2[seg2len - 1];
416 //Returns any path command as a curveto command based on the attrs passed
417 command2curve: function (pathCommand, d) {
420 return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
422 if (pathCommand[0] != "T" && pathCommand[0] != "Q") {
425 switch (pathCommand[0]) {
427 d.X = pathCommand[1];
428 d.Y = pathCommand[2];
431 pathCommand = ["C"].concat(me.arc2curve.apply(me, [d.x, d.y].concat(pathCommand.slice(1))));
434 pathCommand = ["C", d.x + (d.x - (d.bx || d.x)), d.y + (d.y - (d.by || d.y))].concat(pathCommand.slice(1));
437 d.qx = d.x + (d.x - (d.qx || d.x));
438 d.qy = d.y + (d.y - (d.qy || d.y));
439 pathCommand = ["C"].concat(me.quadratic2curve(d.x, d.y, d.qx, d.qy, pathCommand[1], pathCommand[2]));
442 d.qx = pathCommand[1];
443 d.qy = pathCommand[2];
444 pathCommand = ["C"].concat(me.quadratic2curve(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[3], pathCommand[4]));
447 pathCommand = ["C"].concat(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[1], pathCommand[2]);
450 pathCommand = ["C"].concat(d.x, d.y, pathCommand[1], d.y, pathCommand[1], d.y);
453 pathCommand = ["C"].concat(d.x, d.y, d.x, pathCommand[1], d.x, pathCommand[1]);
456 pathCommand = ["C"].concat(d.x, d.y, d.X, d.Y, d.X, d.Y);
462 quadratic2curve: function (x1, y1, ax, ay, x2, y2) {
475 rotate: function (x, y, rad) {
476 var cos = Math.cos(rad),
478 X = x * cos - y * sin,
479 Y = x * sin + y * cos;
483 arc2curve: function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
484 // for more information of where this Math came from visit:
485 // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
489 _120 = PI * 120 / 180,
490 rad = radian * (+angle || 0),
498 xy, cos, sin, x, y, h, rx2, ry2, k, cx, cy, f1, f2, df, c1, s1, c2, s2,
499 t, hx, hy, m1, m2, m3, m4, newres, i, ln, f2old, x2old, y2old;
501 xy = me.rotate(x1, y1, -rad);
504 xy = me.rotate(x2, y2, -rad);
507 cos = mcos(radian * angle);
508 sin = msin(radian * angle);
511 h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
519 k = (large_arc_flag == sweep_flag ? -1 : 1) *
520 msqrt(mabs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x)));
521 cx = k * rx * y / ry + (x1 + x2) / 2;
522 cy = k * -ry * x / rx + (y1 + y2) / 2;
523 f1 = masin(((y1 - cy) / ry).toFixed(7));
524 f2 = masin(((y2 - cy) / ry).toFixed(7));
526 f1 = x1 < cx ? PI - f1 : f1;
527 f2 = x2 < cx ? PI - f2 : f2;
534 if (sweep_flag && f1 > f2) {
537 if (!sweep_flag && f2 > f1) {
548 if (mabs(df) > _120) {
552 f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
553 x2 = cx + rx * mcos(f2);
554 y2 = cy + ry * msin(f2);
555 res = me.arc2curve(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
562 t = math.tan(df / 4);
566 m2 = [x1 + hx * s1, y1 - hy * c1];
567 m3 = [x2 + hx * s2, y2 - hy * c2];
569 m2[0] = 2 * m1[0] - m2[0];
570 m2[1] = 2 * m1[1] - m2[1];
572 return [m2, m3, m4].concat(res);
575 res = [m2, m3, m4].concat(res).join().split(",");
578 for (i = 0; i < ln; i++) {
579 newres[i] = i % 2 ? me.rotate(res[i - 1], res[i], rad).y : me.rotate(res[i], res[i + 1], rad).x;
586 rotateAndTranslatePath: function (sprite) {
587 var alpha = sprite.rotation.degrees,
588 cx = sprite.rotation.x,
589 cy = sprite.rotation.y,
590 dx = sprite.translation.x,
591 dy = sprite.translation.y,
598 if (!alpha && !dx && !dy) {
599 return this.pathToAbsolute(sprite.attr.path);
603 path = this.pathToAbsolute(sprite.attr.path);
604 for (i = path.length; i--;) {
605 p = res[i] = path[i].slice();
606 if (p[0] == "A") {
607 xy = this.rotatePoint(p[6], p[7], alpha, cx, cy);
612 while (p[j + 1] != null) {
613 xy = this.rotatePoint(p[j], p[j + 1], alpha, cx, cy);
615 p[j + 1] = xy.y + dy;
624 rotatePoint: function (x, y, alpha, cx, cy) {
635 alpha = alpha * this.radian;
636 var cos = Math.cos(alpha),
637 sin = Math.sin(alpha);
639 x: x * cos - y * sin + cx,
640 y: x * sin + y * cos + cy
644 pathDimensions: function (path) {
645 if (!path || !(path + "")) {
646 return {x: 0, y: 0, width: 0, height: 0};
648 path = this.path2curve(path);
656 for (; i < ln; i++) {
658 if (p[0] == "M") {
665 dim = this.curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
666 X = X.concat(dim.min.x, dim.max.x);
667 Y = Y.concat(dim.min.y, dim.max.y);
672 xmin = Math.min.apply(0, X);
673 ymin = Math.min.apply(0, Y);
678 width: Math.max.apply(0, X) - xmin,
679 height: Math.max.apply(0, Y) - ymin
683 intersectInside: function(path, cp1, cp2) {
684 return (cp2[0] - cp1[0]) * (path[1] - cp1[1]) > (cp2[1] - cp1[1]) * (path[0] - cp1[0]);
687 intersectIntersection: function(s, e, cp1, cp2) {
689 dcx = cp1[0] - cp2[0],
690 dcy = cp1[1] - cp2[1],
693 n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0],
694 n2 = s[0] * e[1] - s[1] * e[0],
695 n3 = 1 / (dcx * dpy - dcy * dpx);
697 p[0] = (n1 * dpx - n2 * dcx) * n3;
698 p[1] = (n1 * dpy - n2 * dcy) * n3;
702 intersect: function(subjectPolygon, clipPolygon) {
705 ln = clipPolygon.length,
706 cp1 = clipPolygon[ln - 1],
707 outputList = subjectPolygon,
708 cp2, s, e, point, ln2, inputList, j;
709 for (; i < ln; ++i) {
710 cp2 = clipPolygon[i];
711 inputList = outputList;
713 s = inputList[inputList.length - 1];
715 ln2 = inputList.length;
716 for (; j < ln2; j++) {
718 if (me.intersectInside(e, cp1, cp2)) {
719 if (!me.intersectInside(s, cp1, cp2)) {
720 outputList.push(me.intersectIntersection(s, e, cp1, cp2));
724 else if (me.intersectInside(s, cp1, cp2)) {
725 outputList.push(me.intersectIntersection(s, e, cp1, cp2));
734 curveDim: function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
735 var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
736 b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
738 t1 = (-b + Math.sqrt(b * b - 4 * a * c)) / 2 / a,
739 t2 = (-b - Math.sqrt(b * b - 4 * a * c)) / 2 / a,
743 if (Math.abs(t1) > 1e12) {
746 if (Math.abs(t2) > 1e12) {
749 if (t1 > 0 && t1 < 1) {
750 dot = this.findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
754 if (t2 > 0 && t2 < 1) {
755 dot = this.findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
759 a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
760 b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
762 t1 = (-b + Math.sqrt(b * b - 4 * a * c)) / 2 / a;
763 t2 = (-b - Math.sqrt(b * b - 4 * a * c)) / 2 / a;
764 if (Math.abs(t1) > 1e12) {
767 if (Math.abs(t2) > 1e12) {
770 if (t1 > 0 && t1 < 1) {
771 dot = this.findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
775 if (t2 > 0 && t2 < 1) {
776 dot = this.findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
781 min: {x: Math.min.apply(0, x), y: Math.min.apply(0, y)},
782 max: {x: Math.max.apply(0, x), y: Math.max.apply(0, y)}
786 <span id='Ext-draw-Draw-method-getAnchors'> /**
789 * Calculates bezier curve control anchor points for a particular point in a path, with a
790 * smoothing curve applied. The smoothness of the curve is controlled by the 'value' parameter.
791 * Note that this algorithm assumes that the line being smoothed is normalized going from left
792 * to right; it makes special adjustments assuming this orientation.
794 * @param {Number} prevX X coordinate of the previous point in the path
795 * @param {Number} prevY Y coordinate of the previous point in the path
796 * @param {Number} curX X coordinate of the current point in the path
797 * @param {Number} curY Y coordinate of the current point in the path
798 * @param {Number} nextX X coordinate of the next point in the path
799 * @param {Number} nextY Y coordinate of the next point in the path
800 * @param {Number} value A value to control the smoothness of the curve; this is used to
801 * divide the distance between points, so a value of 2 corresponds to
802 * half the distance between points (a very smooth line) while higher values
803 * result in less smooth curves. Defaults to 4.
804 * @return {Object} Object containing x1, y1, x2, y2 bezier control anchor points; x1 and y1
805 * are the control point for the curve toward the previous path point, and
806 * x2 and y2 are the control point for the curve toward the next path point.
808 getAnchors: function (prevX, prevY, curX, curY, nextX, nextY, value) {
817 control1Length, control2Length, control1Angle, control2Angle,
818 control1X, control1Y, control2X, control2Y, alpha;
820 // Find the length of each control anchor line, by dividing the horizontal distance
821 // between points by the value parameter.
822 control1Length = (curX - prevX) / value;
823 control2Length = (nextX - curX) / value;
825 // Determine the angle of each control anchor line. If the middle point is a vertical
826 // turnaround then we force it to a flat horizontal angle to prevent the curve from
827 // dipping above or below the middle point. Otherwise we use an angle that points
828 // toward the previous/next target point.
829 if ((curY >= prevY && curY >= nextY) || (curY <= prevY && curY <= nextY)) {
830 control1Angle = control2Angle = halfPI;
832 control1Angle = atan((curX - prevX) / abs(curY - prevY));
833 if (prevY < curY) {
834 control1Angle = PI - control1Angle;
836 control2Angle = atan((nextX - curX) / abs(curY - nextY));
837 if (nextY < curY) {
838 control2Angle = PI - control2Angle;
842 // Adjust the calculated angles so they point away from each other on the same line
843 alpha = halfPI - ((control1Angle + control2Angle) % (PI * 2)) / 2;
844 if (alpha > halfPI) {
847 control1Angle += alpha;
848 control2Angle += alpha;
850 // Find the control anchor points from the angles and length
851 control1X = curX - control1Length * sin(control1Angle);
852 control1Y = curY + control1Length * cos(control1Angle);
853 control2X = curX + control2Length * sin(control2Angle);
854 control2Y = curY + control2Length * cos(control2Angle);
856 // One last adjustment, make sure that no control anchor point extends vertically past
857 // its target prev/next point, as that results in curves dipping above or below and
858 // bending back strangely. If we find this happening we keep the control angle but
859 // reduce the length of the control line so it stays within bounds.
860 if ((curY > prevY && control1Y < prevY) || (curY < prevY && control1Y > prevY)) {
861 control1X += abs(prevY - control1Y) * (control1X - curX) / (control1Y - curY);
864 if ((curY > nextY && control2Y < nextY) || (curY < nextY && control2Y > nextY)) {
865 control2X -= abs(nextY - control2Y) * (control2X - curX) / (control2Y - curY);
877 /* Smoothing function for a path. Converts a path into cubic beziers. Value defines the divider of the distance between points.
878 * Defaults to a value of 4.
880 smooth: function (originalPath, value) {
881 var path = this.path2curve(originalPath),
894 for (; i < ii; i++) {
896 pathil = pathi.length,
897 pathim = path[i - 1],
898 pathiml = pathim.length,
899 pathip = path[i + 1],
900 pathipl = pathip && pathip.length;
901 if (pathi[0] == "M") {
905 while (path[j][0] != "C") {
910 newp.push(["M", mx, my]);
916 if (pathi[pathil - 2] == mx && pathi[pathil - 1] == my && (!pathip || pathip[0] == "M")) {
917 var begl = newp[beg].length;
918 points = this.getAnchors(pathim[pathiml - 2], pathim[pathiml - 1], mx, my, newp[beg][begl - 2], newp[beg][begl - 1], value);
919 newp[beg][1] = points.x2;
920 newp[beg][2] = points.y2;
922 else if (!pathip || pathip[0] == "M") {
924 x1: pathi[pathil - 2],
925 y1: pathi[pathil - 1]
928 points = this.getAnchors(pathim[pathiml - 2], pathim[pathiml - 1], pathi[pathil - 2], pathi[pathil - 1], pathip[pathipl - 2], pathip[pathipl - 1], value);
930 newp.push(["C", x, y, points.x1, points.y1, pathi[pathil - 2], pathi[pathil - 1]]);
937 findDotAtSegment: function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
940 x: Math.pow(t1, 3) * p1x + Math.pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + Math.pow(t, 3) * p2x,
941 y: Math.pow(t1, 3) * p1y + Math.pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + Math.pow(t, 3) * p2y
945 snapEnds: function (from, to, stepsMax) {
946 var step = (to - from) / stepsMax,
947 level = Math.floor(Math.log(step) / Math.LN10) + 1,
948 m = Math.pow(10, level),
950 modulo = Math.round((step % m) * Math.pow(10, 2 - level)),
951 interval = [[0, 15], [20, 4], [30, 2], [40, 4], [50, 9], [60, 4], [70, 2], [80, 4], [100, 15]],
958 ln = interval.length;
959 cur = from = Math.floor(from / m) * m;
960 for (i = 0; i < ln; i++) {
961 value = interval[i][0];
962 weight = (value - modulo) < 0 ? 1e6 : (value - modulo) / interval[i][1];
963 if (weight < topWeight) {
968 step = Math.floor(step * Math.pow(10, -level)) * Math.pow(10, level) + topValue * Math.pow(10, level - 2);
969 while (cur < to) {
973 to = +cur.toFixed(10);
983 sorter: function (a, b) {
984 return a.offset - b.offset;
987 rad: function(degrees) {
988 return degrees % 360 * Math.PI / 180;
991 degrees: function(radian) {
992 return radian * 180 / Math.PI % 360;
995 withinBox: function(x, y, bbox) {
997 return (x >= bbox.x && x <= (bbox.x + bbox.width) && y >= bbox.y && y <= (bbox.y + bbox.height));
1000 parseGradient: function(gradient) {
1002 type = gradient.type || 'linear',
1003 angle = gradient.angle || 0,
1005 stops = gradient.stops,
1012 if (type == 'linear') {
1013 vector = [0, 0, Math.cos(angle * radian), Math.sin(angle * radian)];
1014 max = 1 / (Math.max(Math.abs(vector[2]), Math.abs(vector[3])) || 1);
1017 if (vector[2] < 0) {
1018 vector[0] = -vector[2];
1021 if (vector[3] < 0) {
1022 vector[1] = -vector[3];
1027 for (stop in stops) {
1028 if (stops.hasOwnProperty(stop) && me.stopsRE.test(stop)) {
1030 offset: parseInt(stop, 10),
1031 color: Ext.draw.Color.toHex(stops[stop].color) || '#ffffff',
1032 opacity: stops[stop].opacity || 1
1034 stopsArr.push(stopObj);
1037 // Sort by pct property
1038 Ext.Array.sort(stopsArr, me.sorter);
1039 if (type == 'linear') {
1051 centerX: gradient.centerX,
1052 centerY: gradient.centerY,
1053 focalX: gradient.focalX,
1054 focalY: gradient.focalY,
1055 radius: gradient.radius,