NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / charts-legend / charts-legend.js
bloba3f713ded8225bbbd5b9783e48f7de30bf74b89e
1 /*
2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
8 YUI.add('charts-legend', function (Y, NAME) {
10 /**
11  * Adds legend functionality to charts.
12  *
13  * @module charts
14  * @submodule charts-legend
15  */
16 var DOCUMENT = Y.config.doc,
17 TOP = "top",
18 RIGHT = "right",
19 BOTTOM = "bottom",
20 LEFT = "left",
21 EXTERNAL = "external",
22 HORIZONTAL = "horizontal",
23 VERTICAL = "vertical",
24 WIDTH = "width",
25 HEIGHT = "height",
26 POSITION = "position",
27 _X = "x",
28 _Y = "y",
29 PX = "px",
30 PieChartLegend,
31 LEGEND = {
32     setter: function(val)
33     {
34         var legend = this.get("legend");
35         if(legend)
36         {
37             legend.destroy(true);
38         }
39         if(val instanceof Y.ChartLegend)
40         {
41             legend = val;
42             legend.set("chart", this);
43         }
44         else
45         {
46             val.chart = this;
47             if(!val.hasOwnProperty("render"))
48             {
49                 val.render = this.get("contentBox");
50                 val.includeInChartLayout = true;
51             }
52             legend = new Y.ChartLegend(val);
53         }
54         return legend;
55     }
58 /**
59  * Contains methods for displaying items horizontally in a legend.
60  *
61  * @module charts
62  * @submodule charts-legend
63  * @class HorizontalLegendLayout
64  */
65 HorizontalLegendLayout = {
66     /**
67      * Displays items horizontally in a legend.
68      *
69      * @method _positionLegendItems
70      * @param {Array} items Array of items to display in the legend.
71      * @param {Number} maxWidth The width of the largest item in the legend.
72      * @param {Number} maxHeight The height of the largest item in the legend.
73      * @param {Number} totalWidth The total width of all items in a legend.
74      * @param {Number} totalHeight The total height of all items in a legend.
75      * @param {Number} padding The left, top, right and bottom padding properties for the legend.
76      * @param {Number} horizontalGap The horizontal distance between items in a legend.
77      * @param {Number} verticalGap The vertical distance between items in a legend.
78      * @param {String} hAlign The horizontal alignment of the legend.
79      * @protected
80      */
81     _positionLegendItems: function(items, maxWidth, maxHeight, totalWidth, totalHeight, padding, horizontalGap, verticalGap, hAlign)
82     {
83         var i = 0,
84             rowIterator = 0,
85             item,
86             node,
87             itemWidth,
88             itemHeight,
89             len,
90             width = this.get("width"),
91             rows,
92             rowsLen,
93             row,
94             totalWidthArray,
95             legendWidth,
96             topHeight = padding.top - verticalGap,
97             limit = width - (padding.left + padding.right),
98             left,
99             top,
100             right,
101             bottom;
102         HorizontalLegendLayout._setRowArrays(items, limit, horizontalGap);
103         rows = HorizontalLegendLayout.rowArray;
104         totalWidthArray = HorizontalLegendLayout.totalWidthArray;
105         rowsLen = rows.length;
106         for(; rowIterator < rowsLen; ++ rowIterator)
107         {
108             topHeight += verticalGap;
109             row = rows[rowIterator];
110             len = row.length;
111             legendWidth =  HorizontalLegendLayout.getStartPoint(width, totalWidthArray[rowIterator], hAlign, padding);
112             for(i = 0; i < len; ++i)
113             {
114                 item = row[i];
115                 node = item.node;
116                 itemWidth = item.width;
117                 itemHeight = item.height;
118                 item.x = legendWidth;
119                 item.y = 0;
120                 left = !isNaN(left) ? Math.min(left, legendWidth) : legendWidth;
121                 top = !isNaN(top) ? Math.min(top, topHeight) : topHeight;
122                 right = !isNaN(right) ? Math.max(legendWidth + itemWidth, right) : legendWidth + itemWidth;
123                 bottom = !isNaN(bottom) ? Math.max(topHeight + itemHeight, bottom) : topHeight + itemHeight;
124                 node.setStyle("left", legendWidth + PX);
125                 node.setStyle("top", topHeight + PX);
126                 legendWidth += itemWidth + horizontalGap;
127             }
128             topHeight += item.height;
129         }
130         this._contentRect = {
131             left: left,
132             top: top,
133             right: right,
134             bottom: bottom
135         };
136         if(this.get("includeInChartLayout"))
137         {
138             this.set("height", topHeight + padding.bottom);
139         }
140     },
142     /**
143      * Creates row and total width arrays used for displaying multiple rows of
144      * legend items based on the items, available width and horizontalGap for the legend.
145      *
146      * @method _setRowArrays
147      * @param {Array} items Array of legend items to display in a legend.
148      * @param {Number} limit Total available width for displaying items in a legend.
149      * @param {Number} horizontalGap Horizontal distance between items in a legend.
150      * @protected
151      */
152     _setRowArrays: function(items, limit, horizontalGap)
153     {
154         var item = items[0],
155             rowArray = [[item]],
156             i = 1,
157             rowIterator = 0,
158             len = items.length,
159             totalWidth = item.width,
160             itemWidth,
161             totalWidthArray = [[totalWidth]];
162         for(; i < len; ++i)
163         {
164             item = items[i];
165             itemWidth = item.width;
166             if((totalWidth + horizontalGap + itemWidth) <= limit)
167             {
168                 totalWidth += horizontalGap + itemWidth;
169                 rowArray[rowIterator].push(item);
170             }
171             else
172             {
173                 totalWidth = horizontalGap + itemWidth;
174                 if(rowArray[rowIterator])
175                 {
176                     rowIterator += 1;
177                 }
178                 rowArray[rowIterator] = [item];
179             }
180             totalWidthArray[rowIterator] = totalWidth;
181         }
182         HorizontalLegendLayout.rowArray = rowArray;
183         HorizontalLegendLayout.totalWidthArray = totalWidthArray;
184     },
186     /**
187      * Returns the starting x-coordinate for a row of legend items.
188      *
189      * @method getStartPoint
190      * @param {Number} w Width of the legend.
191      * @param {Number} totalWidth Total width of all labels in the row.
192      * @param {String} align Horizontal alignment of items for the legend.
193      * @param {Object} padding Object contain left, top, right and bottom padding properties.
194      * @return Number
195      * @protected
196      */
197     getStartPoint: function(w, totalWidth, align, padding)
198     {
199         var startPoint;
200         switch(align)
201         {
202             case LEFT :
203                 startPoint = padding.left;
204             break;
205             case "center" :
206                 startPoint = (w - totalWidth) * 0.5;
207             break;
208             case RIGHT :
209                 startPoint = w - totalWidth - padding.right;
210             break;
211         }
212         return startPoint;
213     }
217  * Contains methods for displaying items vertically in a legend.
219  * @module charts
220  * @submodule charts-legend
221  * @class VerticalLegendLayout
222  */
223 VerticalLegendLayout = {
224     /**
225      * Displays items vertically in a legend.
226      *
227      * @method _positionLegendItems
228      * @param {Array} items Array of items to display in the legend.
229      * @param {Number} maxWidth The width of the largest item in the legend.
230      * @param {Number} maxHeight The height of the largest item in the legend.
231      * @param {Number} totalWidth The total width of all items in a legend.
232      * @param {Number} totalHeight The total height of all items in a legend.
233      * @param {Number} padding The left, top, right and bottom padding properties for the legend.
234      * @param {Number} horizontalGap The horizontal distance between items in a legend.
235      * @param {Number} verticalGap The vertical distance between items in a legend.
236      * @param {String} vAlign The vertical alignment of the legend.
237      * @protected
238      */
239     _positionLegendItems: function(items, maxWidth, maxHeight, totalWidth, totalHeight, padding, horizontalGap, verticalGap, vAlign)
240     {
241         var i = 0,
242             columnIterator = 0,
243             item,
244             node,
245             itemHeight,
246             itemWidth,
247             len,
248             height = this.get("height"),
249             columns,
250             columnsLen,
251             column,
252             totalHeightArray,
253             legendHeight,
254             leftWidth = padding.left - horizontalGap,
255             legendWidth,
256             limit = height - (padding.top + padding.bottom),
257             left,
258             top,
259             right,
260             bottom;
261         VerticalLegendLayout._setColumnArrays(items, limit, verticalGap);
262         columns = VerticalLegendLayout.columnArray;
263         totalHeightArray = VerticalLegendLayout.totalHeightArray;
264         columnsLen = columns.length;
265         for(; columnIterator < columnsLen; ++ columnIterator)
266         {
267             leftWidth += horizontalGap;
268             column = columns[columnIterator];
269             len = column.length;
270             legendHeight =  VerticalLegendLayout.getStartPoint(height, totalHeightArray[columnIterator], vAlign, padding);
271             legendWidth = 0;
272             for(i = 0; i < len; ++i)
273             {
274                 item = column[i];
275                 node = item.node;
276                 itemHeight = item.height;
277                 itemWidth = item.width;
278                 item.y = legendHeight;
279                 item.x = leftWidth;
280                 left = !isNaN(left) ? Math.min(left, leftWidth) : leftWidth;
281                 top = !isNaN(top) ? Math.min(top, legendHeight) : legendHeight;
282                 right = !isNaN(right) ? Math.max(leftWidth + itemWidth, right) : leftWidth + itemWidth;
283                 bottom = !isNaN(bottom) ? Math.max(legendHeight + itemHeight, bottom) : legendHeight + itemHeight;
284                 node.setStyle("left", leftWidth + PX);
285                 node.setStyle("top", legendHeight + PX);
286                 legendHeight += itemHeight + verticalGap;
287                 legendWidth = Math.max(legendWidth, item.width);
288             }
289             leftWidth += legendWidth;
290         }
291         this._contentRect = {
292             left: left,
293             top: top,
294             right: right,
295             bottom: bottom
296         };
297         if(this.get("includeInChartLayout"))
298         {
299             this.set("width", leftWidth + padding.right);
300         }
301     },
303     /**
304      * Creates column and total height arrays used for displaying multiple columns of
305      * legend items based on the items, available height and verticalGap for the legend.
306      *
307      * @method _setColumnArrays
308      * @param {Array} items Array of legend items to display in a legend.
309      * @param {Number} limit Total available height for displaying items in a legend.
310      * @param {Number} verticalGap Vertical distance between items in a legend.
311      * @protected
312      */
313     _setColumnArrays: function(items, limit, verticalGap)
314     {
315         var item = items[0],
316             columnArray = [[item]],
317             i = 1,
318             columnIterator = 0,
319             len = items.length,
320             totalHeight = item.height,
321             itemHeight,
322             totalHeightArray = [[totalHeight]];
323         for(; i < len; ++i)
324         {
325             item = items[i];
326             itemHeight = item.height;
327             if((totalHeight + verticalGap + itemHeight) <= limit)
328             {
329                 totalHeight += verticalGap + itemHeight;
330                 columnArray[columnIterator].push(item);
331             }
332             else
333             {
334                 totalHeight = verticalGap + itemHeight;
335                 if(columnArray[columnIterator])
336                 {
337                     columnIterator += 1;
338                 }
339                 columnArray[columnIterator] = [item];
340             }
341             totalHeightArray[columnIterator] = totalHeight;
342         }
343         VerticalLegendLayout.columnArray = columnArray;
344         VerticalLegendLayout.totalHeightArray = totalHeightArray;
345     },
347     /**
348      * Returns the starting y-coordinate for a column of legend items.
349      *
350      * @method getStartPoint
351      * @param {Number} h Height of the legend.
352      * @param {Number} totalHeight Total height of all labels in the column.
353      * @param {String} align Vertical alignment of items for the legend.
354      * @param {Object} padding Object contain left, top, right and bottom padding properties.
355      * @return Number
356      * @protected
357      */
358     getStartPoint: function(h, totalHeight, align, padding)
359     {
360         var startPoint;
361         switch(align)
362         {
363             case TOP :
364                 startPoint = padding.top;
365             break;
366             case "middle" :
367                 startPoint = (h - totalHeight) * 0.5;
368             break;
369             case BOTTOM :
370                 startPoint = h - totalHeight - padding.bottom;
371             break;
372         }
373         return startPoint;
374     }
377 CartesianChartLegend = Y.Base.create("cartesianChartLegend", Y.CartesianChart, [], {
378     /**
379      * Redraws and position all the components of the chart instance.
380      *
381      * @method _redraw
382      * @private
383      */
384     _redraw: function()
385     {
386         if(this._drawing)
387         {
388             this._callLater = true;
389             return;
390         }
391         this._drawing = true;
392         this._callLater = false;
393         var w = this.get("width"),
394             h = this.get("height"),
395             layoutBoxDimensions = this._getLayoutBoxDimensions(),
396             leftPaneWidth = layoutBoxDimensions.left,
397             rightPaneWidth = layoutBoxDimensions.right,
398             topPaneHeight = layoutBoxDimensions.top,
399             bottomPaneHeight = layoutBoxDimensions.bottom,
400             leftAxesCollection = this.get("leftAxesCollection"),
401             rightAxesCollection = this.get("rightAxesCollection"),
402             topAxesCollection = this.get("topAxesCollection"),
403             bottomAxesCollection = this.get("bottomAxesCollection"),
404             i = 0,
405             l,
406             axis,
407             graphOverflow = "visible",
408             graph = this.get("graph"),
409             topOverflow,
410             bottomOverflow,
411             leftOverflow,
412             rightOverflow,
413             graphWidth,
414             graphHeight,
415             graphX,
416             graphY,
417             allowContentOverflow = this.get("allowContentOverflow"),
418             diff,
419             rightAxesXCoords,
420             leftAxesXCoords,
421             topAxesYCoords,
422             bottomAxesYCoords,
423             legend = this.get("legend"),
424             graphRect = {};
426         if(leftAxesCollection)
427         {
428             leftAxesXCoords = [];
429             l = leftAxesCollection.length;
430             for(i = l - 1; i > -1; --i)
431             {
432                 leftAxesXCoords.unshift(leftPaneWidth);
433                 leftPaneWidth += leftAxesCollection[i].get("width");
434             }
435         }
436         if(rightAxesCollection)
437         {
438             rightAxesXCoords = [];
439             l = rightAxesCollection.length;
440             i = 0;
441             for(i = l - 1; i > -1; --i)
442             {
443                 rightPaneWidth += rightAxesCollection[i].get("width");
444                 rightAxesXCoords.unshift(w - rightPaneWidth);
445             }
446         }
447         if(topAxesCollection)
448         {
449             topAxesYCoords = [];
450             l = topAxesCollection.length;
451             for(i = l - 1; i > -1; --i)
452             {
453                 topAxesYCoords.unshift(topPaneHeight);
454                 topPaneHeight += topAxesCollection[i].get("height");
455             }
456         }
457         if(bottomAxesCollection)
458         {
459             bottomAxesYCoords = [];
460             l = bottomAxesCollection.length;
461             for(i = l - 1; i > -1; --i)
462             {
463                 bottomPaneHeight += bottomAxesCollection[i].get("height");
464                 bottomAxesYCoords.unshift(h - bottomPaneHeight);
465             }
466         }
468         graphWidth = w - (leftPaneWidth + rightPaneWidth);
469         graphHeight = h - (bottomPaneHeight + topPaneHeight);
470         graphRect.left = leftPaneWidth;
471         graphRect.top = topPaneHeight;
472         graphRect.bottom = h - bottomPaneHeight;
473         graphRect.right = w - rightPaneWidth;
474         if(!allowContentOverflow)
475         {
476             topOverflow = this._getTopOverflow(leftAxesCollection, rightAxesCollection);
477             bottomOverflow = this._getBottomOverflow(leftAxesCollection, rightAxesCollection);
478             leftOverflow = this._getLeftOverflow(bottomAxesCollection, topAxesCollection);
479             rightOverflow = this._getRightOverflow(bottomAxesCollection, topAxesCollection);
481             diff = topOverflow - topPaneHeight;
482             if(diff > 0)
483             {
484                 graphRect.top = topOverflow;
485                 if(topAxesYCoords)
486                 {
487                     i = 0;
488                     l = topAxesYCoords.length;
489                     for(; i < l; ++i)
490                     {
491                         topAxesYCoords[i] += diff;
492                     }
493                 }
494             }
496             diff = bottomOverflow - bottomPaneHeight;
497             if(diff > 0)
498             {
499                 graphRect.bottom = h - bottomOverflow;
500                 if(bottomAxesYCoords)
501                 {
502                     i = 0;
503                     l = bottomAxesYCoords.length;
504                     for(; i < l; ++i)
505                     {
506                         bottomAxesYCoords[i] -= diff;
507                     }
508                 }
509             }
511             diff = leftOverflow - leftPaneWidth;
512             if(diff > 0)
513             {
514                 graphRect.left = leftOverflow;
515                 if(leftAxesXCoords)
516                 {
517                     i = 0;
518                     l = leftAxesXCoords.length;
519                     for(; i < l; ++i)
520                     {
521                         leftAxesXCoords[i] += diff;
522                     }
523                 }
524             }
526             diff = rightOverflow - rightPaneWidth;
527             if(diff > 0)
528             {
529                 graphRect.right = w - rightOverflow;
530                 if(rightAxesXCoords)
531                 {
532                     i = 0;
533                     l = rightAxesXCoords.length;
534                     for(; i < l; ++i)
535                     {
536                         rightAxesXCoords[i] -= diff;
537                     }
538                 }
539             }
540         }
541         graphWidth = graphRect.right - graphRect.left;
542         graphHeight = graphRect.bottom - graphRect.top;
543         graphX = graphRect.left;
544         graphY = graphRect.top;
545         if(legend)
546         {
547             if(legend.get("includeInChartLayout"))
548             {
549                 switch(legend.get("position"))
550                 {
551                     case "left" :
552                         legend.set("y", graphY);
553                         legend.set("height", graphHeight);
554                     break;
555                     case "top" :
556                         legend.set("x", graphX);
557                         legend.set("width", graphWidth);
558                     break;
559                     case "bottom" :
560                         legend.set("x", graphX);
561                         legend.set("width", graphWidth);
562                     break;
563                     case "right" :
564                         legend.set("y", graphY);
565                         legend.set("height", graphHeight);
566                     break;
567                 }
568             }
569         }
570         if(topAxesCollection)
571         {
572             l = topAxesCollection.length;
573             i = 0;
574             for(; i < l; i++)
575             {
576                 axis = topAxesCollection[i];
577                 if(axis.get("width") !== graphWidth)
578                 {
579                     axis.set("width", graphWidth);
580                 }
581                 axis.get("boundingBox").setStyle("left", graphX + PX);
582                 axis.get("boundingBox").setStyle("top", topAxesYCoords[i] + PX);
583             }
584             if(axis._hasDataOverflow())
585             {
586                 graphOverflow = "hidden";
587             }
588         }
589         if(bottomAxesCollection)
590         {
591             l = bottomAxesCollection.length;
592             i = 0;
593             for(; i < l; i++)
594             {
595                 axis = bottomAxesCollection[i];
596                 if(axis.get("width") !== graphWidth)
597                 {
598                     axis.set("width", graphWidth);
599                 }
600                 axis.get("boundingBox").setStyle("left", graphX + PX);
601                 axis.get("boundingBox").setStyle("top", bottomAxesYCoords[i] + PX);
602             }
603             if(axis._hasDataOverflow())
604             {
605                 graphOverflow = "hidden";
606             }
607         }
608         if(leftAxesCollection)
609         {
610             l = leftAxesCollection.length;
611             i = 0;
612             for(; i < l; ++i)
613             {
614                 axis = leftAxesCollection[i];
615                 axis.get("boundingBox").setStyle("top", graphY + PX);
616                 axis.get("boundingBox").setStyle("left", leftAxesXCoords[i] + PX);
617                 if(axis.get("height") !== graphHeight)
618                 {
619                     axis.set("height", graphHeight);
620                 }
621             }
622             if(axis._hasDataOverflow())
623             {
624                 graphOverflow = "hidden";
625             }
626         }
627         if(rightAxesCollection)
628         {
629             l = rightAxesCollection.length;
630             i = 0;
631             for(; i < l; ++i)
632             {
633                 axis = rightAxesCollection[i];
634                 axis.get("boundingBox").setStyle("top", graphY + PX);
635                 axis.get("boundingBox").setStyle("left", rightAxesXCoords[i] + PX);
636                 if(axis.get("height") !== graphHeight)
637                 {
638                     axis.set("height", graphHeight);
639                 }
640             }
641             if(axis._hasDataOverflow())
642             {
643                 graphOverflow = "hidden";
644             }
645         }
646         this._drawing = false;
647         if(this._callLater)
648         {
649             this._redraw();
650             return;
651         }
652         if(graph)
653         {
654             graph.get("boundingBox").setStyle("left", graphX + PX);
655             graph.get("boundingBox").setStyle("top", graphY + PX);
656             graph.set("width", graphWidth);
657             graph.set("height", graphHeight);
658             graph.get("boundingBox").setStyle("overflow", graphOverflow);
659         }
661         if(this._overlay)
662         {
663             this._overlay.setStyle("left", graphX + PX);
664             this._overlay.setStyle("top", graphY + PX);
665             this._overlay.setStyle("width", graphWidth + PX);
666             this._overlay.setStyle("height", graphHeight + PX);
667         }
668     },
670     /**
671      * Positions the legend in a chart and returns the properties of the legend to be used in the
672      * chart's layout algorithm.
673      *
674      * @method _getLayoutDimensions
675      * @return {Object} The left, top, right and bottom values for the legend.
676      * @protected
677      */
678     _getLayoutBoxDimensions: function()
679     {
680         var box = {
681                 top: 0,
682                 right: 0,
683                 bottom: 0,
684                 left: 0
685             },
686             legend = this.get("legend"),
687             position,
688             direction,
689             dimension,
690             size,
691             w = this.get(WIDTH),
692             h = this.get(HEIGHT),
693             gap;
694         if(legend && legend.get("includeInChartLayout"))
695         {
696             gap = legend.get("styles").gap;
697             position = legend.get(POSITION);
698             if(position !== EXTERNAL)
699             {
700                 direction = legend.get("direction");
701                 dimension = direction === HORIZONTAL ? HEIGHT : WIDTH;
702                 size = legend.get(dimension);
703                 box[position] = size + gap;
704                 switch(position)
705                 {
706                     case TOP :
707                         legend.set(_Y, 0);
708                     break;
709                     case BOTTOM :
710                         legend.set(_Y, h - size);
711                     break;
712                     case RIGHT :
713                         legend.set(_X, w - size);
714                     break;
715                     case LEFT:
716                         legend.set(_X, 0);
717                     break;
718                 }
719             }
720         }
721         return box;
722     },
724     /**
725      * Destructor implementation for the CartesianChart class. Calls destroy on all axes, series, legend (if available) and the Graph instance.
726      * Removes the tooltip and overlay HTML elements.
727      *
728      * @method destructor
729      * @protected
730      */
731     destructor: function()
732     {
733         var legend = this.get("legend");
734         if(legend)
735         {
736             legend.destroy(true);
737         }
738     }
739 }, {
740     ATTRS: {
741         legend: LEGEND
742     }
745 Y.CartesianChart = CartesianChartLegend;
747 PieChartLegend = Y.Base.create("pieChartLegend", Y.PieChart, [], {
748     /**
749      * Redraws the chart instance.
750      *
751      * @method _redraw
752      * @private
753      */
754     _redraw: function()
755     {
756         if(this._drawing)
757         {
758             this._callLater = true;
759             return;
760         }
761         this._drawing = true;
762         this._callLater = false;
763         var graph = this.get("graph"),
764             w = this.get("width"),
765             h = this.get("height"),
766             graphWidth,
767             graphHeight,
768             legend = this.get("legend"),
769             x = 0,
770             y = 0,
771             legendX = 0,
772             legendY = 0,
773             legendWidth,
774             legendHeight,
775             dimension,
776             gap,
777             position,
778             direction;
779         if(graph)
780         {
781             if(legend)
782             {
783                 position = legend.get("position");
784                 direction = legend.get("direction");
785                 graphWidth = graph.get("width");
786                 graphHeight = graph.get("height");
787                 legendWidth = legend.get("width");
788                 legendHeight = legend.get("height");
789                 gap = legend.get("styles").gap;
791                 if((direction === "vertical" && (graphWidth + legendWidth + gap !== w)) ||
792                     (direction === "horizontal" &&  (graphHeight + legendHeight + gap !== h)))
793                 {
794                     switch(legend.get("position"))
795                     {
796                         case LEFT :
797                             dimension = Math.min(w - (legendWidth + gap), h);
798                             legendHeight = h;
799                             x = legendWidth + gap;
800                             legend.set(HEIGHT, legendHeight);
801                         break;
802                         case TOP :
803                             dimension = Math.min(h - (legendHeight + gap), w);
804                             legendWidth = w;
805                             y = legendHeight + gap;
806                             legend.set(WIDTH, legendWidth);
807                         break;
808                         case RIGHT :
809                             dimension = Math.min(w - (legendWidth + gap), h);
810                             legendHeight = h;
811                             legendX = dimension + gap;
812                             legend.set(HEIGHT, legendHeight);
813                         break;
814                         case BOTTOM :
815                             dimension = Math.min(h - (legendHeight + gap), w);
816                             legendWidth = w;
817                             legendY = dimension + gap;
818                             legend.set(WIDTH, legendWidth);
819                         break;
820                     }
821                     graph.set(WIDTH, dimension);
822                     graph.set(HEIGHT, dimension);
823                 }
824                 else
825                 {
826                     switch(legend.get("position"))
827                     {
828                         case LEFT :
829                             x = legendWidth + gap;
830                         break;
831                         case TOP :
832                             y = legendHeight + gap;
833                         break;
834                         case RIGHT :
835                             legendX = graphWidth + gap;
836                         break;
837                         case BOTTOM :
838                             legendY = graphHeight + gap;
839                         break;
840                     }
841                 }
842             }
843             else
844             {
845                 graph.set(_X, 0);
846                 graph.set(_Y, 0);
847                 graph.set(WIDTH, w);
848                 graph.set(HEIGHT, h);
849             }
850         }
851         this._drawing = false;
852         if(this._callLater)
853         {
854             this._redraw();
855             return;
856         }
857         if(graph)
858         {
859             graph.set(_X, x);
860             graph.set(_Y, y);
861         }
862         if(legend)
863         {
864             legend.set(_X, legendX);
865             legend.set(_Y, legendY);
866         }
867     }
868 }, {
869     ATTRS: {
870         /**
871          * The legend for the chart.
872          *
873          * @attribute
874          * @type Legend
875          */
876         legend: LEGEND
877     }
879 Y.PieChart = PieChartLegend;
881  * ChartLegend provides a legend for a chart.
883  * @class ChartLegend
884  * @module charts
885  * @submodule charts-legend
886  * @extends Widget
887  */
888 Y.ChartLegend = Y.Base.create("chartlegend", Y.Widget, [Y.Renderer], {
889     /**
890      * Initializes the chart.
891      *
892      * @method initializer
893      * @private
894      */
895     initializer: function()
896     {
897         this._items = [];
898     },
900     /**
901      * @method renderUI
902      * @private
903      */
904     renderUI: function()
905     {
906         var bb = this.get("boundingBox"),
907             cb = this.get("contentBox"),
908             styles = this.get("styles").background,
909             background = new Y.Rect({
910                 graphic: cb,
911                 fill: styles.fill,
912                 stroke: styles.border
913             });
914         bb.setStyle("display", "block");
915         bb.setStyle("position", "absolute");
916         this.set("background", background);
917     },
919     /**
920      * @method bindUI
921      * @private
922      */
923     bindUI: function()
924     {
925         this.get("chart").after("seriesCollectionChange", Y.bind(this._updateHandler, this));
926         this.get("chart").after("stylesChange", Y.bind(this._updateHandler, this));
927         this.after("stylesChange", this._updateHandler);
928         this.after("positionChange", this._positionChangeHandler);
929         this.after("widthChange", this._handleSizeChange);
930         this.after("heightChange", this._handleSizeChange);
931     },
933     /**
934      * @method syncUI
935      * @private
936      */
937     syncUI: function()
938     {
939         var w = this.get("width"),
940             h = this.get("height");
941         if(isFinite(w) && isFinite(h) && w > 0 && h > 0)
942         {
943             this._drawLegend();
944         }
945     },
947     /**
948      * Handles changes to legend.
949      *
950      * @method _updateHandler
951      * @param {Object} e Event object
952      * @private
953      */
954     _updateHandler: function()
955     {
956         if(this.get("rendered"))
957         {
958             this._drawLegend();
959         }
960     },
962     /**
963      * Handles position changes.
964      *
965      * @method _positionChangeHandler
966      * @param {Object} e Event object
967      * @private
968      */
969     _positionChangeHandler: function()
970     {
971         var chart = this.get("chart"),
972             parentNode = this._parentNode;
973         if(parentNode && ((chart && this.get("includeInChartLayout"))))
974         {
975             this.fire("legendRendered");
976         }
977         else if(this.get("rendered"))
978         {
979             this._drawLegend();
980         }
981     },
983     /**
984      * Updates the legend when the size changes.
985      *
986      * @method _handleSizeChange
987      * @param {Object} e Event object.
988      * @private
989      */
990     _handleSizeChange: function(e)
991     {
992         var attrName = e.attrName,
993             pos = this.get(POSITION),
994             vert = pos === LEFT || pos === RIGHT,
995             hor = pos === BOTTOM || pos === TOP;
996         if((hor && attrName === WIDTH) || (vert && attrName === HEIGHT))
997         {
998             this._drawLegend();
999         }
1000     },
1002     /**
1003      * Draws the legend
1004      *
1005      * @method _drawLegend
1006      * @private
1007      */
1008     _drawLegend: function()
1009     {
1010         if(this._drawing)
1011         {
1012             this._callLater = true;
1013             return;
1014         }
1015         this._drawing = true;
1016         this._callLater = false;
1017         if(this.get("includeInChartLayout"))
1018         {
1019             this.get("chart")._itemRenderQueue.unshift(this);
1020         }
1021         var chart = this.get("chart"),
1022             node = this.get("contentBox"),
1023             seriesCollection = chart.get("seriesCollection"),
1024             series,
1025             styles = this.get("styles"),
1026             padding = styles.padding,
1027             itemStyles = styles.item,
1028             seriesStyles,
1029             hSpacing = itemStyles.hSpacing,
1030             vSpacing = itemStyles.vSpacing,
1031             direction = this.get("direction"),
1032             align = direction === "vertical" ? styles.vAlign : styles.hAlign,
1033             marker = styles.marker,
1034             labelStyles = itemStyles.label,
1035             displayName,
1036             layout = this._layout[direction],
1037             i,
1038             len,
1039             isArray,
1040             legendShape,
1041             shape,
1042             shapeClass,
1043             item,
1044             fill,
1045             border,
1046             fillColors,
1047             borderColors,
1048             borderWeight,
1049             items = [],
1050             markerWidth = marker.width,
1051             markerHeight = marker.height,
1052             totalWidth = 0 - hSpacing,
1053             totalHeight = 0 - vSpacing,
1054             maxWidth = 0,
1055             maxHeight = 0,
1056             itemWidth,
1057             itemHeight;
1058         if(marker && marker.shape)
1059         {
1060             legendShape = marker.shape;
1061         }
1062         this._destroyLegendItems();
1063         if(chart instanceof Y.PieChart)
1064         {
1065             series = seriesCollection[0];
1066             displayName = series.get("categoryAxis").getDataByKey(series.get("categoryKey"));
1067             seriesStyles = series.get("styles").marker;
1068             fillColors = seriesStyles.fill.colors;
1069             borderColors = seriesStyles.border.colors;
1070             borderWeight = seriesStyles.border.weight;
1071             i = 0;
1072             len = displayName.length;
1073             shape = legendShape || Y.Circle;
1074             isArray = Y.Lang.isArray(shape);
1075             for(; i < len; ++i)
1076             {
1077                 shape = isArray ? shape[i] : shape;
1078                 fill = {
1079                     color: fillColors[i]
1080                 };
1081                 border = {
1082                     colors: borderColors[i],
1083                     weight: borderWeight
1084                 };
1085                 displayName = chart.getSeriesItems(series, i).category.value;
1086                 item = this._getLegendItem(node, this._getShapeClass(shape), fill, border, labelStyles, markerWidth, markerHeight, displayName);
1087                 itemWidth = item.width;
1088                 itemHeight = item.height;
1089                 maxWidth = Math.max(maxWidth, itemWidth);
1090                 maxHeight = Math.max(maxHeight, itemHeight);
1091                 totalWidth += itemWidth + hSpacing;
1092                 totalHeight += itemHeight + vSpacing;
1093                 items.push(item);
1094             }
1095         }
1096         else
1097         {
1098             i = 0;
1099             len = seriesCollection.length;
1100             for(; i < len; ++i)
1101             {
1102                 series = seriesCollection[i];
1103                 seriesStyles = this._getStylesBySeriesType(series, shape);
1104                 if(!legendShape)
1105                 {
1106                     shape = seriesStyles.shape;
1107                     if(!shape)
1108                     {
1109                         shape = Y.Circle;
1110                     }
1111                 }
1112                 shapeClass = Y.Lang.isArray(shape) ? shape[i] : shape;
1113                 item = this._getLegendItem(
1114                     node,
1115                     this._getShapeClass(shape),
1116                     seriesStyles.fill,
1117                     seriesStyles.border,
1118                     labelStyles,
1119                     markerWidth,
1120                     markerHeight,
1121                     series.get("valueDisplayName")
1122                 );
1123                 itemWidth = item.width;
1124                 itemHeight = item.height;
1125                 maxWidth = Math.max(maxWidth, itemWidth);
1126                 maxHeight = Math.max(maxHeight, itemHeight);
1127                 totalWidth += itemWidth + hSpacing;
1128                 totalHeight += itemHeight + vSpacing;
1129                 items.push(item);
1130             }
1131         }
1132         this._drawing = false;
1133         if(this._callLater)
1134         {
1135             this._drawLegend();
1136         }
1137         else
1138         {
1139             layout._positionLegendItems.apply(
1140                 this,
1141                 [items, maxWidth, maxHeight, totalWidth, totalHeight, padding, hSpacing, vSpacing, align]
1142             );
1143             this._updateBackground(styles);
1144             this.fire("legendRendered");
1145         }
1146     },
1148     /**
1149      * Updates the background for the legend.
1150      *
1151      * @method _updateBackground
1152      * @param {Object} styles Reference to the legend's styles attribute
1153      * @private
1154      */
1155     _updateBackground: function(styles)
1156     {
1157         var backgroundStyles = styles.background,
1158             contentRect = this._contentRect,
1159             padding = styles.padding,
1160             x = contentRect.left - padding.left,
1161             y = contentRect.top - padding.top,
1162             w = contentRect.right - x + padding.right,
1163             h = contentRect.bottom - y + padding.bottom;
1164         this.get("background").set({
1165             fill: backgroundStyles.fill,
1166             stroke: backgroundStyles.border,
1167             width: w,
1168             height: h,
1169             x: x,
1170             y: y
1171         });
1172     },
1174     /**
1175      * Retrieves the marker styles based on the type of series. For series that contain a marker, the marker styles are returned.
1176      *
1177      * @method _getStylesBySeriesType
1178      * @param {CartesianSeries | PieSeries} The series in which the style properties will be received.
1179      * @return Object An object containing fill, border and shape information.
1180      * @private
1181      */
1182     _getStylesBySeriesType: function(series)
1183     {
1184         var styles = series.get("styles"),
1185             color;
1186         if(series instanceof Y.LineSeries || series instanceof Y.StackedLineSeries)
1187         {
1188             styles = series.get("styles").line;
1189             color = styles.color || series._getDefaultColor(series.get("graphOrder"), "line");
1190             return {
1191                 border: {
1192                     weight: 1,
1193                     color: color
1194                 },
1195                 fill: {
1196                     color: color
1197                 }
1198             };
1199         }
1200         else if(series instanceof Y.AreaSeries || series instanceof Y.StackedAreaSeries)
1201         {
1202             styles = series.get("styles").area;
1203             color = styles.color || series._getDefaultColor(series.get("graphOrder"), "slice");
1204             return {
1205                 border: {
1206                     weight: 1,
1207                     color: color
1208                 },
1209                 fill: {
1210                     color: color
1211                 }
1212             };
1213         }
1214         else
1215         {
1216             styles = series.get("styles").marker;
1217             return {
1218                 fill: styles.fill,
1220                 border: {
1221                     weight: styles.border.weight,
1223                     color: styles.border.color,
1225                     shape: styles.shape
1226                 },
1227                 shape: styles.shape
1228             };
1229         }
1230     },
1232     /**
1233      * Returns a legend item consisting of the following properties:
1234      *  <dl>
1235      *    <dt>node</dt><dd>The `Node` containing the legend item elements.</dd>
1236      *      <dt>shape</dt><dd>The `Shape` element for the legend item.</dd>
1237      *      <dt>textNode</dt><dd>The `Node` containing the text></dd>
1238      *      <dt>text</dt><dd></dd>
1239      *  </dl>
1240      *
1241      * @method _getLegendItem
1242      * @param {Node} shapeProps Reference to the `node` attribute.
1243      * @param {String | Class} shapeClass The type of shape
1244      * @param {Object} fill Properties for the shape's fill
1245      * @param {Object} border Properties for the shape's border
1246      * @param {String} text String to be rendered as the legend's text
1247      * @param {Number} width Total width of the legend item
1248      * @param {Number} height Total height of the legend item
1249      * @param {HTML | String} text Text for the legendItem
1250      * @return Object
1251      * @private
1252      */
1253     _getLegendItem: function(node, shapeClass, fill, border, labelStyles, w, h, text)
1254     {
1255         var containerNode = Y.one(DOCUMENT.createElement("div")),
1256             textField = Y.one(DOCUMENT.createElement("span")),
1257             shape,
1258             dimension,
1259             padding,
1260             left,
1261             item,
1262             ShapeClass = shapeClass;
1263         containerNode.setStyle(POSITION, "absolute");
1264         textField.setStyle(POSITION, "absolute");
1265         textField.setStyles(labelStyles);
1266         textField.appendChild(DOCUMENT.createTextNode(text));
1267         containerNode.appendChild(textField);
1268         node.appendChild(containerNode);
1269         dimension = textField.get("offsetHeight");
1270         padding = dimension - h;
1271         left = w + padding + 2;
1272         textField.setStyle("left", left + PX);
1273         containerNode.setStyle("height", dimension + PX);
1274         containerNode.setStyle("width", (left + textField.get("offsetWidth")) + PX);
1275         shape = new ShapeClass({
1276             fill: fill,
1277             stroke: border,
1278             width: w,
1279             height: h,
1280             x: padding * 0.5,
1281             y: padding * 0.5,
1282             w: w,
1283             h: h,
1284             graphic: containerNode
1285         });
1286         textField.setStyle("left", dimension + PX);
1287         item = {
1288             node: containerNode,
1289             width: containerNode.get("offsetWidth"),
1290             height: containerNode.get("offsetHeight"),
1291             shape: shape,
1292             textNode: textField,
1293             text: text
1294         };
1295         this._items.push(item);
1296         return item;
1297     },
1299     /**
1300      * Evaluates and returns correct class for drawing a shape.
1301      *
1302      * @method _getShapeClass
1303      * @return Shape
1304      * @private
1305      */
1306     _getShapeClass: function()
1307     {
1308         var graphic = this.get("background").get("graphic");
1309         return graphic._getShapeClass.apply(graphic, arguments);
1310     },
1312     /**
1313      * Returns the default hash for the `styles` attribute.
1314      *
1315      * @method _getDefaultStyles
1316      * @return Object
1317      * @protected
1318      */
1319     _getDefaultStyles: function()
1320     {
1321         var styles = {
1322             padding: {
1323                 top: 8,
1324                 right: 8,
1325                 bottom: 8,
1326                 left: 9
1327             },
1328             gap: 10,
1329             hAlign: "center",
1330             vAlign: "top",
1331             marker: this._getPlotDefaults(),
1332             item: {
1333                 hSpacing: 10,
1334                 vSpacing: 5,
1335                 label: {
1336                     color:"#808080",
1337                     fontSize:"85%",
1338                     whiteSpace: "nowrap"
1339                 }
1340             },
1341             background: {
1342                 shape: "rect",
1343                 fill:{
1344                     color:"#faf9f2"
1345                 },
1346                 border: {
1347                     color:"#dad8c9",
1348                     weight: 1
1349                 }
1350             }
1351         };
1352         return styles;
1353     },
1355     /**
1356      * Gets the default values for series that use the utility. This method is used by
1357      * the class' `styles` attribute's getter to get build default values.
1358      *
1359      * @method _getPlotDefaults
1360      * @return Object
1361      * @protected
1362      */
1363     _getPlotDefaults: function()
1364     {
1365         var defs = {
1366             width: 10,
1367             height: 10
1368         };
1369         return defs;
1370     },
1372     /**
1373      * Destroys legend items.
1374      *
1375      * @method _destroyLegendItems
1376      * @private
1377      */
1378     _destroyLegendItems: function()
1379     {
1380         var item;
1381         if(this._items)
1382         {
1383             while(this._items.length > 0)
1384             {
1385                 item = this._items.shift();
1386                 item.shape.get("graphic").destroy();
1387                 item.node.empty();
1388                 item.node.destroy(true);
1389                 item.node = null;
1390                 item = null;
1391             }
1392         }
1393         this._items = [];
1394     },
1396     /**
1397      * Maps layout classes.
1398      *
1399      * @property _layout
1400      * @private
1401      */
1402     _layout: {
1403         vertical: VerticalLegendLayout,
1404         horizontal: HorizontalLegendLayout
1405     },
1407     /**
1408      * Destructor implementation ChartLegend class. Removes all items and the Graphic instance from the widget.
1409      *
1410      * @method destructor
1411      * @protected
1412      */
1413     destructor: function()
1414     {
1415         var background = this.get("background"),
1416             backgroundGraphic;
1417         this._destroyLegendItems();
1418         if(background)
1419         {
1420             backgroundGraphic = background.get("graphic");
1421             if(backgroundGraphic)
1422             {
1423                 backgroundGraphic.destroy();
1424             }
1425             else
1426             {
1427                 background.destroy();
1428             }
1429         }
1431     }
1432 }, {
1433     ATTRS: {
1434         /**
1435          * Indicates whether the chart's contentBox is the parentNode for the legend.
1436          *
1437          * @attribute includeInChartLayout
1438          * @type Boolean
1439          * @private
1440          */
1441         includeInChartLayout: {
1442             value: false
1443         },
1445         /**
1446          * Reference to the `Chart` instance.
1447          *
1448          * @attribute chart
1449          * @type Chart
1450          */
1451         chart: {
1452             setter: function(val)
1453             {
1454                 this.after("legendRendered", Y.bind(val._itemRendered, val));
1455                 return val;
1456             }
1457         },
1459         /**
1460          * Indicates the direction in relation of the legend's layout. The `direction` of the legend is determined by its
1461          * `position` value.
1462          *
1463          * @attribute direction
1464          * @type String
1465          */
1466         direction: {
1467             value: "vertical"
1468         },
1470         /**
1471          * Indicates the position and direction of the legend. Possible values are `left`, `top`, `right` and `bottom`.
1472          * Values of `left` and `right` values have a `direction` of `vertical`. Values of `top` and `bottom` values have
1473          * a `direction` of `horizontal`.
1474          *
1475          * @attribute position
1476          * @type String
1477          */
1478         position: {
1479             lazyAdd: false,
1481             value: "right",
1483             setter: function(val)
1484             {
1485                 if(val === TOP || val === BOTTOM)
1486                 {
1487                     this.set("direction", HORIZONTAL);
1488                 }
1489                 else if(val === LEFT || val === RIGHT)
1490                 {
1491                     this.set("direction", VERTICAL);
1492                 }
1493                 return val;
1494             }
1495         },
1497         /**
1498          * The width of the legend. Depending on the implementation of the ChartLegend, this value is `readOnly`.
1499          * By default, the legend is included in the layout of the `Chart` that it references. Under this circumstance,
1500          * `width` is always `readOnly`. When the legend is rendered in its own dom element, the `readOnly` status is
1501          * determined by the direction of the legend. If the `position` is `left` or `right` or the `direction` is
1502          * `vertical`, width is `readOnly`. If the position is `top` or `bottom` or the `direction` is `horizontal`,
1503          * width can be explicitly set. If width is not explicitly set, the width will be determined by the width of the
1504          * legend's parent element.
1505          *
1506          * @attribute width
1507          * @type Number
1508          */
1509         width: {
1510             getter: function()
1511             {
1512                 var chart = this.get("chart"),
1513                     parentNode = this._parentNode;
1514                 if(parentNode)
1515                 {
1516                     if((chart && this.get("includeInChartLayout")) || this._width)
1517                     {
1518                         if(!this._width)
1519                         {
1520                             this._width = 0;
1521                         }
1522                         return this._width;
1523                     }
1524                     else
1525                     {
1526                         return parentNode.get("offsetWidth");
1527                     }
1528                 }
1529                 return "";
1530             },
1532             setter: function(val)
1533             {
1534                 this._width = val;
1535                 return val;
1536             }
1537         },
1539         /**
1540          * The height of the legend. Depending on the implementation of the ChartLegend, this value is `readOnly`.
1541          * By default, the legend is included in the layout of the `Chart` that it references. Under this circumstance,
1542          * `height` is always `readOnly`. When the legend is rendered in its own dom element, the `readOnly` status is
1543          * determined by the direction of the legend. If the `position` is `top` or `bottom` or the `direction` is
1544          * `horizontal`, height is `readOnly`. If the position is `left` or `right` or the `direction` is `vertical`,
1545          * height can be explicitly set. If height is not explicitly set, the height will be determined by the width of the
1546          * legend's parent element.
1547          *
1548          * @attribute height
1549          * @type Number
1550          */
1551         height: {
1552             valueFn: "_heightGetter",
1554             getter: function()
1555             {
1556                 var chart = this.get("chart"),
1557                     parentNode = this._parentNode;
1558                 if(parentNode)
1559                 {
1560                     if((chart && this.get("includeInChartLayout")) || this._height)
1561                     {
1562                         if(!this._height)
1563                         {
1564                             this._height = 0;
1565                         }
1566                         return this._height;
1567                     }
1568                     else
1569                     {
1570                         return parentNode.get("offsetHeight");
1571                     }
1572                 }
1573                 return "";
1574             },
1576             setter: function(val)
1577             {
1578                 this._height = val;
1579                 return val;
1580             }
1581         },
1583         /**
1584          * Indicates the x position of legend.
1585          *
1586          * @attribute x
1587          * @type Number
1588          * @readOnly
1589          */
1590         x: {
1591             lazyAdd: false,
1593             value: 0,
1595             setter: function(val)
1596             {
1597                 var node = this.get("boundingBox");
1598                 if(node)
1599                 {
1600                     node.setStyle(LEFT, val + PX);
1601                 }
1602                 return val;
1603             }
1604         },
1606         /**
1607          * Indicates the y position of legend.
1608          *
1609          * @attribute y
1610          * @type Number
1611          * @readOnly
1612          */
1613         y: {
1614             lazyAdd: false,
1616             value: 0,
1618             setter: function(val)
1619             {
1620                 var node = this.get("boundingBox");
1621                 if(node)
1622                 {
1623                     node.setStyle(TOP, val + PX);
1624                 }
1625                 return val;
1626             }
1627         },
1629         /**
1630          * Array of items contained in the legend. Each item is an object containing the following properties:
1631          *
1632          * <dl>
1633          *      <dt>node</dt><dd>Node containing text for the legend item.</dd>
1634          *      <dt>marker</dt><dd>Shape for the legend item.</dd>
1635          * </dl>
1636          *
1637          * @attribute items
1638          * @type Array
1639          * @readOnly
1640          */
1641         items: {
1642             getter: function()
1643             {
1644                 return this._items;
1645             }
1646         },
1648         /**
1649          * Background for the legend.
1650          *
1651          * @attribute background
1652          * @type Rect
1653          */
1654         background: {}
1656         /**
1657          * Properties used to display and style the ChartLegend.  This attribute is inherited from `Renderer`.
1658          * Below are the default values:
1659          *
1660          *  <dl>
1661          *      <dt>gap</dt><dd>Distance, in pixels, between the `ChartLegend` instance and the chart's content. When `ChartLegend`
1662          *      is rendered within a `Chart` instance this value is applied.</dd>
1663          *      <dt>hAlign</dt><dd>Defines the horizontal alignment of the `items` in a `ChartLegend` rendered in a horizontal direction.
1664          *      This value is applied when the instance's `position` is set to top or bottom. This attribute can be set to left, center
1665          *      or right. The default value is center.</dd>
1666          *      <dt>vAlign</dt><dd>Defines the vertical alignment of the `items` in a `ChartLegend` rendered in vertical direction. This
1667          *      value is applied when the instance's `position` is set to left or right. The attribute can be set to top, middle or
1668          *      bottom. The default value is middle.</dd>
1669          *      <dt>item</dt><dd>Set of style properties applied to the `items` of the `ChartLegend`.
1670          *          <dl>
1671          *              <dt>hSpacing</dt><dd>Horizontal distance, in pixels, between legend `items`.</dd>
1672          *              <dt>vSpacing</dt><dd>Vertical distance, in pixels, between legend `items`.</dd>
1673          *              <dt>label</dt><dd>Properties for the text of an `item`.
1674          *                  <dl>
1675          *                      <dt>color</dt><dd>Color of the text. The default values is "#808080".</dd>
1676          *                      <dt>fontSize</dt><dd>Font size for the text. The default value is "85%".</dd>
1677          *                  </dl>
1678          *              </dd>
1679          *              <dt>marker</dt><dd>Properties for the `item` markers.
1680          *                  <dl>
1681          *                      <dt>width</dt><dd>Specifies the width of the markers.</dd>
1682          *                      <dt>height</dt><dd>Specifies the height of the markers.</dd>
1683          *                  </dl>
1684          *              </dd>
1685          *          </dl>
1686          *      </dd>
1687          *      <dt>background</dt><dd>Properties for the `ChartLegend` background.
1688          *          <dl>
1689          *              <dt>fill</dt><dd>Properties for the background fill.
1690          *                  <dl>
1691          *                      <dt>color</dt><dd>Color for the fill. The default value is "#faf9f2".</dd>
1692          *                  </dl>
1693          *              </dd>
1694          *              <dt>border</dt><dd>Properties for the background border.
1695          *                  <dl>
1696          *                      <dt>color</dt><dd>Color for the border. The default value is "#dad8c9".</dd>
1697          *                      <dt>weight</dt><dd>Weight of the border. The default values is 1.</dd>
1698          *                  </dl>
1699          *              </dd>
1700          *          </dl>
1701          *      </dd>
1702          * </dl>
1703          *
1704          * @attribute styles
1705          * @type Object
1706          */
1707     }
1711 }, '3.13.0', {"requires": ["charts-base"]});