|
1 /* |
|
2 YUI 3.10.3 (build 2fb5187) |
|
3 Copyright 2013 Yahoo! Inc. All rights reserved. |
|
4 Licensed under the BSD License. |
|
5 http://yuilibrary.com/license/ |
|
6 */ |
|
7 |
|
8 YUI.add('charts-legend', function (Y, NAME) { |
|
9 |
|
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 } |
|
56 }, |
|
57 |
|
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 }, |
|
141 |
|
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 }, |
|
185 |
|
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 } |
|
214 }, |
|
215 |
|
216 /** |
|
217 * Contains methods for displaying items vertically in a legend. |
|
218 * |
|
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 }, |
|
302 |
|
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 }, |
|
346 |
|
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 } |
|
375 }, |
|
376 |
|
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 = {}; |
|
425 |
|
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 } |
|
467 |
|
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); |
|
480 |
|
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 } |
|
495 |
|
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 } |
|
510 |
|
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 } |
|
525 |
|
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 } |
|
660 |
|
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 }, |
|
669 |
|
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 }, |
|
723 |
|
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 } |
|
743 }); |
|
744 |
|
745 Y.CartesianChart = CartesianChartLegend; |
|
746 |
|
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; |
|
790 |
|
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 } |
|
878 }); |
|
879 Y.PieChart = PieChartLegend; |
|
880 /** |
|
881 * ChartLegend provides a legend for a chart. |
|
882 * |
|
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 }, |
|
899 |
|
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 }, |
|
918 |
|
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 }, |
|
932 |
|
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 }, |
|
946 |
|
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 }, |
|
961 |
|
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 }, |
|
982 |
|
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 }, |
|
1001 |
|
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 }, |
|
1147 |
|
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 }, |
|
1173 |
|
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, |
|
1219 |
|
1220 border: { |
|
1221 weight: styles.border.weight, |
|
1222 |
|
1223 color: styles.border.color, |
|
1224 |
|
1225 shape: styles.shape |
|
1226 }, |
|
1227 shape: styles.shape |
|
1228 }; |
|
1229 } |
|
1230 }, |
|
1231 |
|
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 }, |
|
1298 |
|
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 }, |
|
1311 |
|
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 }, |
|
1354 |
|
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 }, |
|
1371 |
|
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 }, |
|
1395 |
|
1396 /** |
|
1397 * Maps layout classes. |
|
1398 * |
|
1399 * @property _layout |
|
1400 * @private |
|
1401 */ |
|
1402 _layout: { |
|
1403 vertical: VerticalLegendLayout, |
|
1404 horizontal: HorizontalLegendLayout |
|
1405 }, |
|
1406 |
|
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 } |
|
1430 |
|
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 }, |
|
1444 |
|
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 }, |
|
1458 |
|
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 }, |
|
1469 |
|
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, |
|
1480 |
|
1481 value: "right", |
|
1482 |
|
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 }, |
|
1496 |
|
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 }, |
|
1531 |
|
1532 setter: function(val) |
|
1533 { |
|
1534 this._width = val; |
|
1535 return val; |
|
1536 } |
|
1537 }, |
|
1538 |
|
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", |
|
1553 |
|
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 }, |
|
1575 |
|
1576 setter: function(val) |
|
1577 { |
|
1578 this._height = val; |
|
1579 return val; |
|
1580 } |
|
1581 }, |
|
1582 |
|
1583 /** |
|
1584 * Indicates the x position of legend. |
|
1585 * |
|
1586 * @attribute x |
|
1587 * @type Number |
|
1588 * @readOnly |
|
1589 */ |
|
1590 x: { |
|
1591 lazyAdd: false, |
|
1592 |
|
1593 value: 0, |
|
1594 |
|
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 }, |
|
1605 |
|
1606 /** |
|
1607 * Indicates the y position of legend. |
|
1608 * |
|
1609 * @attribute y |
|
1610 * @type Number |
|
1611 * @readOnly |
|
1612 */ |
|
1613 y: { |
|
1614 lazyAdd: false, |
|
1615 |
|
1616 value: 0, |
|
1617 |
|
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 }, |
|
1628 |
|
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 }, |
|
1647 |
|
1648 /** |
|
1649 * Background for the legend. |
|
1650 * |
|
1651 * @attribute background |
|
1652 * @type Rect |
|
1653 */ |
|
1654 background: {} |
|
1655 |
|
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 } |
|
1708 }); |
|
1709 |
|
1710 |
|
1711 }, '3.10.3', {"requires": ["charts-base"]}); |