--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>The source code</title>
+ <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="../prettify/prettify.js"></script>
+ <style type="text/css">
+ .highlight { display: block; background-color: #ddd; }
+ </style>
+ <script type="text/javascript">
+ function highlight() {
+ document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
+ }
+ </script>
+</head>
+<body onload="prettyPrint(); highlight();">
+ <pre class="prettyprint lang-js">/*
+ * @class Ext.draw.Draw
+ * Base Drawing class. Provides base drawing functions.
+ */
+
+Ext.define('Ext.draw.Draw', {
+ /* Begin Definitions */
+
+ singleton: true,
+
+ requires: ['Ext.draw.Color'],
+
+ /* End Definitions */
+
+ pathToStringRE: /,?([achlmqrstvxz]),?/gi,
+ pathCommandRE: /([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig,
+ pathValuesRE: /(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig,
+ stopsRE: /^(\d+%?)$/,
+ radian: Math.PI / 180,
+
+ availableAnimAttrs: {
+ along: "along",
+ blur: null,
+ "clip-rect": "csv",
+ cx: null,
+ cy: null,
+ fill: "color",
+ "fill-opacity": null,
+ "font-size": null,
+ height: null,
+ opacity: null,
+ path: "path",
+ r: null,
+ rotation: "csv",
+ rx: null,
+ ry: null,
+ scale: "csv",
+ stroke: "color",
+ "stroke-opacity": null,
+ "stroke-width": null,
+ translation: "csv",
+ width: null,
+ x: null,
+ y: null
+ },
+
+ is: function(o, type) {
+ type = String(type).toLowerCase();
+ return (type == "object" && o === Object(o)) ||
+ (type == "undefined" && typeof o == type) ||
+ (type == "null" && o === null) ||
+ (type == "array" && Array.isArray && Array.isArray(o)) ||
+ (Object.prototype.toString.call(o).toLowerCase().slice(8, -1)) == type;
+ },
+
+ ellipsePath: function(sprite) {
+ var attr = sprite.attr;
+ 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);
+ },
+
+ rectPath: function(sprite) {
+ var attr = sprite.attr;
+ if (attr.radius) {
+ 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);
+ }
+ else {
+ return Ext.String.format("M{0},{1}l{2},0,0,{3},{4},0z", attr.x, attr.y, attr.width, attr.height, -attr.width);
+ }
+ },
+
+ // To be deprecated, converts itself (an arrayPath) to a proper SVG path string
+ path2string: function () {
+ return this.join(",").replace(Ext.draw.Draw.pathToStringRE, "$1");
+ },
+
+ // Convert the passed arrayPath to a proper SVG path string (d attribute)
+ pathToString: function(arrayPath) {
+ return arrayPath.join(",").replace(Ext.draw.Draw.pathToStringRE, "$1");
+ },
+
+ parsePathString: function (pathString) {
+ if (!pathString) {
+ return null;
+ }
+ var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0},
+ data = [],
+ me = this;
+ if (me.is(pathString, "array") && me.is(pathString[0], "array")) { // rough assumption
+ data = me.pathClone(pathString);
+ }
+ if (!data.length) {
+ String(pathString).replace(me.pathCommandRE, function (a, b, c) {
+ var params = [],
+ name = b.toLowerCase();
+ c.replace(me.pathValuesRE, function (a, b) {
+ b && params.push(+b);
+ });
+ if (name == "m" && params.length > 2) {
+ data.push([b].concat(params.splice(0, 2)));
+ name = "l";
+ b = (b == "m") ? "l" : "L";
+ }
+ while (params.length >= paramCounts[name]) {
+ data.push([b].concat(params.splice(0, paramCounts[name])));
+ if (!paramCounts[name]) {
+ break;
+ }
+ }
+ });
+ }
+ data.toString = me.path2string;
+ return data;
+ },
+
+ mapPath: function (path, matrix) {
+ if (!matrix) {
+ return path;
+ }
+ var x, y, i, ii, j, jj, pathi;
+ path = this.path2curve(path);
+ for (i = 0, ii = path.length; i < ii; i++) {
+ pathi = path[i];
+ for (j = 1, jj = pathi.length; j < jj-1; j += 2) {
+ x = matrix.x(pathi[j], pathi[j + 1]);
+ y = matrix.y(pathi[j], pathi[j + 1]);
+ pathi[j] = x;
+ pathi[j + 1] = y;
+ }
+ }
+ return path;
+ },
+
+ pathClone: function(pathArray) {
+ var res = [],
+ j, jj, i, ii;
+ if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { // rough assumption
+ pathArray = this.parsePathString(pathArray);
+ }
+ for (i = 0, ii = pathArray.length; i < ii; i++) {
+ res[i] = [];
+ for (j = 0, jj = pathArray[i].length; j < jj; j++) {
+ res[i][j] = pathArray[i][j];
+ }
+ }
+ res.toString = this.path2string;
+ return res;
+ },
+
+ pathToAbsolute: function (pathArray) {
+ if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { // rough assumption
+ pathArray = this.parsePathString(pathArray);
+ }
+ var res = [],
+ x = 0,
+ y = 0,
+ mx = 0,
+ my = 0,
+ i = 0,
+ ln = pathArray.length,
+ r, pathSegment, j, ln2;
+ // MoveTo initial x/y position
+ if (ln && pathArray[0][0] == "M") {
+ x = +pathArray[0][1];
+ y = +pathArray[0][2];
+ mx = x;
+ my = y;
+ i++;
+ res[0] = ["M", x, y];
+ }
+ for (; i < ln; i++) {
+ r = res[i] = [];
+ pathSegment = pathArray[i];
+ if (pathSegment[0] != pathSegment[0].toUpperCase()) {
+ r[0] = pathSegment[0].toUpperCase();
+ switch (r[0]) {
+ // Elliptical Arc
+ case "A":
+ r[1] = pathSegment[1];
+ r[2] = pathSegment[2];
+ r[3] = pathSegment[3];
+ r[4] = pathSegment[4];
+ r[5] = pathSegment[5];
+ r[6] = +(pathSegment[6] + x);
+ r[7] = +(pathSegment[7] + y);
+ break;
+ // Vertical LineTo
+ case "V":
+ r[1] = +pathSegment[1] + y;
+ break;
+ // Horizontal LineTo
+ case "H":
+ r[1] = +pathSegment[1] + x;
+ break;
+ case "M":
+ // MoveTo
+ mx = +pathSegment[1] + x;
+ my = +pathSegment[2] + y;
+ default:
+ j = 1;
+ ln2 = pathSegment.length;
+ for (; j < ln2; j++) {
+ r[j] = +pathSegment[j] + ((j % 2) ? x : y);
+ }
+ }
+ }
+ else {
+ j = 0;
+ ln2 = pathSegment.length;
+ for (; j < ln2; j++) {
+ res[i][j] = pathSegment[j];
+ }
+ }
+ switch (r[0]) {
+ // ClosePath
+ case "Z":
+ x = mx;
+ y = my;
+ break;
+ // Horizontal LineTo
+ case "H":
+ x = r[1];
+ break;
+ // Vertical LineTo
+ case "V":
+ y = r[1];
+ break;
+ // MoveTo
+ case "M":
+ pathSegment = res[i];
+ ln2 = pathSegment.length;
+ mx = pathSegment[ln2 - 2];
+ my = pathSegment[ln2 - 1];
+ default:
+ pathSegment = res[i];
+ ln2 = pathSegment.length;
+ x = pathSegment[ln2 - 2];
+ y = pathSegment[ln2 - 1];
+ }
+ }
+ res.toString = this.path2string;
+ return res;
+ },
+
+ // TO BE DEPRECATED
+ pathToRelative: function (pathArray) {
+ if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) {
+ pathArray = this.parsePathString(pathArray);
+ }
+ var res = [],
+ x = 0,
+ y = 0,
+ mx = 0,
+ my = 0,
+ start = 0;
+ if (pathArray[0][0] == "M") {
+ x = pathArray[0][1];
+ y = pathArray[0][2];
+ mx = x;
+ my = y;
+ start++;
+ res.push(["M", x, y]);
+ }
+ for (var i = start, ii = pathArray.length; i < ii; i++) {
+ var r = res[i] = [],
+ pa = pathArray[i];
+ if (pa[0] != pa[0].toLowerCase()) {
+ r[0] = pa[0].toLowerCase();
+ switch (r[0]) {
+ case "a":
+ r[1] = pa[1];
+ r[2] = pa[2];
+ r[3] = pa[3];
+ r[4] = pa[4];
+ r[5] = pa[5];
+ r[6] = +(pa[6] - x).toFixed(3);
+ r[7] = +(pa[7] - y).toFixed(3);
+ break;
+ case "v":
+ r[1] = +(pa[1] - y).toFixed(3);
+ break;
+ case "m":
+ mx = pa[1];
+ my = pa[2];
+ default:
+ for (var j = 1, jj = pa.length; j < jj; j++) {
+ r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
+ }
+ }
+ } else {
+ r = res[i] = [];
+ if (pa[0] == "m") {
+ mx = pa[1] + x;
+ my = pa[2] + y;
+ }
+ for (var k = 0, kk = pa.length; k < kk; k++) {
+ res[i][k] = pa[k];
+ }
+ }
+ var len = res[i].length;
+ switch (res[i][0]) {
+ case "z":
+ x = mx;
+ y = my;
+ break;
+ case "h":
+ x += +res[i][len - 1];
+ break;
+ case "v":
+ y += +res[i][len - 1];
+ break;
+ default:
+ x += +res[i][len - 2];
+ y += +res[i][len - 1];
+ }
+ }
+ res.toString = this.path2string;
+ return res;
+ },
+
+ // Returns a path converted to a set of curveto commands
+ path2curve: function (path) {
+ var me = this,
+ points = me.pathToAbsolute(path),
+ ln = points.length,
+ attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
+ i, seg, segLn, point;
+
+ for (i = 0; i < ln; i++) {
+ points[i] = me.command2curve(points[i], attrs);
+ if (points[i].length > 7) {
+ points[i].shift();
+ point = points[i];
+ while (point.length) {
+ points.splice(i++, 0, ["C"].concat(point.splice(0, 6)));
+ }
+ points.splice(i, 1);
+ ln = points.length;
+ }
+ seg = points[i];
+ segLn = seg.length;
+ attrs.x = seg[segLn - 2];
+ attrs.y = seg[segLn - 1];
+ attrs.bx = parseFloat(seg[segLn - 4]) || attrs.x;
+ attrs.by = parseFloat(seg[segLn - 3]) || attrs.y;
+ }
+ return points;
+ },
+
+ interpolatePaths: function (path, path2) {
+ var me = this,
+ p = me.pathToAbsolute(path),
+ p2 = me.pathToAbsolute(path2),
+ attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
+ attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
+ fixArc = function (pp, i) {
+ if (pp[i].length > 7) {
+ pp[i].shift();
+ var pi = pp[i];
+ while (pi.length) {
+ pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
+ }
+ pp.splice(i, 1);
+ ii = Math.max(p.length, p2.length || 0);
+ }
+ },
+ fixM = function (path1, path2, a1, a2, i) {
+ if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
+ path2.splice(i, 0, ["M", a2.x, a2.y]);
+ a1.bx = 0;
+ a1.by = 0;
+ a1.x = path1[i][1];
+ a1.y = path1[i][2];
+ ii = Math.max(p.length, p2.length || 0);
+ }
+ };
+ for (var i = 0, ii = Math.max(p.length, p2.length || 0); i < ii; i++) {
+ p[i] = me.command2curve(p[i], attrs);
+ fixArc(p, i);
+ (p2[i] = me.command2curve(p2[i], attrs2));
+ fixArc(p2, i);
+ fixM(p, p2, attrs, attrs2, i);
+ fixM(p2, p, attrs2, attrs, i);
+ var seg = p[i],
+ seg2 = p2[i],
+ seglen = seg.length,
+ seg2len = seg2.length;
+ attrs.x = seg[seglen - 2];
+ attrs.y = seg[seglen - 1];
+ attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x;
+ attrs.by = parseFloat(seg[seglen - 3]) || attrs.y;
+ attrs2.bx = (parseFloat(seg2[seg2len - 4]) || attrs2.x);
+ attrs2.by = (parseFloat(seg2[seg2len - 3]) || attrs2.y);
+ attrs2.x = seg2[seg2len - 2];
+ attrs2.y = seg2[seg2len - 1];
+ }
+ return [p, p2];
+ },
+
+ //Returns any path command as a curveto command based on the attrs passed
+ command2curve: function (pathCommand, d) {
+ var me = this;
+ if (!pathCommand) {
+ return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
+ }
+ if (pathCommand[0] != "T" && pathCommand[0] != "Q") {
+ d.qx = d.qy = null;
+ }
+ switch (pathCommand[0]) {
+ case "M":
+ d.X = pathCommand[1];
+ d.Y = pathCommand[2];
+ break;
+ case "A":
+ pathCommand = ["C"].concat(me.arc2curve.apply(me, [d.x, d.y].concat(pathCommand.slice(1))));
+ break;
+ case "S":
+ pathCommand = ["C", d.x + (d.x - (d.bx || d.x)), d.y + (d.y - (d.by || d.y))].concat(pathCommand.slice(1));
+ break;
+ case "T":
+ d.qx = d.x + (d.x - (d.qx || d.x));
+ d.qy = d.y + (d.y - (d.qy || d.y));
+ pathCommand = ["C"].concat(me.quadratic2curve(d.x, d.y, d.qx, d.qy, pathCommand[1], pathCommand[2]));
+ break;
+ case "Q":
+ d.qx = pathCommand[1];
+ d.qy = pathCommand[2];
+ pathCommand = ["C"].concat(me.quadratic2curve(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[3], pathCommand[4]));
+ break;
+ case "L":
+ pathCommand = ["C"].concat(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[1], pathCommand[2]);
+ break;
+ case "H":
+ pathCommand = ["C"].concat(d.x, d.y, pathCommand[1], d.y, pathCommand[1], d.y);
+ break;
+ case "V":
+ pathCommand = ["C"].concat(d.x, d.y, d.x, pathCommand[1], d.x, pathCommand[1]);
+ break;
+ case "Z":
+ pathCommand = ["C"].concat(d.x, d.y, d.X, d.Y, d.X, d.Y);
+ break;
+ }
+ return pathCommand;
+ },
+
+ quadratic2curve: function (x1, y1, ax, ay, x2, y2) {
+ var _13 = 1 / 3,
+ _23 = 2 / 3;
+ return [
+ _13 * x1 + _23 * ax,
+ _13 * y1 + _23 * ay,
+ _13 * x2 + _23 * ax,
+ _13 * y2 + _23 * ay,
+ x2,
+ y2
+ ];
+ },
+
+ rotate: function (x, y, rad) {
+ var cos = Math.cos(rad),
+ sin = Math.sin(rad),
+ X = x * cos - y * sin,
+ Y = x * sin + y * cos;
+ return {x: X, y: Y};
+ },
+
+ arc2curve: function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
+ // for more information of where this Math came from visit:
+ // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+ var me = this,
+ PI = Math.PI,
+ radian = me.radian,
+ _120 = PI * 120 / 180,
+ rad = radian * (+angle || 0),
+ res = [],
+ math = Math,
+ mcos = math.cos,
+ msin = math.sin,
+ msqrt = math.sqrt,
+ mabs = math.abs,
+ masin = math.asin,
+ xy, cos, sin, x, y, h, rx2, ry2, k, cx, cy, f1, f2, df, c1, s1, c2, s2,
+ t, hx, hy, m1, m2, m3, m4, newres, i, ln, f2old, x2old, y2old;
+ if (!recursive) {
+ xy = me.rotate(x1, y1, -rad);
+ x1 = xy.x;
+ y1 = xy.y;
+ xy = me.rotate(x2, y2, -rad);
+ x2 = xy.x;
+ y2 = xy.y;
+ cos = mcos(radian * angle);
+ sin = msin(radian * angle);
+ x = (x1 - x2) / 2;
+ y = (y1 - y2) / 2;
+ h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
+ if (h > 1) {
+ h = msqrt(h);
+ rx = h * rx;
+ ry = h * ry;
+ }
+ rx2 = rx * rx;
+ ry2 = ry * ry;
+ k = (large_arc_flag == sweep_flag ? -1 : 1) *
+ msqrt(mabs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x)));
+ cx = k * rx * y / ry + (x1 + x2) / 2;
+ cy = k * -ry * x / rx + (y1 + y2) / 2;
+ f1 = masin(((y1 - cy) / ry).toFixed(7));
+ f2 = masin(((y2 - cy) / ry).toFixed(7));
+
+ f1 = x1 < cx ? PI - f1 : f1;
+ f2 = x2 < cx ? PI - f2 : f2;
+ if (f1 < 0) {
+ f1 = PI * 2 + f1;
+ }
+ if (f2 < 0) {
+ f2 = PI * 2 + f2;
+ }
+ if (sweep_flag && f1 > f2) {
+ f1 = f1 - PI * 2;
+ }
+ if (!sweep_flag && f2 > f1) {
+ f2 = f2 - PI * 2;
+ }
+ }
+ else {
+ f1 = recursive[0];
+ f2 = recursive[1];
+ cx = recursive[2];
+ cy = recursive[3];
+ }
+ df = f2 - f1;
+ if (mabs(df) > _120) {
+ f2old = f2;
+ x2old = x2;
+ y2old = y2;
+ f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
+ x2 = cx + rx * mcos(f2);
+ y2 = cy + ry * msin(f2);
+ res = me.arc2curve(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
+ }
+ df = f2 - f1;
+ c1 = mcos(f1);
+ s1 = msin(f1);
+ c2 = mcos(f2);
+ s2 = msin(f2);
+ t = math.tan(df / 4);
+ hx = 4 / 3 * rx * t;
+ hy = 4 / 3 * ry * t;
+ m1 = [x1, y1];
+ m2 = [x1 + hx * s1, y1 - hy * c1];
+ m3 = [x2 + hx * s2, y2 - hy * c2];
+ m4 = [x2, y2];
+ m2[0] = 2 * m1[0] - m2[0];
+ m2[1] = 2 * m1[1] - m2[1];
+ if (recursive) {
+ return [m2, m3, m4].concat(res);
+ }
+ else {
+ res = [m2, m3, m4].concat(res).join().split(",");
+ newres = [];
+ ln = res.length;
+ for (i = 0; i < ln; i++) {
+ newres[i] = i % 2 ? me.rotate(res[i - 1], res[i], rad).y : me.rotate(res[i], res[i + 1], rad).x;
+ }
+ return newres;
+ }
+ },
+
+ // TO BE DEPRECATED
+ rotateAndTranslatePath: function (sprite) {
+ var alpha = sprite.rotation.degrees,
+ cx = sprite.rotation.x,
+ cy = sprite.rotation.y,
+ dx = sprite.translation.x,
+ dy = sprite.translation.y,
+ path,
+ i,
+ p,
+ xy,
+ j,
+ res = [];
+ if (!alpha && !dx && !dy) {
+ return this.pathToAbsolute(sprite.attr.path);
+ }
+ dx = dx || 0;
+ dy = dy || 0;
+ path = this.pathToAbsolute(sprite.attr.path);
+ for (i = path.length; i--;) {
+ p = res[i] = path[i].slice();
+ if (p[0] == "A") {
+ xy = this.rotatePoint(p[6], p[7], alpha, cx, cy);
+ p[6] = xy.x + dx;
+ p[7] = xy.y + dy;
+ } else {
+ j = 1;
+ while (p[j + 1] != null) {
+ xy = this.rotatePoint(p[j], p[j + 1], alpha, cx, cy);
+ p[j] = xy.x + dx;
+ p[j + 1] = xy.y + dy;
+ j += 2;
+ }
+ }
+ }
+ return res;
+ },
+
+ // TO BE DEPRECATED
+ rotatePoint: function (x, y, alpha, cx, cy) {
+ if (!alpha) {
+ return {
+ x: x,
+ y: y
+ };
+ }
+ cx = cx || 0;
+ cy = cy || 0;
+ x = x - cx;
+ y = y - cy;
+ alpha = alpha * this.radian;
+ var cos = Math.cos(alpha),
+ sin = Math.sin(alpha);
+ return {
+ x: x * cos - y * sin + cx,
+ y: x * sin + y * cos + cy
+ };
+ },
+
+ pathDimensions: function (path) {
+ if (!path || !(path + "")) {
+ return {x: 0, y: 0, width: 0, height: 0};
+ }
+ path = this.path2curve(path);
+ var x = 0,
+ y = 0,
+ X = [],
+ Y = [],
+ i = 0,
+ ln = path.length,
+ p, xmin, ymin, dim;
+ for (; i < ln; i++) {
+ p = path[i];
+ if (p[0] == "M") {
+ x = p[1];
+ y = p[2];
+ X.push(x);
+ Y.push(y);
+ }
+ else {
+ dim = this.curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
+ X = X.concat(dim.min.x, dim.max.x);
+ Y = Y.concat(dim.min.y, dim.max.y);
+ x = p[5];
+ y = p[6];
+ }
+ }
+ xmin = Math.min.apply(0, X);
+ ymin = Math.min.apply(0, Y);
+ return {
+ x: xmin,
+ y: ymin,
+ path: path,
+ width: Math.max.apply(0, X) - xmin,
+ height: Math.max.apply(0, Y) - ymin
+ };
+ },
+
+ intersectInside: function(path, cp1, cp2) {
+ return (cp2[0] - cp1[0]) * (path[1] - cp1[1]) > (cp2[1] - cp1[1]) * (path[0] - cp1[0]);
+ },
+
+ intersectIntersection: function(s, e, cp1, cp2) {
+ var p = [],
+ dcx = cp1[0] - cp2[0],
+ dcy = cp1[1] - cp2[1],
+ dpx = s[0] - e[0],
+ dpy = s[1] - e[1],
+ n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0],
+ n2 = s[0] * e[1] - s[1] * e[0],
+ n3 = 1 / (dcx * dpy - dcy * dpx);
+
+ p[0] = (n1 * dpx - n2 * dcx) * n3;
+ p[1] = (n1 * dpy - n2 * dcy) * n3;
+ return p;
+ },
+
+ intersect: function(subjectPolygon, clipPolygon) {
+ var me = this,
+ i = 0,
+ ln = clipPolygon.length,
+ cp1 = clipPolygon[ln - 1],
+ outputList = subjectPolygon,
+ cp2, s, e, point, ln2, inputList, j;
+ for (; i < ln; ++i) {
+ cp2 = clipPolygon[i];
+ inputList = outputList;
+ outputList = [];
+ s = inputList[inputList.length - 1];
+ j = 0;
+ ln2 = inputList.length;
+ for (; j < ln2; j++) {
+ e = inputList[j];
+ if (me.intersectInside(e, cp1, cp2)) {
+ if (!me.intersectInside(s, cp1, cp2)) {
+ outputList.push(me.intersectIntersection(s, e, cp1, cp2));
+ }
+ outputList.push(e);
+ }
+ else if (me.intersectInside(s, cp1, cp2)) {
+ outputList.push(me.intersectIntersection(s, e, cp1, cp2));
+ }
+ s = e;
+ }
+ cp1 = cp2;
+ }
+ return outputList;
+ },
+
+ curveDim: function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
+ var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
+ b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
+ c = p1x - c1x,
+ t1 = (-b + Math.sqrt(b * b - 4 * a * c)) / 2 / a,
+ t2 = (-b - Math.sqrt(b * b - 4 * a * c)) / 2 / a,
+ y = [p1y, p2y],
+ x = [p1x, p2x],
+ dot;
+ if (Math.abs(t1) > 1e12) {
+ t1 = 0.5;
+ }
+ if (Math.abs(t2) > 1e12) {
+ t2 = 0.5;
+ }
+ if (t1 > 0 && t1 < 1) {
+ dot = this.findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ if (t2 > 0 && t2 < 1) {
+ dot = this.findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
+ b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
+ c = p1y - c1y;
+ t1 = (-b + Math.sqrt(b * b - 4 * a * c)) / 2 / a;
+ t2 = (-b - Math.sqrt(b * b - 4 * a * c)) / 2 / a;
+ if (Math.abs(t1) > 1e12) {
+ t1 = 0.5;
+ }
+ if (Math.abs(t2) > 1e12) {
+ t2 = 0.5;
+ }
+ if (t1 > 0 && t1 < 1) {
+ dot = this.findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ if (t2 > 0 && t2 < 1) {
+ dot = this.findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
+ x.push(dot.x);
+ y.push(dot.y);
+ }
+ return {
+ min: {x: Math.min.apply(0, x), y: Math.min.apply(0, y)},
+ max: {x: Math.max.apply(0, x), y: Math.max.apply(0, y)}
+ };
+ },
+
+ getAnchors: function (p1x, p1y, p2x, p2y, p3x, p3y, value) {
+ value = value || 4;
+ var l = Math.min(Math.sqrt(Math.pow(p1x - p2x, 2) + Math.pow(p1y - p2y, 2)) / value, Math.sqrt(Math.pow(p3x - p2x, 2) + Math.pow(p3y - p2y, 2)) / value),
+ a = Math.atan((p2x - p1x) / Math.abs(p2y - p1y)),
+ b = Math.atan((p3x - p2x) / Math.abs(p2y - p3y)),
+ pi = Math.PI;
+ a = p1y < p2y ? pi - a : a;
+ b = p3y < p2y ? pi - b : b;
+ var alpha = pi / 2 - ((a + b) % (pi * 2)) / 2;
+ alpha > pi / 2 && (alpha -= pi);
+ var dx1 = l * Math.sin(alpha + a),
+ dy1 = l * Math.cos(alpha + a),
+ dx2 = l * Math.sin(alpha + b),
+ dy2 = l * Math.cos(alpha + b),
+ out = {
+ x1: p2x - dx1,
+ y1: p2y + dy1,
+ x2: p2x + dx2,
+ y2: p2y + dy2
+ };
+ return out;
+ },
+
+ /* Smoothing function for a path. Converts a path into cubic beziers. Value defines the divider of the distance between points.
+ * Defaults to a value of 4.
+ */
+ smooth: function (originalPath, value) {
+ var path = this.path2curve(originalPath),
+ newp = [path[0]],
+ x = path[0][1],
+ y = path[0][2],
+ j,
+ points,
+ i = 1,
+ ii = path.length,
+ beg = 1,
+ mx = x,
+ my = y,
+ cx = 0,
+ cy = 0;
+ for (; i < ii; i++) {
+ var pathi = path[i],
+ pathil = pathi.length,
+ pathim = path[i - 1],
+ pathiml = pathim.length,
+ pathip = path[i + 1],
+ pathipl = pathip && pathip.length;
+ if (pathi[0] == "M") {
+ mx = pathi[1];
+ my = pathi[2];
+ j = i + 1;
+ while (path[j][0] != "C") {
+ j++;
+ }
+ cx = path[j][5];
+ cy = path[j][6];
+ newp.push(["M", mx, my]);
+ beg = newp.length;
+ x = mx;
+ y = my;
+ continue;
+ }
+ if (pathi[pathil - 2] == mx && pathi[pathil - 1] == my && (!pathip || pathip[0] == "M")) {
+ var begl = newp[beg].length;
+ points = this.getAnchors(pathim[pathiml - 2], pathim[pathiml - 1], mx, my, newp[beg][begl - 2], newp[beg][begl - 1], value);
+ newp[beg][1] = points.x2;
+ newp[beg][2] = points.y2;
+ }
+ else if (!pathip || pathip[0] == "M") {
+ points = {
+ x1: pathi[pathil - 2],
+ y1: pathi[pathil - 1]
+ };
+ } else {
+ points = this.getAnchors(pathim[pathiml - 2], pathim[pathiml - 1], pathi[pathil - 2], pathi[pathil - 1], pathip[pathipl - 2], pathip[pathipl - 1], value);
+ }
+ newp.push(["C", x, y, points.x1, points.y1, pathi[pathil - 2], pathi[pathil - 1]]);
+ x = points.x2;
+ y = points.y2;
+ }
+ return newp;
+ },
+
+ findDotAtSegment: function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+ var t1 = 1 - t;
+ return {
+ x: Math.pow(t1, 3) * p1x + Math.pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + Math.pow(t, 3) * p2x,
+ y: Math.pow(t1, 3) * p1y + Math.pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + Math.pow(t, 3) * p2y
+ };
+ },
+
+ snapEnds: function (from, to, stepsMax) {
+ var step = (to - from) / stepsMax,
+ level = Math.floor(Math.log(step) / Math.LN10) + 1,
+ m = Math.pow(10, level),
+ cur,
+ modulo = Math.round((step % m) * Math.pow(10, 2 - level)),
+ interval = [[0, 15], [20, 4], [30, 2], [40, 4], [50, 9], [60, 4], [70, 2], [80, 4], [100, 15]],
+ stepCount = 0,
+ value,
+ weight,
+ i,
+ topValue,
+ topWeight = 1e9,
+ ln = interval.length;
+ cur = from = Math.floor(from / m) * m;
+ for (i = 0; i < ln; i++) {
+ value = interval[i][0];
+ weight = (value - modulo) < 0 ? 1e6 : (value - modulo) / interval[i][1];
+ if (weight < topWeight) {
+ topValue = value;
+ topWeight = weight;
+ }
+ }
+ step = Math.floor(step * Math.pow(10, -level)) * Math.pow(10, level) + topValue * Math.pow(10, level - 2);
+ while (cur < to) {
+ cur += step;
+ stepCount++;
+ }
+ to = +cur.toFixed(10);
+ return {
+ from: from,
+ to: to,
+ power: level,
+ step: step,
+ steps: stepCount
+ };
+ },
+
+ sorter: function (a, b) {
+ return a.offset - b.offset;
+ },
+
+ rad: function(degrees) {
+ return degrees % 360 * Math.PI / 180;
+ },
+
+ degrees: function(radian) {
+ return radian * 180 / Math.PI % 360;
+ },
+
+ withinBox: function(x, y, bbox) {
+ bbox = bbox || {};
+ return (x >= bbox.x && x <= (bbox.x + bbox.width) && y >= bbox.y && y <= (bbox.y + bbox.height));
+ },
+
+ parseGradient: function(gradient) {
+ var me = this,
+ type = gradient.type || 'linear',
+ angle = gradient.angle || 0,
+ radian = me.radian,
+ stops = gradient.stops,
+ stopsArr = [],
+ stop,
+ vector,
+ max,
+ stopObj;
+
+ if (type == 'linear') {
+ vector = [0, 0, Math.cos(angle * radian), Math.sin(angle * radian)];
+ max = 1 / (Math.max(Math.abs(vector[2]), Math.abs(vector[3])) || 1);
+ vector[2] *= max;
+ vector[3] *= max;
+ if (vector[2] < 0) {
+ vector[0] = -vector[2];
+ vector[2] = 0;
+ }
+ if (vector[3] < 0) {
+ vector[1] = -vector[3];
+ vector[3] = 0;
+ }
+ }
+
+ for (stop in stops) {
+ if (stops.hasOwnProperty(stop) && me.stopsRE.test(stop)) {
+ stopObj = {
+ offset: parseInt(stop, 10),
+ color: Ext.draw.Color.toHex(stops[stop].color) || '#ffffff',
+ opacity: stops[stop].opacity || 1
+ };
+ stopsArr.push(stopObj);
+ }
+ }
+ // Sort by pct property
+ Ext.Array.sort(stopsArr, me.sorter);
+ if (type == 'linear') {
+ return {
+ id: gradient.id,
+ type: type,
+ vector: vector,
+ stops: stopsArr
+ };
+ }
+ else {
+ return {
+ id: gradient.id,
+ type: type,
+ centerX: gradient.centerX,
+ centerY: gradient.centerY,
+ focalX: gradient.focalX,
+ focalY: gradient.focalY,
+ radius: gradient.radius,
+ vector: vector,
+ stops: stopsArr
+ };
+ }
+ }
+});
+</pre>
+</body>
+</html>