Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('axis-base', function (Y, NAME) {
2
 
3
/**
4
 * The Charts widget provides an api for displaying data
5
 * graphically.
6
 *
7
 * @module charts
8
 * @main charts
9
 */
10
 
11
/**
12
 * Provides functionality for the handling of axis data in a chart.
13
 *
14
 * @module charts
15
 * @submodule axis-base
16
 */
17
var Y_Lang = Y.Lang;
18
 
19
/**
20
 * The Renderer class is a base class for chart components that use the `styles`
21
 * attribute.
22
 *
23
 * @module charts
24
 * @class Renderer
25
 * @constructor
26
 */
27
function Renderer(){}
28
 
29
Renderer.ATTRS = {
30
        /**
31
         * Style properties for class
32
         *
33
         * @attribute styles
34
         * @type Object
35
         */
36
        styles:
37
        {
38
            getter: function()
39
            {
40
                this._styles = this._styles || this._getDefaultStyles();
41
                return this._styles;
42
            },
43
 
44
            setter: function(val)
45
            {
46
                this._styles = this._setStyles(val);
47
            }
48
        },
49
 
50
        /**
51
         * The graphic in which drawings will be rendered.
52
         *
53
         * @attribute graphic
54
         * @type Graphic
55
         */
56
        graphic: {}
57
};
58
Renderer.NAME = "renderer";
59
 
60
Renderer.prototype = {
61
    /**
62
     * Storage for `styles` attribute.
63
     *
64
     * @property _styles
65
     * @type Object
66
     * @private
67
     */
68
	_styles: null,
69
 
70
    /**
71
     * Method used by `styles` setter.
72
     *
73
     * @method _setStyles
74
     * @param {Object} newStyles Hash of properties to update.
75
     * @return Object
76
     * @protected
77
     */
78
	_setStyles: function(newstyles)
79
	{
80
		var styles = this.get("styles");
81
        return this._mergeStyles(newstyles, styles);
82
	},
83
 
84
    /**
85
     * Merges to object literals so that only specified properties are
86
     * overwritten.
87
     *
88
     * @method _mergeStyles
89
     * @param {Object} a Hash of new styles
90
     * @param {Object} b Hash of original styles
91
     * @return Object
92
     * @protected
93
     */
94
    _mergeStyles: function(a, b)
95
    {
96
        if(!b)
97
        {
98
            b = {};
99
        }
100
        var newstyles = Y.merge(b, {});
101
        Y.Object.each(a, function(value, key)
102
        {
103
            if(b.hasOwnProperty(key) && Y_Lang.isObject(value) && !Y_Lang.isFunction(value) && !Y_Lang.isArray(value))
104
            {
105
                newstyles[key] = this._mergeStyles(value, b[key]);
106
            }
107
            else
108
            {
109
                newstyles[key] = value;
110
            }
111
        }, this);
112
        return newstyles;
113
    },
114
 
115
    /**
116
     * Copies an object literal.
117
     *
118
     * @method _copyObject
119
     * @param {Object} obj Object literal to be copied.
120
     * @return Object
121
     * @private
122
     */
123
    _copyObject: function(obj) {
124
        var newObj = {},
125
            key,
126
            val;
127
        for(key in obj)
128
        {
129
            if(obj.hasOwnProperty(key))
130
            {
131
                val = obj[key];
132
                if(typeof val === "object" && !Y_Lang.isArray(val))
133
                {
134
                    newObj[key] = this._copyObject(val);
135
                }
136
                else
137
                {
138
                    newObj[key] = val;
139
                }
140
            }
141
        }
142
        return newObj;
143
    },
144
 
145
    /**
146
     * Gets the default value for the `styles` attribute.
147
     *
148
     * @method _getDefaultStyles
149
     * @return Object
150
     * @protected
151
     */
152
    _getDefaultStyles: function()
153
    {
154
        return {padding:{
155
            top:0,
156
            right: 0,
157
            bottom: 0,
158
            left: 0
159
        }};
160
    }
161
};
162
 
163
Y.augment(Renderer, Y.Attribute);
164
Y.Renderer = Renderer;
165
 
166
/**
167
 * The axis-base submodule contains functionality for the handling of axis data in a chart.
168
 *
169
 * @module charts
170
 * @submodule axis-base
171
 */
172
/**
173
 * An abstract class that provides the core functionality used by the following classes:
174
 * <ul>
175
 *      <li>{{#crossLink "CategoryAxisBase"}}{{/crossLink}}</li>
176
 *      <li>{{#crossLink "NumericAxisBase"}}{{/crossLink}}</li>
177
 *      <li>{{#crossLink "StackedAxisBase"}}{{/crossLink}}</li>
178
 *      <li>{{#crossLink "TimeAxisBase"}}{{/crossLink}}</li>
179
 *      <li>{{#crossLink "CategoryAxis"}}{{/crossLink}}</li>
180
 *      <li>{{#crossLink "NumericAxis"}}{{/crossLink}}</li>
181
 *      <li>{{#crossLink "StackedAxis"}}{{/crossLink}}</li>
182
 *      <li>{{#crossLink "TimeAxis"}}{{/crossLink}}</li>
183
 *  </ul>
184
 *
185
 * @class AxisBase
186
 * @constructor
187
 * @extends Base
188
 * @uses Renderer
189
 * @param {Object} config (optional) Configuration parameters.
190
 * @submodule axis-base
191
 */
192
Y.AxisBase = Y.Base.create("axisBase", Y.Base, [Y.Renderer], {
193
    /**
194
     * @method initializer
195
     * @private
196
     */
197
    initializer: function()
198
    {
199
        this.after("minimumChange", Y.bind(this._keyChangeHandler, this));
200
        this.after("maximumChange", Y.bind(this._keyChangeHandler, this));
201
        this.after("keysChange", this._keyChangeHandler);
202
        this.after("dataProviderChange", this._dataProviderChangeHandler);
203
    },
204
 
205
    /**
206
     * Returns the value corresponding to the origin on the axis.
207
     *
208
     * @method getOrigin
209
     * @return Number
210
     */
211
    getOrigin: function() {
212
        return this.get("minimum");
213
    },
214
 
215
    /**
216
     * Handles changes to `dataProvider`.
217
     *
218
     * @method _dataProviderChangeHandler
219
     * @param {Object} e Event object.
220
     * @private
221
     */
222
    _dataProviderChangeHandler: function()
223
    {
224
        var keyCollection = this.get("keyCollection").concat(),
225
            keys = this.get("keys"),
226
            i;
227
        if(keys)
228
        {
229
            for(i in keys)
230
            {
231
                if(keys.hasOwnProperty(i))
232
                {
233
                    delete keys[i];
234
                }
235
            }
236
        }
237
        if(keyCollection && keyCollection.length)
238
        {
239
            this.set("keys", keyCollection);
240
        }
241
    },
242
 
243
    /**
244
     * Calculates the maximum and minimum values for the `Data`.
245
     *
246
     * @method _updateMinAndMax
247
     * @private
248
     */
249
    _updateMinAndMax: function() {
250
    },
251
 
252
    /**
253
     * Constant used to generate unique id.
254
     *
255
     * @property GUID
256
     * @type String
257
     * @private
258
     */
259
    GUID: "yuibaseaxis",
260
 
261
    /**
262
     * Type of data used in `Axis`.
263
     *
264
     * @property _type
265
     * @type String
266
     * @readOnly
267
     * @private
268
     */
269
    _type: null,
270
 
271
    /**
272
     * Storage for `setMaximum` attribute.
273
     *
274
     * @property _setMaximum
275
     * @type Object
276
     * @private
277
     */
278
    _setMaximum: null,
279
 
280
    /**
281
     * Storage for `setMinimum` attribute.
282
     *
283
     * @property _setMinimum
284
     * @type Object
285
     * @private
286
     */
287
    _setMinimum: null,
288
 
289
    /**
290
     * Reference to data array.
291
     *
292
     * @property _data
293
     * @type Array
294
     * @private
295
     */
296
    _data: null,
297
 
298
    /**
299
     * Indicates whether the all data is up to date.
300
     *
301
     * @property _updateTotalDataFlag
302
     * @type Boolean
303
     * @private
304
     */
305
    _updateTotalDataFlag: true,
306
 
307
    /**
308
     * Storage for `dataReady` attribute.
309
     *
310
     * @property _dataReady
311
     * @type Boolean
312
     * @readOnly
313
     * @private
314
     */
315
    _dataReady: false,
316
 
317
    /**
318
     * Adds an array to the key hash.
319
     *
320
     * @method addKey
321
     * @param value Indicates what key to use in retrieving
322
     * the array.
323
     */
324
    addKey: function (value)
325
	{
326
        this.set("keys", value);
327
	},
328
 
329
    /**
330
     * Gets an array of values based on a key.
331
     *
332
     * @method _getKeyArray
333
     * @param {String} key Value key associated with the data array.
334
     * @param {Array} data Array in which the data resides.
335
     * @return Array
336
     * @private
337
     */
338
    _getKeyArray: function(key, data)
339
    {
340
        var i = 0,
341
            obj,
342
            keyArray = [],
343
            len = data.length;
344
        for(; i < len; ++i)
345
        {
346
            obj = data[i];
347
            keyArray[i] = obj[key];
348
        }
349
        return keyArray;
350
    },
351
 
352
    /**
353
     * Updates the total data array.
354
     *
355
     * @method _updateTotalData
356
     * @private
357
     */
358
    _updateTotalData: function()
359
    {
360
		var keys = this.get("keys"),
361
            i;
362
        this._data = [];
363
        for(i in keys)
364
        {
365
            if(keys.hasOwnProperty(i))
366
            {
367
                this._data = this._data.concat(keys[i]);
368
            }
369
        }
370
        this._updateTotalDataFlag = false;
371
    },
372
 
373
    /**
374
     * Removes an array from the key hash.
375
     *
376
     * @method removeKey
377
     * @param {String} value Indicates what key to use in removing from
378
     * the hash.
379
     */
380
    removeKey: function(value)
381
    {
382
        var keys = this.get("keys");
383
        if(keys.hasOwnProperty(value))
384
        {
385
            delete keys[value];
386
            this._keyChangeHandler();
387
        }
388
    },
389
 
390
    /**
391
     * Returns a value based of a key value and an index.
392
     *
393
     * @method getKeyValueAt
394
     * @param {String} key value used to look up the correct array
395
     * @param {Number} index within the array
396
     * @return Number
397
     */
398
    getKeyValueAt: function(key, index)
399
    {
400
        var value = NaN,
401
            keys = this.get("keys");
402
        if(keys[key] && Y_Lang.isNumber(parseFloat(keys[key][index])))
403
        {
404
            value = keys[key][index];
405
        }
406
        return parseFloat(value);
407
    },
408
 
409
    /**
410
     * Returns values based on key identifiers. When a string is passed as an argument, an array of values is returned.
411
     * When an array of keys is passed as an argument, an object literal with an array of values mapped to each key is
412
     * returned.
413
     *
414
     * @method getDataByKey
415
     * @param {String|Array} value value used to identify the array
416
     * @return Array|Object
417
     */
418
    getDataByKey: function (value)
419
    {
420
        var obj,
421
            i,
422
            len,
423
            key,
424
            keys = this.get("keys");
425
        if(Y_Lang.isArray(value))
426
        {
427
            obj = {};
428
            len = value.length;
429
            for(i = 0; i < len; i = i + 1)
430
            {
431
                key = value[i];
432
                if(keys[key])
433
                {
434
                    obj[key] = this.getDataByKey(key);
435
                }
436
            }
437
        }
438
        else if(keys[value])
439
        {
440
            obj = keys[value];
441
        }
442
        else
443
        {
444
            obj = null;
445
        }
446
        return obj;
447
    },
448
 
449
    /**
450
     * Returns the total number of majorUnits that will appear on an axis.
451
     *
452
     * @method getTotalMajorUnits
453
     * @return Number
454
     */
455
    getTotalMajorUnits: function()
456
    {
457
        var units,
458
            majorUnit = this.get("styles").majorUnit;
459
        units = majorUnit.count;
460
        return units;
461
    },
462
 
463
    /**
464
     * Gets the distance that the first and last ticks are offset from there respective
465
     * edges.
466
     *
467
     * @method getEdgeOffset
468
     * @param {Number} ct Number of ticks on the axis.
469
     * @param {Number} l Length (in pixels) of the axis.
470
     * @return Number
471
     */
472
    getEdgeOffset: function(ct, l)
473
    {
474
        var edgeOffset;
475
        if(this.get("calculateEdgeOffset")) {
476
            edgeOffset = (l/ct)/2;
477
        } else {
478
            edgeOffset = 0;
479
        }
480
        return edgeOffset;
481
    },
482
 
483
    /**
484
     * Updates the `Axis` after a change in keys.
485
     *
486
     * @method _keyChangeHandler
487
     * @param {Object} e Event object.
488
     * @private
489
     */
490
    _keyChangeHandler: function()
491
    {
492
        this._updateMinAndMax();
493
        this._updateTotalDataFlag = true;
494
        this.fire("dataUpdate");
495
    },
496
 
497
    /**
498
     * Gets the default value for the `styles` attribute. Overrides
499
     * base implementation.
500
     *
501
     * @method _getDefaultStyles
502
     * @return Object
503
     * @protected
504
     */
505
    _getDefaultStyles: function()
506
    {
507
        var axisstyles = {
508
            majorUnit: {
509
                determinant:"count",
510
                count:11,
511
                distance:75
512
            }
513
        };
514
        return axisstyles;
515
    },
516
 
517
    /**
518
     * Getter method for maximum attribute.
519
     *
520
     * @method _maximumGetter
521
     * @return Number
522
     * @private
523
     */
524
    _maximumGetter: function ()
525
    {
526
        var max = this.get("dataMaximum"),
527
            min = this.get("minimum");
528
        //If all values are zero, force a range so that the Axis and related series
529
        //will still render.
530
        if(min === 0 && max === 0)
531
        {
532
            max = 10;
533
        }
534
        if(Y_Lang.isNumber(this._setMaximum))
535
        {
536
            max = this._setMaximum;
537
        }
538
        return parseFloat(max);
539
    },
540
 
541
    /**
542
     * Setter method for maximum attribute.
543
     *
544
     * @method _maximumSetter
545
     * @param {Object} value
546
     * @private
547
     */
548
    _maximumSetter: function (value)
549
    {
550
        this._setMaximum = parseFloat(value);
551
        return value;
552
    },
553
 
554
    /**
555
     * Getter method for minimum attribute.
556
     *
557
     * @method _minimumGetter
558
     * @return Number
559
     * @private
560
     */
561
    _minimumGetter: function ()
562
    {
563
        var min = this.get("dataMinimum");
564
        if(Y_Lang.isNumber(this._setMinimum))
565
        {
566
            min = this._setMinimum;
567
        }
568
        return parseFloat(min);
569
    },
570
 
571
    /**
572
     * Setter method for minimum attribute.
573
     *
574
     * @method _minimumSetter
575
     * @param {Object} value
576
     * @private
577
     */
578
    _minimumSetter: function(val)
579
    {
580
        this._setMinimum = parseFloat(val);
581
        return val;
582
    },
583
 
584
    /**
585
     * Indicates whether or not the maximum attribute has been explicitly set.
586
     *
587
     * @method _getSetMax
588
     * @return Boolean
589
     * @private
590
     */
591
    _getSetMax: function()
592
    {
593
        return Y_Lang.isNumber(this._setMaximum);
594
    },
595
 
596
 
597
    /**
598
     * Returns and array of coordinates corresponding to an array of data values.
599
     *
600
     * @method _getCoordsFromValues
601
     * @param {Number} min The minimum for the axis.
602
     * @param {Number} max The maximum for the axis.
603
     * @param {Number} length The distance that the axis spans.
604
     * @param {Array} dataValues An array of values.
605
     * @param {Number} offset Value in which to offset the coordinates.
606
     * @param {Boolean} reverse Indicates whether the coordinates should start from
607
     * the end of an axis. Only used in the numeric implementation.
608
     * @return Array
609
     * @private
610
     */
611
    _getCoordsFromValues: function(min, max, length, dataValues, offset, reverse)
612
    {
613
        var i,
614
            valuecoords = [],
615
            len = dataValues.length;
616
        for(i = 0; i < len; i = i + 1)
617
        {
618
            valuecoords.push(this._getCoordFromValue.apply(this, [min, max, length, dataValues[i], offset, reverse]));
619
        }
620
        return valuecoords;
621
    },
622
 
623
    /**
624
     * Returns and array of data values based on the axis' range and number of values.
625
     *
626
     * @method _getDataValuesByCount
627
     * @param {Number} count The number of values to be used.
628
     * @param {Number} min The minimum value of the axis.
629
     * @param {Number} max The maximum value of the axis.
630
     * @return Array
631
     * @private
632
     */
633
    _getDataValuesByCount: function(count, min, max)
634
    {
635
        var dataValues = [],
636
            dataValue = min,
637
            len = count - 1,
638
            range = max - min,
639
            increm = range/len,
640
            i;
641
        for(i = 0; i < len; i = i + 1)
642
        {
643
            dataValues.push(dataValue);
644
            dataValue = dataValue + increm;
645
        }
646
        dataValues.push(max);
647
        return dataValues;
648
    },
649
 
650
    /**
651
     * Indicates whether or not the minimum attribute has been explicitly set.
652
     *
653
     * @method _getSetMin
654
     * @return Boolean
655
     * @private
656
     */
657
    _getSetMin: function()
658
    {
659
        return Y_Lang.isNumber(this._setMinimum);
660
    }
661
}, {
662
    ATTRS: {
663
        /**
664
         * Determines whether and offset is automatically calculated for the edges of the axis.
665
         *
666
         * @attribute calculateEdgeOffset
667
         * @type Boolean
668
         */
669
        calculateEdgeOffset: {
670
            value: false
671
        },
672
 
673
        labelFunction: {
674
            valueFn: function() {
675
                return this.formatLabel;
676
            }
677
        },
678
 
679
        /**
680
         * Hash of array identifed by a string value.
681
         *
682
         * @attribute keys
683
         * @type Object
684
         */
685
        keys: {
686
            value: {},
687
 
688
            setter: function(val)
689
            {
690
                var keys = {},
691
                    i,
692
                    len,
693
                    data = this.get("dataProvider");
694
                if(Y_Lang.isArray(val))
695
                {
696
                    len = val.length;
697
                    for(i = 0; i < len; ++i)
698
                    {
699
                        keys[val[i]] = this._getKeyArray(val[i], data);
700
                    }
701
 
702
                }
703
                else if(Y_Lang.isString(val))
704
                {
705
                    keys = this.get("keys");
706
                    keys[val] = this._getKeyArray(val, data);
707
                }
708
                else
709
                {
710
                    for(i in val)
711
                    {
712
                        if(val.hasOwnProperty(i))
713
                        {
714
                            keys[i] = this._getKeyArray(i, data);
715
                        }
716
                    }
717
                }
718
                this._updateTotalDataFlag = true;
719
                return keys;
720
            }
721
        },
722
 
723
        /**
724
         *Returns the type of axis data
725
         *  <dl>
726
         *      <dt>time</dt><dd>Manages time data</dd>
727
         *      <dt>stacked</dt><dd>Manages stacked numeric data</dd>
728
         *      <dt>numeric</dt><dd>Manages numeric data</dd>
729
         *      <dt>category</dt><dd>Manages categorical data</dd>
730
         *  </dl>
731
         *
732
         * @attribute type
733
         * @type String
734
         */
735
        type:
736
        {
737
            readOnly: true,
738
 
739
            getter: function ()
740
            {
741
                return this._type;
742
            }
743
        },
744
 
745
        /**
746
         * Instance of `ChartDataProvider` that the class uses
747
         * to build its own data.
748
         *
749
         * @attribute dataProvider
750
         * @type Array
751
         */
752
        dataProvider:{
753
            setter: function (value)
754
            {
755
                return value;
756
            }
757
        },
758
 
759
        /**
760
         * The maximum value contained in the `data` array. Used for
761
         * `maximum` when `autoMax` is true.
762
         *
763
         * @attribute dataMaximum
764
         * @type Number
765
         */
766
        dataMaximum: {
767
            getter: function ()
768
            {
769
                if(!Y_Lang.isNumber(this._dataMaximum))
770
                {
771
                    this._updateMinAndMax();
772
                }
773
                return this._dataMaximum;
774
            }
775
        },
776
 
777
        /**
778
         * The maximum value that will appear on an axis.
779
         *
780
         * @attribute maximum
781
         * @type Number
782
         */
783
        maximum: {
784
            lazyAdd: false,
785
 
786
            getter: "_maximumGetter",
787
 
788
            setter: "_maximumSetter"
789
        },
790
 
791
        /**
792
         * The minimum value contained in the `data` array. Used for
793
         * `minimum` when `autoMin` is true.
794
         *
795
         * @attribute dataMinimum
796
         * @type Number
797
         */
798
        dataMinimum: {
799
            getter: function ()
800
            {
801
                if(!Y_Lang.isNumber(this._dataMinimum))
802
                {
803
                    this._updateMinAndMax();
804
                }
805
                return this._dataMinimum;
806
            }
807
        },
808
 
809
        /**
810
         * The minimum value that will appear on an axis.
811
         *
812
         * @attribute minimum
813
         * @type Number
814
         */
815
        minimum: {
816
            lazyAdd: false,
817
 
818
            getter: "_minimumGetter",
819
 
820
            setter: "_minimumSetter"
821
        },
822
 
823
        /**
824
         * Determines whether the maximum is calculated or explicitly
825
         * set by the user.
826
         *
827
         * @attribute setMax
828
         * @type Boolean
829
         */
830
        setMax: {
831
            readOnly: true,
832
 
833
            getter: "_getSetMax"
834
        },
835
 
836
        /**
837
         * Determines whether the minimum is calculated or explicitly
838
         * set by the user.
839
         *
840
         * @attribute setMin
841
         * @type Boolean
842
         */
843
        setMin: {
844
            readOnly: true,
845
 
846
            getter: "_getSetMin"
847
        },
848
 
849
        /**
850
         * Array of axis data
851
         *
852
         * @attribute data
853
         * @type Array
854
         */
855
        data: {
856
            getter: function ()
857
            {
858
                if(!this._data || this._updateTotalDataFlag)
859
                {
860
                    this._updateTotalData();
861
                }
862
                return this._data;
863
            }
864
        },
865
 
866
        /**
867
         * Array containing all the keys in the axis.
868
 
869
         * @attribute keyCollection
870
         * @type Array
871
         */
872
        keyCollection: {
873
            getter: function()
874
            {
875
                var keys = this.get("keys"),
876
                    i,
877
                    col = [];
878
                for(i in keys)
879
                {
880
                    if(keys.hasOwnProperty(i))
881
                    {
882
                        col.push(i);
883
                    }
884
                }
885
                return col;
886
            },
887
            readOnly: true
888
        },
889
 
890
        /**
891
         * Object which should have by the labelFunction
892
         *
893
         * @attribute labelFunctionScope
894
         * @type Object
895
         */
896
        labelFunctionScope: {}
897
    }
898
});
899
 
900
 
901
}, '3.18.1', {"requires": ["classnamemanager", "datatype-number", "datatype-date", "base", "event-custom"]});