<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>
+ <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
<style type="text/css">
.highlight { display: block; background-color: #ddd; }
</style>
</script>
</head>
<body onload="prettyPrint(); highlight();">
- <pre class="prettyprint lang-js">/*
- * @class Ext.draw.Draw
+ <pre class="prettyprint lang-js"><span id='Ext-draw-Draw'>/**
+</span> * @class Ext.draw.Draw
* Base Drawing class. Provides base drawing functions.
+ * @private
*/
-
Ext.define('Ext.draw.Draw', {
/* Begin Definitions */
b && params.push(+b);
});
if (name == "m" && params.length > 2) {
- data.push([b].concat(params.splice(0, 2)));
+ data.push([b].concat(Ext.Array.splice(params, 0, 2)));
name = "l";
b = (b == "m") ? "l" : "L";
}
while (params.length >= paramCounts[name]) {
- data.push([b].concat(params.splice(0, paramCounts[name])));
+ data.push([b].concat(Ext.Array.splice(params, 0, paramCounts[name])));
if (!paramCounts[name]) {
break;
}
points[i].shift();
point = points[i];
while (point.length) {
- points.splice(i++, 0, ["C"].concat(point.splice(0, 6)));
+ Ext.Array.splice(points, i++, 0, ["C"].concat(Ext.Array.splice(point, 0, 6)));
}
- points.splice(i, 1);
+ Ext.Array.erase(points, i, 1);
ln = points.length;
}
seg = points[i];
pp[i].shift();
var pi = pp[i];
while (pi.length) {
- pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
+ Ext.Array.splice(pp, i++, 0, ["C"].concat(Ext.Array.splice(pi, 0, 6)));
}
- pp.splice(i, 1);
+ Ext.Array.erase(pp, 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]);
+ Ext.Array.splice(path2, i, 0, ["M", a2.x, a2.y]);
a1.bx = 0;
a1.by = 0;
a1.x = path1[i][1];
};
},
- getAnchors: function (p1x, p1y, p2x, p2y, p3x, p3y, value) {
+<span id='Ext-draw-Draw-method-getAnchors'> /**
+</span> * @private
+ *
+ * Calculates bezier curve control anchor points for a particular point in a path, with a
+ * smoothing curve applied. The smoothness of the curve is controlled by the 'value' parameter.
+ * Note that this algorithm assumes that the line being smoothed is normalized going from left
+ * to right; it makes special adjustments assuming this orientation.
+ *
+ * @param {Number} prevX X coordinate of the previous point in the path
+ * @param {Number} prevY Y coordinate of the previous point in the path
+ * @param {Number} curX X coordinate of the current point in the path
+ * @param {Number} curY Y coordinate of the current point in the path
+ * @param {Number} nextX X coordinate of the next point in the path
+ * @param {Number} nextY Y coordinate of the next point in the path
+ * @param {Number} value A value to control the smoothness of the curve; this is used to
+ * divide the distance between points, so a value of 2 corresponds to
+ * half the distance between points (a very smooth line) while higher values
+ * result in less smooth curves. Defaults to 4.
+ * @return {Object} Object containing x1, y1, x2, y2 bezier control anchor points; x1 and y1
+ * are the control point for the curve toward the previous path point, and
+ * x2 and y2 are the control point for the curve toward the next path point.
+ */
+ getAnchors: function (prevX, prevY, curX, curY, nextX, nextY, 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;
+ var M = Math,
+ PI = M.PI,
+ halfPI = PI / 2,
+ abs = M.abs,
+ sin = M.sin,
+ cos = M.cos,
+ atan = M.atan,
+ control1Length, control2Length, control1Angle, control2Angle,
+ control1X, control1Y, control2X, control2Y, alpha;
+
+ // Find the length of each control anchor line, by dividing the horizontal distance
+ // between points by the value parameter.
+ control1Length = (curX - prevX) / value;
+ control2Length = (nextX - curX) / value;
+
+ // Determine the angle of each control anchor line. If the middle point is a vertical
+ // turnaround then we force it to a flat horizontal angle to prevent the curve from
+ // dipping above or below the middle point. Otherwise we use an angle that points
+ // toward the previous/next target point.
+ if ((curY >= prevY && curY >= nextY) || (curY <= prevY && curY <= nextY)) {
+ control1Angle = control2Angle = halfPI;
+ } else {
+ control1Angle = atan((curX - prevX) / abs(curY - prevY));
+ if (prevY < curY) {
+ control1Angle = PI - control1Angle;
+ }
+ control2Angle = atan((nextX - curX) / abs(curY - nextY));
+ if (nextY < curY) {
+ control2Angle = PI - control2Angle;
+ }
+ }
+
+ // Adjust the calculated angles so they point away from each other on the same line
+ alpha = halfPI - ((control1Angle + control2Angle) % (PI * 2)) / 2;
+ if (alpha > halfPI) {
+ alpha -= PI;
+ }
+ control1Angle += alpha;
+ control2Angle += alpha;
+
+ // Find the control anchor points from the angles and length
+ control1X = curX - control1Length * sin(control1Angle);
+ control1Y = curY + control1Length * cos(control1Angle);
+ control2X = curX + control2Length * sin(control2Angle);
+ control2Y = curY + control2Length * cos(control2Angle);
+
+ // One last adjustment, make sure that no control anchor point extends vertically past
+ // its target prev/next point, as that results in curves dipping above or below and
+ // bending back strangely. If we find this happening we keep the control angle but
+ // reduce the length of the control line so it stays within bounds.
+ if ((curY > prevY && control1Y < prevY) || (curY < prevY && control1Y > prevY)) {
+ control1X += abs(prevY - control1Y) * (control1X - curX) / (control1Y - curY);
+ control1Y = prevY;
+ }
+ if ((curY > nextY && control2Y < nextY) || (curY < nextY && control2Y > nextY)) {
+ control2X -= abs(nextY - control2Y) * (control2X - curX) / (control2Y - curY);
+ control2Y = nextY;
+ }
+
+ return {
+ x1: control1X,
+ y1: control1Y,
+ x2: control2X,
+ y2: control2Y
+ };
},
/* Smoothing function for a path. Converts a path into cubic beziers. Value defines the divider of the distance between points.
};
},
+<span id='Ext-draw-Draw-method-snapEnds'> /**
+</span> * A utility method to deduce an appropriate tick configuration for the data set of given
+ * feature.
+ *
+ * @param {Number/Date} from The minimum value in the data
+ * @param {Number/Date} to The maximum value in the data
+ * @param {Number} stepsMax The maximum number of ticks
+ * @return {Object} The calculated step and ends info; When `from` and `to` are Dates, refer to the
+ * return value of {@link #snapEndsByDate}. For numerical `from` and `to` the return value contains:
+ * @return {Number} return.from The result start value, which may be lower than the original start value
+ * @return {Number} return.to The result end value, which may be higher than the original end value
+ * @return {Number} return.power The calculate power.
+ * @return {Number} return.step The value size of each step
+ * @return {Number} return.steps The number of steps.
+ */
snapEnds: function (from, to, stepsMax) {
+ if (Ext.isDate(from)) {
+ return this.snapEndsByDate(from, to, stepsMax);
+ }
var step = (to - from) / stepsMax,
level = Math.floor(Math.log(step) / Math.LN10) + 1,
m = Math.pow(10, level),
};
},
+<span id='Ext-draw-Draw-method-snapEndsByDate'> /**
+</span> * A utility method to deduce an appropriate tick configuration for the data set of given
+ * feature when data is Dates. Refer to {@link #snapEnds} for numeric data.
+ *
+ * @param {Date} from The minimum value in the data
+ * @param {Date} to The maximum value in the data
+ * @param {Number} stepsMax The maximum number of ticks
+ * @param {Boolean} lockEnds If true, the 'from' and 'to' parameters will be used as fixed end values
+ * and will not be adjusted
+ * @return {Object} The calculated step and ends info; properties are:
+ * @return {Date} return.from The result start value, which may be lower than the original start value
+ * @return {Date} return.to The result end value, which may be higher than the original end value
+ * @return {Number} return.step The value size of each step
+ * @return {Number} return.steps The number of steps.
+ * NOTE: the steps may not divide the from/to range perfectly evenly;
+ * there may be a smaller distance between the last step and the end value than between prior
+ * steps, particularly when the `endsLocked` param is true. Therefore it is best to not use
+ * the `steps` result when finding the axis tick points, instead use the `step`, `to`, and
+ * `from` to find the correct point for each tick.
+ */
+ snapEndsByDate: function (from, to, stepsMax, lockEnds) {
+ var selectedStep = false, scales = [
+ [Ext.Date.MILLI, [1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500]],
+ [Ext.Date.SECOND, [1, 2, 3, 5, 10, 15, 30]],
+ [Ext.Date.MINUTE, [1, 2, 3, 5, 10, 20, 30]],
+ [Ext.Date.HOUR, [1, 2, 3, 4, 6, 12]],
+ [Ext.Date.DAY, [1, 2, 3, 7, 14]],
+ [Ext.Date.MONTH, [1, 2, 3, 4, 6]]
+ ], j, yearDiff;
+
+ // Find the most desirable scale
+ Ext.each(scales, function(scale, i) {
+ for (j = 0; j < scale[1].length; j++) {
+ if (to < Ext.Date.add(from, scale[0], scale[1][j] * stepsMax)) {
+ selectedStep = [scale[0], scale[1][j]];
+ return false;
+ }
+ }
+ });
+ if (!selectedStep) {
+ yearDiff = this.snapEnds(from.getFullYear(), to.getFullYear() + 1, stepsMax, lockEnds);
+ selectedStep = [Date.YEAR, Math.round(yearDiff.step)];
+ }
+ return this.snapEndsByDateAndStep(from, to, selectedStep, lockEnds);
+ },
+
+
+<span id='Ext-draw-Draw-method-snapEndsByDateAndStep'> /**
+</span> * A utility method to deduce an appropriate tick configuration for the data set of given
+ * feature and specific step size.
+ * @param {Date} from The minimum value in the data
+ * @param {Date} to The maximum value in the data
+ * @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.).
+ * @param {Boolean} lockEnds If true, the 'from' and 'to' parameters will be used as fixed end values
+ * and will not be adjusted
+ * @return {Object} See the return value of {@link #snapEndsByDate}.
+ */
+ snapEndsByDateAndStep: function(from, to, step, lockEnds) {
+ var fromStat = [from.getFullYear(), from.getMonth(), from.getDate(),
+ from.getHours(), from.getMinutes(), from.getSeconds(), from.getMilliseconds()],
+ steps = 0, testFrom, testTo;
+ if (lockEnds) {
+ testFrom = from;
+ } else {
+ switch (step[0]) {
+ case Ext.Date.MILLI:
+ testFrom = new Date(fromStat[0], fromStat[1], fromStat[2], fromStat[3],
+ fromStat[4], fromStat[5], Math.floor(fromStat[6] / step[1]) * step[1]);
+ break;
+ case Ext.Date.SECOND:
+ testFrom = new Date(fromStat[0], fromStat[1], fromStat[2], fromStat[3],
+ fromStat[4], Math.floor(fromStat[5] / step[1]) * step[1], 0);
+ break;
+ case Ext.Date.MINUTE:
+ testFrom = new Date(fromStat[0], fromStat[1], fromStat[2], fromStat[3],
+ Math.floor(fromStat[4] / step[1]) * step[1], 0, 0);
+ break;
+ case Ext.Date.HOUR:
+ testFrom = new Date(fromStat[0], fromStat[1], fromStat[2],
+ Math.floor(fromStat[3] / step[1]) * step[1], 0, 0, 0);
+ break;
+ case Ext.Date.DAY:
+ testFrom = new Date(fromStat[0], fromStat[1],
+ Math.floor(fromStat[2] - 1 / step[1]) * step[1] + 1, 0, 0, 0, 0);
+ break;
+ case Ext.Date.MONTH:
+ testFrom = new Date(fromStat[0], Math.floor(fromStat[1] / step[1]) * step[1], 1, 0, 0, 0, 0);
+ break;
+ default: // Ext.Date.YEAR
+ testFrom = new Date(Math.floor(fromStat[0] / step[1]) * step[1], 0, 1, 0, 0, 0, 0);
+ break;
+ }
+ }
+
+ testTo = testFrom;
+ // TODO(zhangbei) : We can do it better somehow...
+ while (testTo < to) {
+ testTo = Ext.Date.add(testTo, step[0], step[1]);
+ steps++;
+ }
+
+ if (lockEnds) {
+ testTo = to;
+ }
+ return {
+ from : +testFrom,
+ to : +testTo,
+ step : (testTo - testFrom) / steps,
+ steps : steps
+ };
+ },
+
sorter: function (a, b) {
return a.offset - b.offset;
},
}
}
});
+
</pre>
</body>
</html>