- /**
- * Utility class used for drawing area fills.
- *
- * @module charts
- * @class Fills
- * @constructor
- */
- function Fills(cfg)
- {
- var attrs = {
- area: {
- getter: function()
- {
- return this._defaults || this._getAreaDefaults();
- },
- setter: function(val)
- {
- var defaults = this._defaults || this._getAreaDefaults();
- this._defaults = Y.merge(defaults, val);
- }
- }
- };
- this.addAttrs(attrs, cfg);
- this.get("styles");
- }
- Fills.prototype = {
- /**
- * Returns a path shape used for drawing fills.
- *
- * @method _getPath
- * @return Path
- * @private
- */
- _getPath: function()
- {
- var path = this._path;
- if(!path)
- {
- path = this.get("graph").get("graphic").addShape({type:"path"});
- this._path = path;
- }
- return path;
- },
- /**
- * Toggles visibility
- *
- * @method _toggleVisible
- * @param {Boolean} visible indicates visibilitye
- * @private
- */
- _toggleVisible: function(visible)
- {
- if(this._path)
- {
- this._path.set("visible", visible);
- }
- },
- /**
- * Draws fill
- *
- * @method drawFill
- * @param {Array} xcoords The x-coordinates for the series.
- * @param {Array} ycoords The y-coordinates for the series.
- * @protected
- */
- drawFill: function(xcoords, ycoords)
- {
- if(xcoords.length < 1)
- {
- return;
- }
- var isNumber = Y_Lang.isNumber,
- len = xcoords.length,
- firstX = xcoords[0],
- firstY = ycoords[0],
- lastValidX = firstX,
- lastValidY = firstY,
- nextX,
- nextY,
- pointValid,
- noPointsRendered = true,
- i = 0,
- styles = this.get("styles").area,
- path = this._getPath(),
- color = styles.color || this._getDefaultColor(this.get("graphOrder"), "slice");
- path.clear();
- path.set("fill", {
- color: color,
- opacity: styles.alpha
- });
- path.set("stroke", {weight: 0});
- for(; i < len; i = ++i)
- {
- nextX = xcoords[i];
- nextY = ycoords[i];
- pointValid = isNumber(nextX) && isNumber(nextY);
- if(!pointValid)
- {
- continue;
- }
- if(noPointsRendered)
- {
- this._firstValidX = nextX;
- this._firstValidY = nextY;
- noPointsRendered = false;
- path.moveTo(nextX, nextY);
- }
- else
- {
- path.lineTo(nextX, nextY);
- }
- lastValidX = nextX;
- lastValidY = nextY;
- }
- this._lastValidX = lastValidX;
- this._lastValidY = lastValidY;
- path.end();
- },
- /**
- * Draws a fill for a spline
- *
- * @method drawAreaSpline
- * @protected
- */
- drawAreaSpline: function()
- {
- if(this.get("xcoords").length < 1)
- {
- return;
- }
- var xcoords = this.get("xcoords"),
- ycoords = this.get("ycoords"),
- curvecoords = this.getCurveControlPoints(xcoords, ycoords),
- len = curvecoords.length,
- cx1,
- cx2,
- cy1,
- cy2,
- x,
- y,
- i = 0,
- firstX = xcoords[0],
- firstY = ycoords[0],
- styles = this.get("styles").area,
- path = this._getPath(),
- color = styles.color || this._getDefaultColor(this.get("graphOrder"), "slice");
- path.set("fill", {
- color: color,
- opacity: styles.alpha
- });
- path.set("stroke", {weight: 0});
- path.moveTo(firstX, firstY);
- for(; i < len; i = ++i)
- {
- x = curvecoords[i].endx;
- y = curvecoords[i].endy;
- cx1 = curvecoords[i].ctrlx1;
- cx2 = curvecoords[i].ctrlx2;
- cy1 = curvecoords[i].ctrly1;
- cy2 = curvecoords[i].ctrly2;
- path.curveTo(cx1, cy1, cx2, cy2, x, y);
- }
- if(this.get("direction") === "vertical")
- {
- path.lineTo(this._leftOrigin, y);
- path.lineTo(this._leftOrigin, firstY);
- }
- else
- {
- path.lineTo(x, this._bottomOrigin);
- path.lineTo(firstX, this._bottomOrigin);
- }
- path.lineTo(firstX, firstY);
- path.end();
- },
- /**
- * Draws a a stacked area spline
- *
- * @method drawStackedAreaSpline
- * @protected
- */
- drawStackedAreaSpline: function()
- {
- if(this.get("xcoords").length < 1)
- {
- return;
- }
- var xcoords = this.get("xcoords"),
- ycoords = this.get("ycoords"),
- curvecoords,
- order = this.get("order"),
- type = this.get("type"),
- graph = this.get("graph"),
- seriesCollection = graph.seriesTypes[type],
- prevXCoords,
- prevYCoords,
- len,
- cx1,
- cx2,
- cy1,
- cy2,
- x,
- y,
- i = 0,
- firstX,
- firstY,
- styles = this.get("styles").area,
- path = this._getPath(),
- color = styles.color || this._getDefaultColor(this.get("graphOrder"), "slice");
- firstX = xcoords[0];
- firstY = ycoords[0];
- curvecoords = this.getCurveControlPoints(xcoords, ycoords);
- len = curvecoords.length;
- path.set("fill", {
- color: color,
- opacity: styles.alpha
- });
- path.set("stroke", {weight: 0});
- path.moveTo(firstX, firstY);
- for(; i < len; i = ++i)
- {
- x = curvecoords[i].endx;
- y = curvecoords[i].endy;
- cx1 = curvecoords[i].ctrlx1;
- cx2 = curvecoords[i].ctrlx2;
- cy1 = curvecoords[i].ctrly1;
- cy2 = curvecoords[i].ctrly2;
- path.curveTo(cx1, cy1, cx2, cy2, x, y);
- }
- if(order > 0)
- {
- prevXCoords = seriesCollection[order - 1].get("xcoords").concat().reverse();
- prevYCoords = seriesCollection[order - 1].get("ycoords").concat().reverse();
- curvecoords = this.getCurveControlPoints(prevXCoords, prevYCoords);
- i = 0;
- len = curvecoords.length;
- path.lineTo(prevXCoords[0], prevYCoords[0]);
- for(; i < len; i = ++i)
- {
- x = curvecoords[i].endx;
- y = curvecoords[i].endy;
- cx1 = curvecoords[i].ctrlx1;
- cx2 = curvecoords[i].ctrlx2;
- cy1 = curvecoords[i].ctrly1;
- cy2 = curvecoords[i].ctrly2;
- path.curveTo(cx1, cy1, cx2, cy2, x, y);
- }
- }
- else
- {
- if(this.get("direction") === "vertical")
- {
- path.lineTo(this._leftOrigin, ycoords[ycoords.length-1]);
- path.lineTo(this._leftOrigin, firstY);
- }
- else
- {
- path.lineTo(xcoords[xcoords.length-1], this._bottomOrigin);
- path.lineTo(firstX, this._bottomOrigin);
- }
- }
- path.lineTo(firstX, firstY);
- path.end();
- },
- /**
- * Storage for default area styles.
- *
- * @property _defaults
- * @type Object
- * @private
- */
- _defaults: null,
- /**
- * Concatenates coordinate array with correct coordinates for closing an area fill.
- *
- * @method _getClosingPoints
- * @return Array
- * @protected
- */
- _getClosingPoints: function()
- {
- var xcoords = this.get("xcoords").concat(),
- ycoords = this.get("ycoords").concat(),
- firstValidIndex,
- lastValidIndex;
- if(this.get("direction") === "vertical")
- {
- lastValidIndex = this._getLastValidIndex(xcoords);
- firstValidIndex = this._getFirstValidIndex(xcoords);
- ycoords.push(ycoords[lastValidIndex]);
- ycoords.push(ycoords[firstValidIndex]);
- xcoords.push(this._leftOrigin);
- xcoords.push(this._leftOrigin);
- }
- else
- {
- lastValidIndex = this._getLastValidIndex(ycoords);
- firstValidIndex = this._getFirstValidIndex(ycoords);
- xcoords.push(xcoords[lastValidIndex]);
- xcoords.push(xcoords[firstValidIndex]);
- ycoords.push(this._bottomOrigin);
- ycoords.push(this._bottomOrigin);
- }
- xcoords.push(xcoords[0]);
- ycoords.push(ycoords[0]);
- return [xcoords, ycoords];
- },
- /**
- * Returns the order of the series closest to the current series that has a valid value for the current index.
- *
- * @method _getHighestValidOrder
- * @param {Array} seriesCollection Array of series of a given type.
- * @param {Number} index Index of the series item.
- * @param {Number} order Index of the the series in the seriesCollection
- * @param {String} direction Indicates the direction of the series
- * @return Number
- * @private
- */
- _getHighestValidOrder: function(seriesCollection, index, order, direction)
- {
- var coords = direction == "vertical" ? "stackedXCoords" : "stackedYCoords",
- coord;
- while(isNaN(coord) && order > -1)
- {
- order = order - 1;
- if(order > -1)
- {
- coord = seriesCollection[order].get(coords)[index];
- }
- }
- return order;
- },
- /**
- * Returns an array containing the x and y coordinates for a given series and index.
- *
- * @method _getCoordsByOrderAndIndex
- * @param {Array} seriesCollection Array of series of a given type.
- * @param {Number} index Index of the series item.
- * @param {Number} order Index of the the series in the seriesCollection
- * @param {String} direction Indicates the direction of the series
- * @return Array
- * @private
- */
- _getCoordsByOrderAndIndex: function(seriesCollection, index, order, direction)
- {
- var xcoord,
- ycoord;
- if(direction == "vertical")
- {
- xcoord = order < 0 ? this._leftOrigin : seriesCollection[order].get("stackedXCoords")[index];
- ycoord = this.get("stackedYCoords")[index];
- }
- else
- {
- xcoord = this.get("stackedXCoords")[index];
- ycoord = order < 0 ? this._bottomOrigin : seriesCollection[order].get("stackedYCoords")[index];
- }
- return [xcoord, ycoord];
- },
- /**
- * Concatenates coordinate array with the correct coordinates for closing an area stack.
- *
- * @method _getStackedClosingPoints
- * @return Array
- * @protected
- */
- _getStackedClosingPoints: function()
- {
- var order = this.get("order"),
- type = this.get("type"),
- graph = this.get("graph"),
- direction = this.get("direction"),
- seriesCollection = graph.seriesTypes[type],
- firstValidIndex,
- lastValidIndex,
- xcoords = this.get("stackedXCoords"),
- ycoords = this.get("stackedYCoords"),
- limit,
- previousSeries,
- previousSeriesFirstValidIndex,
- previousSeriesLastValidIndex,
- previousXCoords,
- previousYCoords,
- coords,
- closingXCoords,
- closingYCoords,
- currentIndex,
- highestValidOrder,
- oldOrder;
- if(order < 1)
- {
- return this._getClosingPoints();
- }
- previousSeries = seriesCollection[order - 1];
- previousXCoords = previousSeries.get("stackedXCoords").concat();
- previousYCoords = previousSeries.get("stackedYCoords").concat();
- if(direction == "vertical")
- {
- firstValidIndex = this._getFirstValidIndex(xcoords);
- lastValidIndex = this._getLastValidIndex(xcoords);
- previousSeriesFirstValidIndex = previousSeries._getFirstValidIndex(previousXCoords);
- previousSeriesLastValidIndex = previousSeries._getLastValidIndex(previousXCoords);
- }
- else
- {
- firstValidIndex = this._getFirstValidIndex(ycoords);
- lastValidIndex = this._getLastValidIndex(ycoords);
- previousSeriesFirstValidIndex = previousSeries._getFirstValidIndex(previousYCoords);
- previousSeriesLastValidIndex = previousSeries._getLastValidIndex(previousYCoords);
- }
- if(previousSeriesLastValidIndex >= firstValidIndex && previousSeriesFirstValidIndex <= lastValidIndex)
- {
- previousSeriesFirstValidIndex = Math.max(firstValidIndex, previousSeriesFirstValidIndex);
- previousSeriesLastValidIndex = Math.min(lastValidIndex, previousSeriesLastValidIndex);
- previousXCoords = previousXCoords.slice(previousSeriesFirstValidIndex, previousSeriesLastValidIndex + 1);
- previousYCoords = previousYCoords.slice(previousSeriesFirstValidIndex, previousSeriesLastValidIndex + 1);
- limit = previousSeriesFirstValidIndex;
- }
- else
- {
- limit = lastValidIndex;
- }
- closingXCoords = [xcoords[firstValidIndex]];
- closingYCoords = [ycoords[firstValidIndex]];
- currentIndex = firstValidIndex;
- while((isNaN(highestValidOrder) || highestValidOrder < order - 1) && currentIndex <= limit)
- {
- oldOrder = highestValidOrder;
- highestValidOrder = this._getHighestValidOrder(seriesCollection, currentIndex, order, direction);
- if(!isNaN(oldOrder) && highestValidOrder > oldOrder)
- {
- coords = this._getCoordsByOrderAndIndex(seriesCollection, currentIndex, oldOrder, direction);
- closingXCoords.push(coords[0]);
- closingYCoords.push(coords[1]);
- }
- coords = this._getCoordsByOrderAndIndex(seriesCollection, currentIndex, highestValidOrder, direction);
- closingXCoords.push(coords[0]);
- closingYCoords.push(coords[1]);
- currentIndex = currentIndex + 1;
- }
- if(previousXCoords && previousXCoords.length > 0 && previousSeriesLastValidIndex > firstValidIndex && previousSeriesFirstValidIndex < lastValidIndex)
- {
- closingXCoords = closingXCoords.concat(previousXCoords);
- closingYCoords = closingYCoords.concat(previousYCoords);
- highestValidOrder = order -1;
- }
- currentIndex = Math.max(firstValidIndex, previousSeriesLastValidIndex);
- order = order - 1;
- highestValidOrder = NaN;
- while(currentIndex <= lastValidIndex)
- {
- oldOrder = highestValidOrder;
- highestValidOrder = this._getHighestValidOrder(seriesCollection, currentIndex, order, direction);
- if(!isNaN(oldOrder))
- {
- if(highestValidOrder > oldOrder)
- {
- coords = this._getCoordsByOrderAndIndex(seriesCollection, currentIndex, oldOrder, direction);
- closingXCoords.push(coords[0]);
- closingYCoords.push(coords[1]);
- }
- else if(highestValidOrder < oldOrder)
- {
- coords = this._getCoordsByOrderAndIndex(seriesCollection, currentIndex - 1, highestValidOrder, direction);
- closingXCoords.push(coords[0]);
- closingYCoords.push(coords[1]);
- }
- }
- coords = this._getCoordsByOrderAndIndex(seriesCollection, currentIndex, highestValidOrder, direction);
- closingXCoords.push(coords[0]);
- closingYCoords.push(coords[1]);
- currentIndex = currentIndex + 1;
- }
- closingXCoords.reverse();
- closingYCoords.reverse();
- return [xcoords.concat(closingXCoords), ycoords.concat(closingYCoords)];
- },
- /**
- * Returns default values for area styles.
- *
- * @method _getAreaDefaults
- * @return Object
- * @private
- */
- _getAreaDefaults: function()
- {
- return {
- };
- }
- };
- Y.augment(Fills, Y.Attribute);
- Y.Fills = Fills;
-