NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / series-plot-util / series-plot-util-debug.js
blob95a0dbae56e4d58d0cbb04059fcbf891b047e744
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('series-plot-util', function (Y, NAME) {
10 /**
11  * Provides functionality for drawing plots in a series.
12  *
13  * @module charts
14  * @submodule series-plot-util
15  */
16 var Y_Lang = Y.Lang,
17     _getClassName = Y.ClassNameManager.getClassName,
18     SERIES_MARKER = _getClassName("seriesmarker");
20 /**
21  * Utility class used for drawing markers.
22  *
23  * @class Plots
24  * @constructor
25  * @submodule series-plot-util
26  */
27 function Plots(cfg)
29     var attrs = {
30         markers: {
31             getter: function()
32             {
33                 return this._markers;
34             }
35         }
36     };
37     this.addAttrs(attrs, cfg);
40 Plots.prototype = {
41     /**
42      * Storage for default marker styles.
43      *
44      * @property _plotDefaults
45      * @type Object
46      * @private
47      */
48     _plotDefaults: null,
50     /**
51      * Draws the markers
52      *
53      * @method drawPlots
54      * @protected
55      */
56     drawPlots: function()
57     {
58         if(!this.get("xcoords") || this.get("xcoords").length < 1)
59                 {
60                         return;
61                 }
62         var isNumber = Y_Lang.isNumber,
63             style = Y.clone(this.get("styles").marker),
64             w = style.width,
65             h = style.height,
66             xcoords = this.get("xcoords"),
67             ycoords = this.get("ycoords"),
68             i = 0,
69             len = xcoords.length,
70             top = ycoords[0],
71             left,
72             marker,
73             offsetWidth = w/2,
74             offsetHeight = h/2,
75             xvalues,
76             yvalues,
77             fillColors = null,
78             borderColors = null,
79             graphOrder = this.get("graphOrder"),
80             groupMarkers = this.get("groupMarkers");
81         if(groupMarkers)
82         {
83             xvalues = [];
84             yvalues = [];
85             for(; i < len; ++i)
86             {
87                 xvalues.push(parseFloat(xcoords[i] - offsetWidth));
88                 yvalues.push(parseFloat(ycoords[i] - offsetHeight));
89             }
90             this._createGroupMarker({
91                 xvalues: xvalues,
92                 yvalues: yvalues,
93                 fill: style.fill,
94                 border: style.border,
95                 dimensions: {
96                     width: w,
97                     height: h
98                 },
99                 graphOrder: graphOrder,
100                 shape: style.shape
101             });
102             return;
103         }
104         if(Y_Lang.isArray(style.fill.color))
105         {
106             fillColors = style.fill.color.concat();
107         }
108         if(Y_Lang.isArray(style.border.color))
109         {
110             borderColors = style.border.color.concat();
111         }
112         this._createMarkerCache();
113         for(; i < len; ++i)
114         {
115             top = parseFloat(ycoords[i] - offsetHeight);
116             left = parseFloat(xcoords[i] - offsetWidth);
117             if(!isNumber(left) || !isNumber(top))
118             {
119                 this._markers.push(null);
120                 continue;
121             }
122             if(fillColors)
123             {
124                 style.fill.color = fillColors[i % fillColors.length];
125             }
126             if(borderColors)
127             {
128                 style.border.color = borderColors[i % borderColors.length];
129             }
131             style.x = left;
132             style.y = top;
133             marker = this.getMarker(style, graphOrder, i);
134         }
135         this._clearMarkerCache();
136     },
138     /**
139      * Pre-defined group shapes.
140      *
141      * @property _groupShapes
142      * @private
143      */
144     _groupShapes: {
145         circle: Y.CircleGroup,
146         rect: Y.RectGroup,
147         ellipse: Y.EllipseGroup,
148         diamond: Y.DiamondGroup
149     },
151     /**
152      * Returns the correct group shape class.
153      *
154      * @method _getGroupShape
155      * @param {Shape | String} shape Indicates which shape class.
156      * @return Function
157      * @protected
158      */
159     _getGroupShape: function(shape)
160     {
161         if(Y_Lang.isString(shape))
162         {
163             shape = this._groupShapes[shape];
164         }
165         return shape;
166     },
168     /**
169      * Gets the default values for series that use the utility. This method is used by
170      * the class' `styles` attribute's getter to get build default values.
171      *
172      * @method _getPlotDefaults
173      * @return Object
174      * @protected
175      */
176     _getPlotDefaults: function()
177     {
178         var defs = {
179             fill:{
180                 type: "solid",
181                 alpha: 1,
182                 colors:null,
183                 alphas: null,
184                 ratios: null
185             },
186             border:{
187                 weight: 1,
188                 alpha: 1
189             },
190             width: 10,
191             height: 10,
192             shape: "circle"
193         };
194         defs.fill.color = this._getDefaultColor(this.get("graphOrder"), "fill");
195         defs.border.color = this._getDefaultColor(this.get("graphOrder"), "border");
196         return defs;
197     },
199     /**
200      * Collection of markers to be used in the series.
201      *
202      * @property _markers
203      * @type Array
204      * @private
205      */
206     _markers: null,
208     /**
209      * Collection of markers to be re-used on a series redraw.
210      *
211      * @property _markerCache
212      * @type Array
213      * @private
214      */
215     _markerCache: null,
217     /**
218      * Gets and styles a marker. If there is a marker in cache, it will use it. Otherwise
219      * it will create one.
220      *
221      * @method getMarker
222      * @param {Object} styles Hash of style properties.
223      * @param {Number} order Order of the series.
224      * @param {Number} index Index within the series associated with the marker.
225      * @return Shape
226      * @protected
227      */
228     getMarker: function(styles, order, index)
229     {
230         var marker,
231             border = styles.border;
232         styles.id = this._getChart().get("id") + "_" + order + "_" + index;
233         //fix name differences between graphic layer
234         border.opacity = border.alpha;
235         styles.stroke = border;
236         styles.fill.opacity = styles.fill.alpha;
237         if(this._markerCache.length > 0)
238         {
239             while(!marker)
240             {
241                 if(this._markerCache.length < 1)
242                 {
243                     marker = this._createMarker(styles);
244                     break;
245                 }
246                 marker = this._markerCache.shift();
248             }
249             marker.set(styles);
250         }
251         else
252         {
253             marker = this._createMarker(styles);
254         }
255         this._markers.push(marker);
256         return marker;
257     },
259     /**
260      * Creates a shape to be used as a marker.
261      *
262      * @method _createMarker
263      * @param {Object} styles Hash of style properties.
264      * @return Shape
265      * @private
266      */
267     _createMarker: function(styles)
268     {
269         var graphic = this.get("graphic"),
270             marker,
271             cfg = Y.clone(styles);
272         cfg.type = cfg.shape;
273         marker = graphic.addShape(cfg);
274         marker.addClass(SERIES_MARKER);
275         return marker;
276     },
278     /**
279      * Creates a cache of markers for reuse.
280      *
281      * @method _createMarkerCache
282      * @private
283      */
284     _createMarkerCache: function()
285     {
286         if(this._groupMarker)
287         {
288             this._groupMarker.destroy();
289             this._groupMarker = null;
290         }
291         if(this._markers && this._markers.length > 0)
292         {
293             this._markerCache = this._markers.concat();
294         }
295         else
296         {
297             this._markerCache = [];
298         }
299         this._markers = [];
300     },
302     /**
303      * Draws a series of markers in a single shape instance.
304      *
305      * @method _createGroupMarkers
306      * @param {Object} styles Set of configuration properties used to create the markers.
307      * @protected
308      */
309     _createGroupMarker: function(styles)
310     {
311         var marker,
312             markers = this.get("markers"),
313             border = styles.border,
314             graphic,
315             cfg,
316             shape;
317         if(markers && markers.length > 0)
318         {
319             while(markers.length > 0)
320             {
321                 marker = markers.shift();
322                 marker.destroy();
323             }
324             this.set("markers", []);
325         }
326         //fix name differences between graphic layer
327         border.opacity = border.alpha;
328         cfg = {
329             id: this._getChart().get("id") + "_" + styles.graphOrder,
330             stroke: border,
331             fill: styles.fill,
332             dimensions: styles.dimensions,
333             xvalues: styles.xvalues,
334             yvalues: styles.yvalues
335         };
336         cfg.fill.opacity = styles.fill.alpha;
337         shape = this._getGroupShape(styles.shape);
338         if(shape)
339         {
340             cfg.type = shape;
341         }
342         if(styles.hasOwnProperty("radius") && !isNaN(styles.radius))
343         {
344             cfg.dimensions.radius = styles.radius;
345         }
346         if(this._groupMarker)
347         {
348             this._groupMarker.destroy();
349         }
350         graphic = this.get("graphic");
351         this._groupMarker = graphic.addShape(cfg);
352         graphic._redraw();
353     },
355     /**
356      * Toggles visibility
357      *
358      * @method _toggleVisible
359      * @param {Boolean} visible indicates visibilitye
360      * @private
361      */
362     _toggleVisible: function(visible)
363     {
364         var marker,
365             markers = this.get("markers"),
366             i = 0,
367             len;
368         if(markers)
369         {
370             len = markers.length;
371             for(; i < len; ++i)
372             {
373                 marker = markers[i];
374                 if(marker)
375                 {
376                     marker.set("visible", visible);
377                 }
378             }
379         }
380     },
382     /**
383      * Removes unused markers from the marker cache
384      *
385      * @method _clearMarkerCache
386      * @private
387      */
388     _clearMarkerCache: function()
389     {
390         var marker;
391         while(this._markerCache.length > 0)
392         {
393             marker = this._markerCache.shift();
394             if(marker)
395             {
396                 marker.destroy();
397             }
398         }
399     },
401     /**
402      * Resizes and positions markers based on a mouse interaction.
403      *
404      * @method updateMarkerState
405      * @param {String} type state of the marker
406      * @param {Number} i index of the marker
407      * @protected
408      */
409     updateMarkerState: function(type, i)
410     {
411         if(this._markers && this._markers[i])
412         {
413             var w,
414                 h,
415                 styles = Y.clone(this.get("styles").marker),
416                 state = this._getState(type),
417                 xcoords = this.get("xcoords"),
418                 ycoords = this.get("ycoords"),
419                 marker = this._markers[i],
420                 markerStyles = state === "off" || !styles[state] ? styles : styles[state];
421                 markerStyles.fill.color = this._getItemColor(markerStyles.fill.color, i);
422                 markerStyles.border.color = this._getItemColor(markerStyles.border.color, i);
423                 markerStyles.stroke = markerStyles.border;
424                 marker.set(markerStyles);
425                 w = markerStyles.width;
426                 h = markerStyles.height;
427                 marker.set("x", (xcoords[i] - w/2));
428                 marker.set("y",  (ycoords[i] - h/2));
429                 marker.set("visible", this.get("visible"));
430         }
431     },
433     /**
434      * Parses a color from an array.
435      *
436      * @method _getItemColor
437      * @param {Array} val collection of colors
438      * @param {Number} i index of the item
439      * @return String
440      * @protected
441      */
442     _getItemColor: function(val, i)
443     {
444         if(Y_Lang.isArray(val))
445         {
446             return val[i % val.length];
447         }
448         return val;
449     },
451     /**
452      * Method used by `styles` setter. Overrides base implementation.
453      *
454      * @method _setStyles
455      * @param {Object} newStyles Hash of properties to update.
456      * @return Object
457      * @protected
458      */
459     _setStyles: function(val)
460     {
461         val = this._parseMarkerStyles(val);
462         return Y.Renderer.prototype._setStyles.apply(this, [val]);
463     },
465     /**
466      * Combines new styles with existing styles.
467      *
468      * @method _parseMarkerStyles
469      * @param {Object} Object containing style properties for the marker.
470      * @return Object
471      * @private
472      */
473     _parseMarkerStyles: function(val)
474     {
475         if(val.marker)
476         {
477             var defs = this._getPlotDefaults();
478             val.marker = this._mergeStyles(val.marker, defs);
479             if(val.marker.over)
480             {
481                 val.marker.over = this._mergeStyles(val.marker.over, val.marker);
482             }
483             if(val.marker.down)
484             {
485                 val.marker.down = this._mergeStyles(val.marker.down, val.marker);
486             }
487         }
488         return val;
489     },
491     /**
492      * Returns marker state based on event type
493      *
494      * @method _getState
495      * @param {String} type event type
496      * @return String
497      * @protected
498      */
499     _getState: function(type)
500     {
501         var state;
502         switch(type)
503         {
504             case "mouseout" :
505                 state = "off";
506             break;
507             case "mouseover" :
508                 state = "over";
509             break;
510             case "mouseup" :
511                 state = "over";
512             break;
513             case "mousedown" :
514                 state = "down";
515             break;
516         }
517         return state;
518     },
520     /**
521      * @property _statSyles
522      * @type Object
523      * @private
524      */
525     _stateSyles: null,
527     /**
528      * @protected
529      *
530      * Draws the series.
531      *
532      * @method drawSeries
533      */
534     drawSeries: function()
535     {
536         this.drawPlots();
537     },
539     /**
540      * @protected
541      *
542      * Gets the default value for the `styles` attribute. Overrides
543      * base implementation.
544      *
545      * @method _getDefaultStyles
546      * @return Object
547      */
548     _getDefaultStyles: function()
549     {
550         var styles = this._mergeStyles({marker:this._getPlotDefaults()}, this.constructor.superclass._getDefaultStyles());
551         return styles;
552     }
555 Y.augment(Plots, Y.Attribute);
556 Y.Plots = Plots;
559 }, '3.13.0');