--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cm/media/js/lib/yui/yui_3.10.3/build/charts-legend/charts-legend.js Tue Jul 16 14:29:46 2013 +0200
@@ -0,0 +1,1711 @@
+/*
+YUI 3.10.3 (build 2fb5187)
+Copyright 2013 Yahoo! Inc. All rights reserved.
+Licensed under the BSD License.
+http://yuilibrary.com/license/
+*/
+
+YUI.add('charts-legend', function (Y, NAME) {
+
+/**
+ * Adds legend functionality to charts.
+ *
+ * @module charts
+ * @submodule charts-legend
+ */
+var DOCUMENT = Y.config.doc,
+TOP = "top",
+RIGHT = "right",
+BOTTOM = "bottom",
+LEFT = "left",
+EXTERNAL = "external",
+HORIZONTAL = "horizontal",
+VERTICAL = "vertical",
+WIDTH = "width",
+HEIGHT = "height",
+POSITION = "position",
+_X = "x",
+_Y = "y",
+PX = "px",
+PieChartLegend,
+LEGEND = {
+ setter: function(val)
+ {
+ var legend = this.get("legend");
+ if(legend)
+ {
+ legend.destroy(true);
+ }
+ if(val instanceof Y.ChartLegend)
+ {
+ legend = val;
+ legend.set("chart", this);
+ }
+ else
+ {
+ val.chart = this;
+ if(!val.hasOwnProperty("render"))
+ {
+ val.render = this.get("contentBox");
+ val.includeInChartLayout = true;
+ }
+ legend = new Y.ChartLegend(val);
+ }
+ return legend;
+ }
+},
+
+/**
+ * Contains methods for displaying items horizontally in a legend.
+ *
+ * @module charts
+ * @submodule charts-legend
+ * @class HorizontalLegendLayout
+ */
+HorizontalLegendLayout = {
+ /**
+ * Displays items horizontally in a legend.
+ *
+ * @method _positionLegendItems
+ * @param {Array} items Array of items to display in the legend.
+ * @param {Number} maxWidth The width of the largest item in the legend.
+ * @param {Number} maxHeight The height of the largest item in the legend.
+ * @param {Number} totalWidth The total width of all items in a legend.
+ * @param {Number} totalHeight The total height of all items in a legend.
+ * @param {Number} padding The left, top, right and bottom padding properties for the legend.
+ * @param {Number} horizontalGap The horizontal distance between items in a legend.
+ * @param {Number} verticalGap The vertical distance between items in a legend.
+ * @param {String} hAlign The horizontal alignment of the legend.
+ * @protected
+ */
+ _positionLegendItems: function(items, maxWidth, maxHeight, totalWidth, totalHeight, padding, horizontalGap, verticalGap, hAlign)
+ {
+ var i = 0,
+ rowIterator = 0,
+ item,
+ node,
+ itemWidth,
+ itemHeight,
+ len,
+ width = this.get("width"),
+ rows,
+ rowsLen,
+ row,
+ totalWidthArray,
+ legendWidth,
+ topHeight = padding.top - verticalGap,
+ limit = width - (padding.left + padding.right),
+ left,
+ top,
+ right,
+ bottom;
+ HorizontalLegendLayout._setRowArrays(items, limit, horizontalGap);
+ rows = HorizontalLegendLayout.rowArray;
+ totalWidthArray = HorizontalLegendLayout.totalWidthArray;
+ rowsLen = rows.length;
+ for(; rowIterator < rowsLen; ++ rowIterator)
+ {
+ topHeight += verticalGap;
+ row = rows[rowIterator];
+ len = row.length;
+ legendWidth = HorizontalLegendLayout.getStartPoint(width, totalWidthArray[rowIterator], hAlign, padding);
+ for(i = 0; i < len; ++i)
+ {
+ item = row[i];
+ node = item.node;
+ itemWidth = item.width;
+ itemHeight = item.height;
+ item.x = legendWidth;
+ item.y = 0;
+ left = !isNaN(left) ? Math.min(left, legendWidth) : legendWidth;
+ top = !isNaN(top) ? Math.min(top, topHeight) : topHeight;
+ right = !isNaN(right) ? Math.max(legendWidth + itemWidth, right) : legendWidth + itemWidth;
+ bottom = !isNaN(bottom) ? Math.max(topHeight + itemHeight, bottom) : topHeight + itemHeight;
+ node.setStyle("left", legendWidth + PX);
+ node.setStyle("top", topHeight + PX);
+ legendWidth += itemWidth + horizontalGap;
+ }
+ topHeight += item.height;
+ }
+ this._contentRect = {
+ left: left,
+ top: top,
+ right: right,
+ bottom: bottom
+ };
+ if(this.get("includeInChartLayout"))
+ {
+ this.set("height", topHeight + padding.bottom);
+ }
+ },
+
+ /**
+ * Creates row and total width arrays used for displaying multiple rows of
+ * legend items based on the items, available width and horizontalGap for the legend.
+ *
+ * @method _setRowArrays
+ * @param {Array} items Array of legend items to display in a legend.
+ * @param {Number} limit Total available width for displaying items in a legend.
+ * @param {Number} horizontalGap Horizontal distance between items in a legend.
+ * @protected
+ */
+ _setRowArrays: function(items, limit, horizontalGap)
+ {
+ var item = items[0],
+ rowArray = [[item]],
+ i = 1,
+ rowIterator = 0,
+ len = items.length,
+ totalWidth = item.width,
+ itemWidth,
+ totalWidthArray = [[totalWidth]];
+ for(; i < len; ++i)
+ {
+ item = items[i];
+ itemWidth = item.width;
+ if((totalWidth + horizontalGap + itemWidth) <= limit)
+ {
+ totalWidth += horizontalGap + itemWidth;
+ rowArray[rowIterator].push(item);
+ }
+ else
+ {
+ totalWidth = horizontalGap + itemWidth;
+ if(rowArray[rowIterator])
+ {
+ rowIterator += 1;
+ }
+ rowArray[rowIterator] = [item];
+ }
+ totalWidthArray[rowIterator] = totalWidth;
+ }
+ HorizontalLegendLayout.rowArray = rowArray;
+ HorizontalLegendLayout.totalWidthArray = totalWidthArray;
+ },
+
+ /**
+ * Returns the starting x-coordinate for a row of legend items.
+ *
+ * @method getStartPoint
+ * @param {Number} w Width of the legend.
+ * @param {Number} totalWidth Total width of all labels in the row.
+ * @param {String} align Horizontal alignment of items for the legend.
+ * @param {Object} padding Object contain left, top, right and bottom padding properties.
+ * @return Number
+ * @protected
+ */
+ getStartPoint: function(w, totalWidth, align, padding)
+ {
+ var startPoint;
+ switch(align)
+ {
+ case LEFT :
+ startPoint = padding.left;
+ break;
+ case "center" :
+ startPoint = (w - totalWidth) * 0.5;
+ break;
+ case RIGHT :
+ startPoint = w - totalWidth - padding.right;
+ break;
+ }
+ return startPoint;
+ }
+},
+
+/**
+ * Contains methods for displaying items vertically in a legend.
+ *
+ * @module charts
+ * @submodule charts-legend
+ * @class VerticalLegendLayout
+ */
+VerticalLegendLayout = {
+ /**
+ * Displays items vertically in a legend.
+ *
+ * @method _positionLegendItems
+ * @param {Array} items Array of items to display in the legend.
+ * @param {Number} maxWidth The width of the largest item in the legend.
+ * @param {Number} maxHeight The height of the largest item in the legend.
+ * @param {Number} totalWidth The total width of all items in a legend.
+ * @param {Number} totalHeight The total height of all items in a legend.
+ * @param {Number} padding The left, top, right and bottom padding properties for the legend.
+ * @param {Number} horizontalGap The horizontal distance between items in a legend.
+ * @param {Number} verticalGap The vertical distance between items in a legend.
+ * @param {String} vAlign The vertical alignment of the legend.
+ * @protected
+ */
+ _positionLegendItems: function(items, maxWidth, maxHeight, totalWidth, totalHeight, padding, horizontalGap, verticalGap, vAlign)
+ {
+ var i = 0,
+ columnIterator = 0,
+ item,
+ node,
+ itemHeight,
+ itemWidth,
+ len,
+ height = this.get("height"),
+ columns,
+ columnsLen,
+ column,
+ totalHeightArray,
+ legendHeight,
+ leftWidth = padding.left - horizontalGap,
+ legendWidth,
+ limit = height - (padding.top + padding.bottom),
+ left,
+ top,
+ right,
+ bottom;
+ VerticalLegendLayout._setColumnArrays(items, limit, verticalGap);
+ columns = VerticalLegendLayout.columnArray;
+ totalHeightArray = VerticalLegendLayout.totalHeightArray;
+ columnsLen = columns.length;
+ for(; columnIterator < columnsLen; ++ columnIterator)
+ {
+ leftWidth += horizontalGap;
+ column = columns[columnIterator];
+ len = column.length;
+ legendHeight = VerticalLegendLayout.getStartPoint(height, totalHeightArray[columnIterator], vAlign, padding);
+ legendWidth = 0;
+ for(i = 0; i < len; ++i)
+ {
+ item = column[i];
+ node = item.node;
+ itemHeight = item.height;
+ itemWidth = item.width;
+ item.y = legendHeight;
+ item.x = leftWidth;
+ left = !isNaN(left) ? Math.min(left, leftWidth) : leftWidth;
+ top = !isNaN(top) ? Math.min(top, legendHeight) : legendHeight;
+ right = !isNaN(right) ? Math.max(leftWidth + itemWidth, right) : leftWidth + itemWidth;
+ bottom = !isNaN(bottom) ? Math.max(legendHeight + itemHeight, bottom) : legendHeight + itemHeight;
+ node.setStyle("left", leftWidth + PX);
+ node.setStyle("top", legendHeight + PX);
+ legendHeight += itemHeight + verticalGap;
+ legendWidth = Math.max(legendWidth, item.width);
+ }
+ leftWidth += legendWidth;
+ }
+ this._contentRect = {
+ left: left,
+ top: top,
+ right: right,
+ bottom: bottom
+ };
+ if(this.get("includeInChartLayout"))
+ {
+ this.set("width", leftWidth + padding.right);
+ }
+ },
+
+ /**
+ * Creates column and total height arrays used for displaying multiple columns of
+ * legend items based on the items, available height and verticalGap for the legend.
+ *
+ * @method _setColumnArrays
+ * @param {Array} items Array of legend items to display in a legend.
+ * @param {Number} limit Total available height for displaying items in a legend.
+ * @param {Number} verticalGap Vertical distance between items in a legend.
+ * @protected
+ */
+ _setColumnArrays: function(items, limit, verticalGap)
+ {
+ var item = items[0],
+ columnArray = [[item]],
+ i = 1,
+ columnIterator = 0,
+ len = items.length,
+ totalHeight = item.height,
+ itemHeight,
+ totalHeightArray = [[totalHeight]];
+ for(; i < len; ++i)
+ {
+ item = items[i];
+ itemHeight = item.height;
+ if((totalHeight + verticalGap + itemHeight) <= limit)
+ {
+ totalHeight += verticalGap + itemHeight;
+ columnArray[columnIterator].push(item);
+ }
+ else
+ {
+ totalHeight = verticalGap + itemHeight;
+ if(columnArray[columnIterator])
+ {
+ columnIterator += 1;
+ }
+ columnArray[columnIterator] = [item];
+ }
+ totalHeightArray[columnIterator] = totalHeight;
+ }
+ VerticalLegendLayout.columnArray = columnArray;
+ VerticalLegendLayout.totalHeightArray = totalHeightArray;
+ },
+
+ /**
+ * Returns the starting y-coordinate for a column of legend items.
+ *
+ * @method getStartPoint
+ * @param {Number} h Height of the legend.
+ * @param {Number} totalHeight Total height of all labels in the column.
+ * @param {String} align Vertical alignment of items for the legend.
+ * @param {Object} padding Object contain left, top, right and bottom padding properties.
+ * @return Number
+ * @protected
+ */
+ getStartPoint: function(h, totalHeight, align, padding)
+ {
+ var startPoint;
+ switch(align)
+ {
+ case TOP :
+ startPoint = padding.top;
+ break;
+ case "middle" :
+ startPoint = (h - totalHeight) * 0.5;
+ break;
+ case BOTTOM :
+ startPoint = h - totalHeight - padding.bottom;
+ break;
+ }
+ return startPoint;
+ }
+},
+
+CartesianChartLegend = Y.Base.create("cartesianChartLegend", Y.CartesianChart, [], {
+ /**
+ * Redraws and position all the components of the chart instance.
+ *
+ * @method _redraw
+ * @private
+ */
+ _redraw: function()
+ {
+ if(this._drawing)
+ {
+ this._callLater = true;
+ return;
+ }
+ this._drawing = true;
+ this._callLater = false;
+ var w = this.get("width"),
+ h = this.get("height"),
+ layoutBoxDimensions = this._getLayoutBoxDimensions(),
+ leftPaneWidth = layoutBoxDimensions.left,
+ rightPaneWidth = layoutBoxDimensions.right,
+ topPaneHeight = layoutBoxDimensions.top,
+ bottomPaneHeight = layoutBoxDimensions.bottom,
+ leftAxesCollection = this.get("leftAxesCollection"),
+ rightAxesCollection = this.get("rightAxesCollection"),
+ topAxesCollection = this.get("topAxesCollection"),
+ bottomAxesCollection = this.get("bottomAxesCollection"),
+ i = 0,
+ l,
+ axis,
+ graphOverflow = "visible",
+ graph = this.get("graph"),
+ topOverflow,
+ bottomOverflow,
+ leftOverflow,
+ rightOverflow,
+ graphWidth,
+ graphHeight,
+ graphX,
+ graphY,
+ allowContentOverflow = this.get("allowContentOverflow"),
+ diff,
+ rightAxesXCoords,
+ leftAxesXCoords,
+ topAxesYCoords,
+ bottomAxesYCoords,
+ legend = this.get("legend"),
+ graphRect = {};
+
+ if(leftAxesCollection)
+ {
+ leftAxesXCoords = [];
+ l = leftAxesCollection.length;
+ for(i = l - 1; i > -1; --i)
+ {
+ leftAxesXCoords.unshift(leftPaneWidth);
+ leftPaneWidth += leftAxesCollection[i].get("width");
+ }
+ }
+ if(rightAxesCollection)
+ {
+ rightAxesXCoords = [];
+ l = rightAxesCollection.length;
+ i = 0;
+ for(i = l - 1; i > -1; --i)
+ {
+ rightPaneWidth += rightAxesCollection[i].get("width");
+ rightAxesXCoords.unshift(w - rightPaneWidth);
+ }
+ }
+ if(topAxesCollection)
+ {
+ topAxesYCoords = [];
+ l = topAxesCollection.length;
+ for(i = l - 1; i > -1; --i)
+ {
+ topAxesYCoords.unshift(topPaneHeight);
+ topPaneHeight += topAxesCollection[i].get("height");
+ }
+ }
+ if(bottomAxesCollection)
+ {
+ bottomAxesYCoords = [];
+ l = bottomAxesCollection.length;
+ for(i = l - 1; i > -1; --i)
+ {
+ bottomPaneHeight += bottomAxesCollection[i].get("height");
+ bottomAxesYCoords.unshift(h - bottomPaneHeight);
+ }
+ }
+
+ graphWidth = w - (leftPaneWidth + rightPaneWidth);
+ graphHeight = h - (bottomPaneHeight + topPaneHeight);
+ graphRect.left = leftPaneWidth;
+ graphRect.top = topPaneHeight;
+ graphRect.bottom = h - bottomPaneHeight;
+ graphRect.right = w - rightPaneWidth;
+ if(!allowContentOverflow)
+ {
+ topOverflow = this._getTopOverflow(leftAxesCollection, rightAxesCollection);
+ bottomOverflow = this._getBottomOverflow(leftAxesCollection, rightAxesCollection);
+ leftOverflow = this._getLeftOverflow(bottomAxesCollection, topAxesCollection);
+ rightOverflow = this._getRightOverflow(bottomAxesCollection, topAxesCollection);
+
+ diff = topOverflow - topPaneHeight;
+ if(diff > 0)
+ {
+ graphRect.top = topOverflow;
+ if(topAxesYCoords)
+ {
+ i = 0;
+ l = topAxesYCoords.length;
+ for(; i < l; ++i)
+ {
+ topAxesYCoords[i] += diff;
+ }
+ }
+ }
+
+ diff = bottomOverflow - bottomPaneHeight;
+ if(diff > 0)
+ {
+ graphRect.bottom = h - bottomOverflow;
+ if(bottomAxesYCoords)
+ {
+ i = 0;
+ l = bottomAxesYCoords.length;
+ for(; i < l; ++i)
+ {
+ bottomAxesYCoords[i] -= diff;
+ }
+ }
+ }
+
+ diff = leftOverflow - leftPaneWidth;
+ if(diff > 0)
+ {
+ graphRect.left = leftOverflow;
+ if(leftAxesXCoords)
+ {
+ i = 0;
+ l = leftAxesXCoords.length;
+ for(; i < l; ++i)
+ {
+ leftAxesXCoords[i] += diff;
+ }
+ }
+ }
+
+ diff = rightOverflow - rightPaneWidth;
+ if(diff > 0)
+ {
+ graphRect.right = w - rightOverflow;
+ if(rightAxesXCoords)
+ {
+ i = 0;
+ l = rightAxesXCoords.length;
+ for(; i < l; ++i)
+ {
+ rightAxesXCoords[i] -= diff;
+ }
+ }
+ }
+ }
+ graphWidth = graphRect.right - graphRect.left;
+ graphHeight = graphRect.bottom - graphRect.top;
+ graphX = graphRect.left;
+ graphY = graphRect.top;
+ if(legend)
+ {
+ if(legend.get("includeInChartLayout"))
+ {
+ switch(legend.get("position"))
+ {
+ case "left" :
+ legend.set("y", graphY);
+ legend.set("height", graphHeight);
+ break;
+ case "top" :
+ legend.set("x", graphX);
+ legend.set("width", graphWidth);
+ break;
+ case "bottom" :
+ legend.set("x", graphX);
+ legend.set("width", graphWidth);
+ break;
+ case "right" :
+ legend.set("y", graphY);
+ legend.set("height", graphHeight);
+ break;
+ }
+ }
+ }
+ if(topAxesCollection)
+ {
+ l = topAxesCollection.length;
+ i = 0;
+ for(; i < l; i++)
+ {
+ axis = topAxesCollection[i];
+ if(axis.get("width") !== graphWidth)
+ {
+ axis.set("width", graphWidth);
+ }
+ axis.get("boundingBox").setStyle("left", graphX + PX);
+ axis.get("boundingBox").setStyle("top", topAxesYCoords[i] + PX);
+ }
+ if(axis._hasDataOverflow())
+ {
+ graphOverflow = "hidden";
+ }
+ }
+ if(bottomAxesCollection)
+ {
+ l = bottomAxesCollection.length;
+ i = 0;
+ for(; i < l; i++)
+ {
+ axis = bottomAxesCollection[i];
+ if(axis.get("width") !== graphWidth)
+ {
+ axis.set("width", graphWidth);
+ }
+ axis.get("boundingBox").setStyle("left", graphX + PX);
+ axis.get("boundingBox").setStyle("top", bottomAxesYCoords[i] + PX);
+ }
+ if(axis._hasDataOverflow())
+ {
+ graphOverflow = "hidden";
+ }
+ }
+ if(leftAxesCollection)
+ {
+ l = leftAxesCollection.length;
+ i = 0;
+ for(; i < l; ++i)
+ {
+ axis = leftAxesCollection[i];
+ axis.get("boundingBox").setStyle("top", graphY + PX);
+ axis.get("boundingBox").setStyle("left", leftAxesXCoords[i] + PX);
+ if(axis.get("height") !== graphHeight)
+ {
+ axis.set("height", graphHeight);
+ }
+ }
+ if(axis._hasDataOverflow())
+ {
+ graphOverflow = "hidden";
+ }
+ }
+ if(rightAxesCollection)
+ {
+ l = rightAxesCollection.length;
+ i = 0;
+ for(; i < l; ++i)
+ {
+ axis = rightAxesCollection[i];
+ axis.get("boundingBox").setStyle("top", graphY + PX);
+ axis.get("boundingBox").setStyle("left", rightAxesXCoords[i] + PX);
+ if(axis.get("height") !== graphHeight)
+ {
+ axis.set("height", graphHeight);
+ }
+ }
+ if(axis._hasDataOverflow())
+ {
+ graphOverflow = "hidden";
+ }
+ }
+ this._drawing = false;
+ if(this._callLater)
+ {
+ this._redraw();
+ return;
+ }
+ if(graph)
+ {
+ graph.get("boundingBox").setStyle("left", graphX + PX);
+ graph.get("boundingBox").setStyle("top", graphY + PX);
+ graph.set("width", graphWidth);
+ graph.set("height", graphHeight);
+ graph.get("boundingBox").setStyle("overflow", graphOverflow);
+ }
+
+ if(this._overlay)
+ {
+ this._overlay.setStyle("left", graphX + PX);
+ this._overlay.setStyle("top", graphY + PX);
+ this._overlay.setStyle("width", graphWidth + PX);
+ this._overlay.setStyle("height", graphHeight + PX);
+ }
+ },
+
+ /**
+ * Positions the legend in a chart and returns the properties of the legend to be used in the
+ * chart's layout algorithm.
+ *
+ * @method _getLayoutDimensions
+ * @return {Object} The left, top, right and bottom values for the legend.
+ * @protected
+ */
+ _getLayoutBoxDimensions: function()
+ {
+ var box = {
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0
+ },
+ legend = this.get("legend"),
+ position,
+ direction,
+ dimension,
+ size,
+ w = this.get(WIDTH),
+ h = this.get(HEIGHT),
+ gap;
+ if(legend && legend.get("includeInChartLayout"))
+ {
+ gap = legend.get("styles").gap;
+ position = legend.get(POSITION);
+ if(position !== EXTERNAL)
+ {
+ direction = legend.get("direction");
+ dimension = direction === HORIZONTAL ? HEIGHT : WIDTH;
+ size = legend.get(dimension);
+ box[position] = size + gap;
+ switch(position)
+ {
+ case TOP :
+ legend.set(_Y, 0);
+ break;
+ case BOTTOM :
+ legend.set(_Y, h - size);
+ break;
+ case RIGHT :
+ legend.set(_X, w - size);
+ break;
+ case LEFT:
+ legend.set(_X, 0);
+ break;
+ }
+ }
+ }
+ return box;
+ },
+
+ /**
+ * Destructor implementation for the CartesianChart class. Calls destroy on all axes, series, legend (if available) and the Graph instance.
+ * Removes the tooltip and overlay HTML elements.
+ *
+ * @method destructor
+ * @protected
+ */
+ destructor: function()
+ {
+ var legend = this.get("legend");
+ if(legend)
+ {
+ legend.destroy(true);
+ }
+ }
+}, {
+ ATTRS: {
+ legend: LEGEND
+ }
+});
+
+Y.CartesianChart = CartesianChartLegend;
+
+PieChartLegend = Y.Base.create("pieChartLegend", Y.PieChart, [], {
+ /**
+ * Redraws the chart instance.
+ *
+ * @method _redraw
+ * @private
+ */
+ _redraw: function()
+ {
+ if(this._drawing)
+ {
+ this._callLater = true;
+ return;
+ }
+ this._drawing = true;
+ this._callLater = false;
+ var graph = this.get("graph"),
+ w = this.get("width"),
+ h = this.get("height"),
+ graphWidth,
+ graphHeight,
+ legend = this.get("legend"),
+ x = 0,
+ y = 0,
+ legendX = 0,
+ legendY = 0,
+ legendWidth,
+ legendHeight,
+ dimension,
+ gap,
+ position,
+ direction;
+ if(graph)
+ {
+ if(legend)
+ {
+ position = legend.get("position");
+ direction = legend.get("direction");
+ graphWidth = graph.get("width");
+ graphHeight = graph.get("height");
+ legendWidth = legend.get("width");
+ legendHeight = legend.get("height");
+ gap = legend.get("styles").gap;
+
+ if((direction === "vertical" && (graphWidth + legendWidth + gap !== w)) ||
+ (direction === "horizontal" && (graphHeight + legendHeight + gap !== h)))
+ {
+ switch(legend.get("position"))
+ {
+ case LEFT :
+ dimension = Math.min(w - (legendWidth + gap), h);
+ legendHeight = h;
+ x = legendWidth + gap;
+ legend.set(HEIGHT, legendHeight);
+ break;
+ case TOP :
+ dimension = Math.min(h - (legendHeight + gap), w);
+ legendWidth = w;
+ y = legendHeight + gap;
+ legend.set(WIDTH, legendWidth);
+ break;
+ case RIGHT :
+ dimension = Math.min(w - (legendWidth + gap), h);
+ legendHeight = h;
+ legendX = dimension + gap;
+ legend.set(HEIGHT, legendHeight);
+ break;
+ case BOTTOM :
+ dimension = Math.min(h - (legendHeight + gap), w);
+ legendWidth = w;
+ legendY = dimension + gap;
+ legend.set(WIDTH, legendWidth);
+ break;
+ }
+ graph.set(WIDTH, dimension);
+ graph.set(HEIGHT, dimension);
+ }
+ else
+ {
+ switch(legend.get("position"))
+ {
+ case LEFT :
+ x = legendWidth + gap;
+ break;
+ case TOP :
+ y = legendHeight + gap;
+ break;
+ case RIGHT :
+ legendX = graphWidth + gap;
+ break;
+ case BOTTOM :
+ legendY = graphHeight + gap;
+ break;
+ }
+ }
+ }
+ else
+ {
+ graph.set(_X, 0);
+ graph.set(_Y, 0);
+ graph.set(WIDTH, w);
+ graph.set(HEIGHT, h);
+ }
+ }
+ this._drawing = false;
+ if(this._callLater)
+ {
+ this._redraw();
+ return;
+ }
+ if(graph)
+ {
+ graph.set(_X, x);
+ graph.set(_Y, y);
+ }
+ if(legend)
+ {
+ legend.set(_X, legendX);
+ legend.set(_Y, legendY);
+ }
+ }
+}, {
+ ATTRS: {
+ /**
+ * The legend for the chart.
+ *
+ * @attribute
+ * @type Legend
+ */
+ legend: LEGEND
+ }
+});
+Y.PieChart = PieChartLegend;
+/**
+ * ChartLegend provides a legend for a chart.
+ *
+ * @class ChartLegend
+ * @module charts
+ * @submodule charts-legend
+ * @extends Widget
+ */
+Y.ChartLegend = Y.Base.create("chartlegend", Y.Widget, [Y.Renderer], {
+ /**
+ * Initializes the chart.
+ *
+ * @method initializer
+ * @private
+ */
+ initializer: function()
+ {
+ this._items = [];
+ },
+
+ /**
+ * @method renderUI
+ * @private
+ */
+ renderUI: function()
+ {
+ var bb = this.get("boundingBox"),
+ cb = this.get("contentBox"),
+ styles = this.get("styles").background,
+ background = new Y.Rect({
+ graphic: cb,
+ fill: styles.fill,
+ stroke: styles.border
+ });
+ bb.setStyle("display", "block");
+ bb.setStyle("position", "absolute");
+ this.set("background", background);
+ },
+
+ /**
+ * @method bindUI
+ * @private
+ */
+ bindUI: function()
+ {
+ this.get("chart").after("seriesCollectionChange", Y.bind(this._updateHandler, this));
+ this.get("chart").after("stylesChange", Y.bind(this._updateHandler, this));
+ this.after("stylesChange", this._updateHandler);
+ this.after("positionChange", this._positionChangeHandler);
+ this.after("widthChange", this._handleSizeChange);
+ this.after("heightChange", this._handleSizeChange);
+ },
+
+ /**
+ * @method syncUI
+ * @private
+ */
+ syncUI: function()
+ {
+ var w = this.get("width"),
+ h = this.get("height");
+ if(isFinite(w) && isFinite(h) && w > 0 && h > 0)
+ {
+ this._drawLegend();
+ }
+ },
+
+ /**
+ * Handles changes to legend.
+ *
+ * @method _updateHandler
+ * @param {Object} e Event object
+ * @private
+ */
+ _updateHandler: function()
+ {
+ if(this.get("rendered"))
+ {
+ this._drawLegend();
+ }
+ },
+
+ /**
+ * Handles position changes.
+ *
+ * @method _positionChangeHandler
+ * @param {Object} e Event object
+ * @private
+ */
+ _positionChangeHandler: function()
+ {
+ var chart = this.get("chart"),
+ parentNode = this._parentNode;
+ if(parentNode && ((chart && this.get("includeInChartLayout"))))
+ {
+ this.fire("legendRendered");
+ }
+ else if(this.get("rendered"))
+ {
+ this._drawLegend();
+ }
+ },
+
+ /**
+ * Updates the legend when the size changes.
+ *
+ * @method _handleSizeChange
+ * @param {Object} e Event object.
+ * @private
+ */
+ _handleSizeChange: function(e)
+ {
+ var attrName = e.attrName,
+ pos = this.get(POSITION),
+ vert = pos === LEFT || pos === RIGHT,
+ hor = pos === BOTTOM || pos === TOP;
+ if((hor && attrName === WIDTH) || (vert && attrName === HEIGHT))
+ {
+ this._drawLegend();
+ }
+ },
+
+ /**
+ * Draws the legend
+ *
+ * @method _drawLegend
+ * @private
+ */
+ _drawLegend: function()
+ {
+ if(this._drawing)
+ {
+ this._callLater = true;
+ return;
+ }
+ this._drawing = true;
+ this._callLater = false;
+ if(this.get("includeInChartLayout"))
+ {
+ this.get("chart")._itemRenderQueue.unshift(this);
+ }
+ var chart = this.get("chart"),
+ node = this.get("contentBox"),
+ seriesCollection = chart.get("seriesCollection"),
+ series,
+ styles = this.get("styles"),
+ padding = styles.padding,
+ itemStyles = styles.item,
+ seriesStyles,
+ hSpacing = itemStyles.hSpacing,
+ vSpacing = itemStyles.vSpacing,
+ direction = this.get("direction"),
+ align = direction === "vertical" ? styles.vAlign : styles.hAlign,
+ marker = styles.marker,
+ labelStyles = itemStyles.label,
+ displayName,
+ layout = this._layout[direction],
+ i,
+ len,
+ isArray,
+ legendShape,
+ shape,
+ shapeClass,
+ item,
+ fill,
+ border,
+ fillColors,
+ borderColors,
+ borderWeight,
+ items = [],
+ markerWidth = marker.width,
+ markerHeight = marker.height,
+ totalWidth = 0 - hSpacing,
+ totalHeight = 0 - vSpacing,
+ maxWidth = 0,
+ maxHeight = 0,
+ itemWidth,
+ itemHeight;
+ if(marker && marker.shape)
+ {
+ legendShape = marker.shape;
+ }
+ this._destroyLegendItems();
+ if(chart instanceof Y.PieChart)
+ {
+ series = seriesCollection[0];
+ displayName = series.get("categoryAxis").getDataByKey(series.get("categoryKey"));
+ seriesStyles = series.get("styles").marker;
+ fillColors = seriesStyles.fill.colors;
+ borderColors = seriesStyles.border.colors;
+ borderWeight = seriesStyles.border.weight;
+ i = 0;
+ len = displayName.length;
+ shape = legendShape || Y.Circle;
+ isArray = Y.Lang.isArray(shape);
+ for(; i < len; ++i)
+ {
+ shape = isArray ? shape[i] : shape;
+ fill = {
+ color: fillColors[i]
+ };
+ border = {
+ colors: borderColors[i],
+ weight: borderWeight
+ };
+ displayName = chart.getSeriesItems(series, i).category.value;
+ item = this._getLegendItem(node, this._getShapeClass(shape), fill, border, labelStyles, markerWidth, markerHeight, displayName);
+ itemWidth = item.width;
+ itemHeight = item.height;
+ maxWidth = Math.max(maxWidth, itemWidth);
+ maxHeight = Math.max(maxHeight, itemHeight);
+ totalWidth += itemWidth + hSpacing;
+ totalHeight += itemHeight + vSpacing;
+ items.push(item);
+ }
+ }
+ else
+ {
+ i = 0;
+ len = seriesCollection.length;
+ for(; i < len; ++i)
+ {
+ series = seriesCollection[i];
+ seriesStyles = this._getStylesBySeriesType(series, shape);
+ if(!legendShape)
+ {
+ shape = seriesStyles.shape;
+ if(!shape)
+ {
+ shape = Y.Circle;
+ }
+ }
+ shapeClass = Y.Lang.isArray(shape) ? shape[i] : shape;
+ item = this._getLegendItem(
+ node,
+ this._getShapeClass(shape),
+ seriesStyles.fill,
+ seriesStyles.border,
+ labelStyles,
+ markerWidth,
+ markerHeight,
+ series.get("valueDisplayName")
+ );
+ itemWidth = item.width;
+ itemHeight = item.height;
+ maxWidth = Math.max(maxWidth, itemWidth);
+ maxHeight = Math.max(maxHeight, itemHeight);
+ totalWidth += itemWidth + hSpacing;
+ totalHeight += itemHeight + vSpacing;
+ items.push(item);
+ }
+ }
+ this._drawing = false;
+ if(this._callLater)
+ {
+ this._drawLegend();
+ }
+ else
+ {
+ layout._positionLegendItems.apply(
+ this,
+ [items, maxWidth, maxHeight, totalWidth, totalHeight, padding, hSpacing, vSpacing, align]
+ );
+ this._updateBackground(styles);
+ this.fire("legendRendered");
+ }
+ },
+
+ /**
+ * Updates the background for the legend.
+ *
+ * @method _updateBackground
+ * @param {Object} styles Reference to the legend's styles attribute
+ * @private
+ */
+ _updateBackground: function(styles)
+ {
+ var backgroundStyles = styles.background,
+ contentRect = this._contentRect,
+ padding = styles.padding,
+ x = contentRect.left - padding.left,
+ y = contentRect.top - padding.top,
+ w = contentRect.right - x + padding.right,
+ h = contentRect.bottom - y + padding.bottom;
+ this.get("background").set({
+ fill: backgroundStyles.fill,
+ stroke: backgroundStyles.border,
+ width: w,
+ height: h,
+ x: x,
+ y: y
+ });
+ },
+
+ /**
+ * Retrieves the marker styles based on the type of series. For series that contain a marker, the marker styles are returned.
+ *
+ * @method _getStylesBySeriesType
+ * @param {CartesianSeries | PieSeries} The series in which the style properties will be received.
+ * @return Object An object containing fill, border and shape information.
+ * @private
+ */
+ _getStylesBySeriesType: function(series)
+ {
+ var styles = series.get("styles"),
+ color;
+ if(series instanceof Y.LineSeries || series instanceof Y.StackedLineSeries)
+ {
+ styles = series.get("styles").line;
+ color = styles.color || series._getDefaultColor(series.get("graphOrder"), "line");
+ return {
+ border: {
+ weight: 1,
+ color: color
+ },
+ fill: {
+ color: color
+ }
+ };
+ }
+ else if(series instanceof Y.AreaSeries || series instanceof Y.StackedAreaSeries)
+ {
+ styles = series.get("styles").area;
+ color = styles.color || series._getDefaultColor(series.get("graphOrder"), "slice");
+ return {
+ border: {
+ weight: 1,
+ color: color
+ },
+ fill: {
+ color: color
+ }
+ };
+ }
+ else
+ {
+ styles = series.get("styles").marker;
+ return {
+ fill: styles.fill,
+
+ border: {
+ weight: styles.border.weight,
+
+ color: styles.border.color,
+
+ shape: styles.shape
+ },
+ shape: styles.shape
+ };
+ }
+ },
+
+ /**
+ * Returns a legend item consisting of the following properties:
+ * <dl>
+ * <dt>node</dt><dd>The `Node` containing the legend item elements.</dd>
+ * <dt>shape</dt><dd>The `Shape` element for the legend item.</dd>
+ * <dt>textNode</dt><dd>The `Node` containing the text></dd>
+ * <dt>text</dt><dd></dd>
+ * </dl>
+ *
+ * @method _getLegendItem
+ * @param {Node} shapeProps Reference to the `node` attribute.
+ * @param {String | Class} shapeClass The type of shape
+ * @param {Object} fill Properties for the shape's fill
+ * @param {Object} border Properties for the shape's border
+ * @param {String} text String to be rendered as the legend's text
+ * @param {Number} width Total width of the legend item
+ * @param {Number} height Total height of the legend item
+ * @param {HTML | String} text Text for the legendItem
+ * @return Object
+ * @private
+ */
+ _getLegendItem: function(node, shapeClass, fill, border, labelStyles, w, h, text)
+ {
+ var containerNode = Y.one(DOCUMENT.createElement("div")),
+ textField = Y.one(DOCUMENT.createElement("span")),
+ shape,
+ dimension,
+ padding,
+ left,
+ item,
+ ShapeClass = shapeClass;
+ containerNode.setStyle(POSITION, "absolute");
+ textField.setStyle(POSITION, "absolute");
+ textField.setStyles(labelStyles);
+ textField.appendChild(DOCUMENT.createTextNode(text));
+ containerNode.appendChild(textField);
+ node.appendChild(containerNode);
+ dimension = textField.get("offsetHeight");
+ padding = dimension - h;
+ left = w + padding + 2;
+ textField.setStyle("left", left + PX);
+ containerNode.setStyle("height", dimension + PX);
+ containerNode.setStyle("width", (left + textField.get("offsetWidth")) + PX);
+ shape = new ShapeClass({
+ fill: fill,
+ stroke: border,
+ width: w,
+ height: h,
+ x: padding * 0.5,
+ y: padding * 0.5,
+ w: w,
+ h: h,
+ graphic: containerNode
+ });
+ textField.setStyle("left", dimension + PX);
+ item = {
+ node: containerNode,
+ width: containerNode.get("offsetWidth"),
+ height: containerNode.get("offsetHeight"),
+ shape: shape,
+ textNode: textField,
+ text: text
+ };
+ this._items.push(item);
+ return item;
+ },
+
+ /**
+ * Evaluates and returns correct class for drawing a shape.
+ *
+ * @method _getShapeClass
+ * @return Shape
+ * @private
+ */
+ _getShapeClass: function()
+ {
+ var graphic = this.get("background").get("graphic");
+ return graphic._getShapeClass.apply(graphic, arguments);
+ },
+
+ /**
+ * Returns the default hash for the `styles` attribute.
+ *
+ * @method _getDefaultStyles
+ * @return Object
+ * @protected
+ */
+ _getDefaultStyles: function()
+ {
+ var styles = {
+ padding: {
+ top: 8,
+ right: 8,
+ bottom: 8,
+ left: 9
+ },
+ gap: 10,
+ hAlign: "center",
+ vAlign: "top",
+ marker: this._getPlotDefaults(),
+ item: {
+ hSpacing: 10,
+ vSpacing: 5,
+ label: {
+ color:"#808080",
+ fontSize:"85%",
+ whiteSpace: "nowrap"
+ }
+ },
+ background: {
+ shape: "rect",
+ fill:{
+ color:"#faf9f2"
+ },
+ border: {
+ color:"#dad8c9",
+ weight: 1
+ }
+ }
+ };
+ return styles;
+ },
+
+ /**
+ * Gets the default values for series that use the utility. This method is used by
+ * the class' `styles` attribute's getter to get build default values.
+ *
+ * @method _getPlotDefaults
+ * @return Object
+ * @protected
+ */
+ _getPlotDefaults: function()
+ {
+ var defs = {
+ width: 10,
+ height: 10
+ };
+ return defs;
+ },
+
+ /**
+ * Destroys legend items.
+ *
+ * @method _destroyLegendItems
+ * @private
+ */
+ _destroyLegendItems: function()
+ {
+ var item;
+ if(this._items)
+ {
+ while(this._items.length > 0)
+ {
+ item = this._items.shift();
+ item.shape.get("graphic").destroy();
+ item.node.empty();
+ item.node.destroy(true);
+ item.node = null;
+ item = null;
+ }
+ }
+ this._items = [];
+ },
+
+ /**
+ * Maps layout classes.
+ *
+ * @property _layout
+ * @private
+ */
+ _layout: {
+ vertical: VerticalLegendLayout,
+ horizontal: HorizontalLegendLayout
+ },
+
+ /**
+ * Destructor implementation ChartLegend class. Removes all items and the Graphic instance from the widget.
+ *
+ * @method destructor
+ * @protected
+ */
+ destructor: function()
+ {
+ var background = this.get("background"),
+ backgroundGraphic;
+ this._destroyLegendItems();
+ if(background)
+ {
+ backgroundGraphic = background.get("graphic");
+ if(backgroundGraphic)
+ {
+ backgroundGraphic.destroy();
+ }
+ else
+ {
+ background.destroy();
+ }
+ }
+
+ }
+}, {
+ ATTRS: {
+ /**
+ * Indicates whether the chart's contentBox is the parentNode for the legend.
+ *
+ * @attribute includeInChartLayout
+ * @type Boolean
+ * @private
+ */
+ includeInChartLayout: {
+ value: false
+ },
+
+ /**
+ * Reference to the `Chart` instance.
+ *
+ * @attribute chart
+ * @type Chart
+ */
+ chart: {
+ setter: function(val)
+ {
+ this.after("legendRendered", Y.bind(val._itemRendered, val));
+ return val;
+ }
+ },
+
+ /**
+ * Indicates the direction in relation of the legend's layout. The `direction` of the legend is determined by its
+ * `position` value.
+ *
+ * @attribute direction
+ * @type String
+ */
+ direction: {
+ value: "vertical"
+ },
+
+ /**
+ * Indicates the position and direction of the legend. Possible values are `left`, `top`, `right` and `bottom`.
+ * Values of `left` and `right` values have a `direction` of `vertical`. Values of `top` and `bottom` values have
+ * a `direction` of `horizontal`.
+ *
+ * @attribute position
+ * @type String
+ */
+ position: {
+ lazyAdd: false,
+
+ value: "right",
+
+ setter: function(val)
+ {
+ if(val === TOP || val === BOTTOM)
+ {
+ this.set("direction", HORIZONTAL);
+ }
+ else if(val === LEFT || val === RIGHT)
+ {
+ this.set("direction", VERTICAL);
+ }
+ return val;
+ }
+ },
+
+ /**
+ * The width of the legend. Depending on the implementation of the ChartLegend, this value is `readOnly`.
+ * By default, the legend is included in the layout of the `Chart` that it references. Under this circumstance,
+ * `width` is always `readOnly`. When the legend is rendered in its own dom element, the `readOnly` status is
+ * determined by the direction of the legend. If the `position` is `left` or `right` or the `direction` is
+ * `vertical`, width is `readOnly`. If the position is `top` or `bottom` or the `direction` is `horizontal`,
+ * width can be explicitly set. If width is not explicitly set, the width will be determined by the width of the
+ * legend's parent element.
+ *
+ * @attribute width
+ * @type Number
+ */
+ width: {
+ getter: function()
+ {
+ var chart = this.get("chart"),
+ parentNode = this._parentNode;
+ if(parentNode)
+ {
+ if((chart && this.get("includeInChartLayout")) || this._width)
+ {
+ if(!this._width)
+ {
+ this._width = 0;
+ }
+ return this._width;
+ }
+ else
+ {
+ return parentNode.get("offsetWidth");
+ }
+ }
+ return "";
+ },
+
+ setter: function(val)
+ {
+ this._width = val;
+ return val;
+ }
+ },
+
+ /**
+ * The height of the legend. Depending on the implementation of the ChartLegend, this value is `readOnly`.
+ * By default, the legend is included in the layout of the `Chart` that it references. Under this circumstance,
+ * `height` is always `readOnly`. When the legend is rendered in its own dom element, the `readOnly` status is
+ * determined by the direction of the legend. If the `position` is `top` or `bottom` or the `direction` is
+ * `horizontal`, height is `readOnly`. If the position is `left` or `right` or the `direction` is `vertical`,
+ * height can be explicitly set. If height is not explicitly set, the height will be determined by the width of the
+ * legend's parent element.
+ *
+ * @attribute height
+ * @type Number
+ */
+ height: {
+ valueFn: "_heightGetter",
+
+ getter: function()
+ {
+ var chart = this.get("chart"),
+ parentNode = this._parentNode;
+ if(parentNode)
+ {
+ if((chart && this.get("includeInChartLayout")) || this._height)
+ {
+ if(!this._height)
+ {
+ this._height = 0;
+ }
+ return this._height;
+ }
+ else
+ {
+ return parentNode.get("offsetHeight");
+ }
+ }
+ return "";
+ },
+
+ setter: function(val)
+ {
+ this._height = val;
+ return val;
+ }
+ },
+
+ /**
+ * Indicates the x position of legend.
+ *
+ * @attribute x
+ * @type Number
+ * @readOnly
+ */
+ x: {
+ lazyAdd: false,
+
+ value: 0,
+
+ setter: function(val)
+ {
+ var node = this.get("boundingBox");
+ if(node)
+ {
+ node.setStyle(LEFT, val + PX);
+ }
+ return val;
+ }
+ },
+
+ /**
+ * Indicates the y position of legend.
+ *
+ * @attribute y
+ * @type Number
+ * @readOnly
+ */
+ y: {
+ lazyAdd: false,
+
+ value: 0,
+
+ setter: function(val)
+ {
+ var node = this.get("boundingBox");
+ if(node)
+ {
+ node.setStyle(TOP, val + PX);
+ }
+ return val;
+ }
+ },
+
+ /**
+ * Array of items contained in the legend. Each item is an object containing the following properties:
+ *
+ * <dl>
+ * <dt>node</dt><dd>Node containing text for the legend item.</dd>
+ * <dt>marker</dt><dd>Shape for the legend item.</dd>
+ * </dl>
+ *
+ * @attribute items
+ * @type Array
+ * @readOnly
+ */
+ items: {
+ getter: function()
+ {
+ return this._items;
+ }
+ },
+
+ /**
+ * Background for the legend.
+ *
+ * @attribute background
+ * @type Rect
+ */
+ background: {}
+
+ /**
+ * Properties used to display and style the ChartLegend. This attribute is inherited from `Renderer`.
+ * Below are the default values:
+ *
+ * <dl>
+ * <dt>gap</dt><dd>Distance, in pixels, between the `ChartLegend` instance and the chart's content. When `ChartLegend`
+ * is rendered within a `Chart` instance this value is applied.</dd>
+ * <dt>hAlign</dt><dd>Defines the horizontal alignment of the `items` in a `ChartLegend` rendered in a horizontal direction.
+ * This value is applied when the instance's `position` is set to top or bottom. This attribute can be set to left, center
+ * or right. The default value is center.</dd>
+ * <dt>vAlign</dt><dd>Defines the vertical alignment of the `items` in a `ChartLegend` rendered in vertical direction. This
+ * value is applied when the instance's `position` is set to left or right. The attribute can be set to top, middle or
+ * bottom. The default value is middle.</dd>
+ * <dt>item</dt><dd>Set of style properties applied to the `items` of the `ChartLegend`.
+ * <dl>
+ * <dt>hSpacing</dt><dd>Horizontal distance, in pixels, between legend `items`.</dd>
+ * <dt>vSpacing</dt><dd>Vertical distance, in pixels, between legend `items`.</dd>
+ * <dt>label</dt><dd>Properties for the text of an `item`.
+ * <dl>
+ * <dt>color</dt><dd>Color of the text. The default values is "#808080".</dd>
+ * <dt>fontSize</dt><dd>Font size for the text. The default value is "85%".</dd>
+ * </dl>
+ * </dd>
+ * <dt>marker</dt><dd>Properties for the `item` markers.
+ * <dl>
+ * <dt>width</dt><dd>Specifies the width of the markers.</dd>
+ * <dt>height</dt><dd>Specifies the height of the markers.</dd>
+ * </dl>
+ * </dd>
+ * </dl>
+ * </dd>
+ * <dt>background</dt><dd>Properties for the `ChartLegend` background.
+ * <dl>
+ * <dt>fill</dt><dd>Properties for the background fill.
+ * <dl>
+ * <dt>color</dt><dd>Color for the fill. The default value is "#faf9f2".</dd>
+ * </dl>
+ * </dd>
+ * <dt>border</dt><dd>Properties for the background border.
+ * <dl>
+ * <dt>color</dt><dd>Color for the border. The default value is "#dad8c9".</dd>
+ * <dt>weight</dt><dd>Weight of the border. The default values is 1.</dd>
+ * </dl>
+ * </dd>
+ * </dl>
+ * </dd>
+ * </dl>
+ *
+ * @attribute styles
+ * @type Object
+ */
+ }
+});
+
+
+}, '3.10.3', {"requires": ["charts-base"]});