source: Dev/trunk/src/client/dojox/charting/plot2d/Bars.js @ 525

Last change on this file since 525 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 9.7 KB
Line 
1define(["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "dojo/has", "./CartesianBase", "./_PlotEvents", "./common",
2        "dojox/gfx/fx", "dojox/lang/utils", "dojox/lang/functional", "dojox/lang/functional/reversed"],
3        function(lang, arr, declare, has, CartesianBase, _PlotEvents, dc, fx, du, df, dfr){
4               
5        /*=====
6        declare("dojox.charting.plot2d.__BarCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, {
7                // summary:
8                //              Additional keyword arguments for bar charts.
9       
10                // minBarSize: Number?
11                //              The minimum size for a bar in pixels.  Default is 1.
12                minBarSize: 1,
13       
14                // maxBarSize: Number?
15                //              The maximum size for a bar in pixels.  Default is 1.
16                maxBarSize: 1,
17
18                // stroke: dojox.gfx.Stroke?
19                //              An optional stroke to use for any series on the plot.
20                stroke:         {},
21
22                // outline: dojox.gfx.Stroke?
23                //              An optional stroke used to outline any series on the plot.
24                outline:        {},
25
26                // shadow: dojox.gfx.Stroke?
27                //              An optional stroke to use to draw any shadows for a series on a plot.
28                shadow:         {},
29
30                // fill: dojox.gfx.Fill?
31                //              Any fill to be used for elements on the plot.
32                fill:           {},
33
34                // filter: dojox.gfx.Filter?
35                //              An SVG filter to be used for elements on the plot. gfx SVG renderer must be used and dojox/gfx/svgext must
36                //              be required for this to work.
37                filter:         {},
38
39                // styleFunc: Function?
40                //              A function that returns a styling object for the a given data item.
41                styleFunc:      null,
42
43                // font: String?
44                //              A font definition to be used for labels and other text-based elements on the plot.
45                font:           "",
46
47                // fontColor: String|dojo.Color?
48                //              The color to be used for any text-based elements on the plot.
49                fontColor:      "",
50               
51                // enableCache: Boolean?
52                //              Whether the bars rect are cached from one rendering to another. This improves the rendering performance of
53                //              successive rendering but penalize the first rendering.  Default false.
54                enableCache: false
55        });
56        =====*/
57        var purgeGroup = dfr.lambda("item.purgeGroup()");
58
59        return declare("dojox.charting.plot2d.Bars", [CartesianBase, _PlotEvents], {
60                // summary:
61                //              The plot object representing a bar chart (horizontal bars).
62                defaultParams: {
63                        gap:    0,              // gap between columns in pixels
64                        animate: null,   // animate bars into place
65                        enableCache: false
66                },
67                optionalParams: {
68                        minBarSize:     1,      // minimal bar width in pixels
69                        maxBarSize:     1,      // maximal bar width in pixels
70                        // theme component
71                        stroke:         {},
72                        outline:        {},
73                        shadow:         {},
74                        fill:           {},
75                        filter:     {},
76                        styleFunc:  null,
77                        font:           "",
78                        fontColor:      ""
79                },
80
81                constructor: function(chart, kwArgs){
82                        // summary:
83                        //              The constructor for a bar chart.
84                        // chart: dojox/charting/Chart
85                        //              The chart this plot belongs to.
86                        // kwArgs: dojox.charting.plot2d.__BarCtorArgs?
87                        //              An optional keyword arguments object to help define the plot.
88                        this.opt = lang.clone(lang.mixin(this.opt, this.defaultParams));
89                        du.updateWithObject(this.opt, kwArgs);
90                        du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
91                        this.animate = this.opt.animate;
92                },
93
94                getSeriesStats: function(){
95                        // summary:
96                        //              Calculate the min/max on all attached series in both directions.
97                        // returns: Object
98                        //              {hmin, hmax, vmin, vmax} min/max in both directions.
99                        var stats = dc.collectSimpleStats(this.series), t;
100                        stats.hmin -= 0.5;
101                        stats.hmax += 0.5;
102                        t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t;
103                        t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t;
104                        return stats; // Object
105                },
106               
107                createRect: function(run, creator, params){
108                        var rect;
109                        if(this.opt.enableCache && run._rectFreePool.length > 0){
110                                rect = run._rectFreePool.pop();
111                                rect.setShape(params);
112                                // was cleared, add it back
113                                creator.add(rect);
114                        }else{
115                                rect = creator.createRect(params);
116                        }
117                        if(this.opt.enableCache){
118                                run._rectUsePool.push(rect);
119                        }
120                        return rect;
121                },
122
123                createLabel: function(group, value, bbox, theme){
124                        if(this.opt.labels && this.opt.labelStyle == "outside"){
125                                var y = bbox.y + bbox.height / 2;
126                                var x = bbox.x + bbox.width + this.opt.labelOffset;
127                                this.renderLabel(group, x, y, this._getLabel(isNaN(value.y)?value:value.y), theme, "start");
128                }else{
129                                this.inherited(arguments);
130                        }
131                },
132
133                render: function(dim, offsets){
134                        // summary:
135                        //              Run the calculations for any axes for this plot.
136                        // dim: Object
137                        //              An object in the form of { width, height }
138                        // offsets: Object
139                        //              An object of the form { l, r, t, b}.
140                        // returns: dojox/charting/plot2d/Bars
141                        //              A reference to this plot for functional chaining.
142                        if(this.zoom && !this.isDataDirty()){
143                                return this.performZoom(dim, offsets); // dojox/charting/plot2d/Bars
144                        }
145                        this.dirty = this.isDirty();
146                        this.resetEvents();
147                        var s;
148                        if(this.dirty){
149                                arr.forEach(this.series, purgeGroup);
150                                this._eventSeries = {};
151                                this.cleanGroup();
152                                s = this.getGroup();
153                                df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
154                        }
155                        var t = this.chart.theme,
156                                ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
157                                vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
158                                baseline = Math.max(0, this._hScaler.bounds.lower),
159                                baselineWidth = ht(baseline),
160                                events = this.events();
161                        var bar = this.getBarProperties();
162                       
163                        for(var i = this.series.length - 1; i >= 0; --i){
164                                var run = this.series[i];
165                                if(!this.dirty && !run.dirty){
166                                        t.skip();
167                                        this._reconnectEvents(run.name);
168                                        continue;
169                                }
170                                run.cleanGroup();
171                                if(this.opt.enableCache){
172                                        run._rectFreePool = (run._rectFreePool?run._rectFreePool:[]).concat(run._rectUsePool?run._rectUsePool:[]);
173                                        run._rectUsePool = [];
174                                }
175                                var theme = t.next("bar", [this.opt, run]),
176                                        eventSeries = new Array(run.data.length);
177                                s = run.group;
178                                var indexed = arr.some(run.data, function(item){
179                                        return typeof item == "number" || (item && !item.hasOwnProperty("x"));
180                                });
181                                // on indexed charts we can easily just interate from the first visible to the last visible
182                                // data point to save time
183                                var min = indexed?Math.max(0, Math.floor(this._vScaler.bounds.from - 1)):0;
184                                var max = indexed?Math.min(run.data.length, Math.ceil(this._vScaler.bounds.to)):run.data.length;
185                                for(var j = min; j < max; ++j){
186                                        var value = run.data[j];
187                                        if(value != null){
188                                                var val = this.getValue(value, j, i, indexed),
189                                                        hv = ht(val.y),
190                                                        w = Math.abs(hv - baselineWidth),
191                                                        finalTheme,
192                                                        sshape;
193                                                if(this.opt.styleFunc || typeof value != "number"){
194                                                        var tMixin = typeof value != "number" ? [value] : [];
195                                                        if(this.opt.styleFunc){
196                                                                tMixin.push(this.opt.styleFunc(value));
197                                                        }
198                                                        finalTheme = t.addMixin(theme, "bar", tMixin, true);
199                                                }else{
200                                                        finalTheme = t.post(theme, "bar");
201                                                }
202                                                if(w >= 0 && bar.height >= 1){
203                                                        var rect = {
204                                                                x: offsets.l + (val.y < baseline ? hv : baselineWidth),
205                                                                y: dim.height - offsets.b - vt(val.x + 1.5) + bar.gap + bar.thickness * (this.series.length - i - 1),
206                                                                width: w,
207                                                                height: bar.height
208                                                        };
209                                                        if(finalTheme.series.shadow){
210                                                                var srect = lang.clone(rect);
211                                                                srect.x += finalTheme.series.shadow.dx;
212                                                                srect.y += finalTheme.series.shadow.dy;
213                                                                sshape = this.createRect(run, s, srect).setFill(finalTheme.series.shadow.color).setStroke(finalTheme.series.shadow);
214                                                                if(this.animate){
215                                                                        this._animateBar(sshape, offsets.l + baselineWidth, -w);
216                                                                }
217                                                        }
218                                                        var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets);
219                                                        specialFill = this._shapeFill(specialFill, rect);
220                                                        var shape = this.createRect(run, s, rect).setFill(specialFill).setStroke(finalTheme.series.stroke);
221                                                        if(shape.setFilter && finalTheme.series.filter){
222                                                                shape.setFilter(finalTheme.series.filter);
223                                                        }
224                                                        run.dyn.fill   = shape.getFill();
225                                                        run.dyn.stroke = shape.getStroke();
226                                                        if(events){
227                                                                var o = {
228                                                                        element: "bar",
229                                                                        index:   j,
230                                                                        run:     run,
231                                                                        shape:   shape,
232                                                                        shadow:  sshape,
233                                                                        cx:      val.y,
234                                                                        cy:      val.x + 1.5,
235                                                                        x:           indexed?j:run.data[j].x,
236                                                                        y:               indexed?run.data[j]:run.data[j].y
237                                                                };
238                                                                this._connectEvents(o);
239                                                                eventSeries[j] = o;
240                                                        }
241                                                        // if val.py is here, this means we are stacking and we need to subtract previous
242                                                        // value to get the high in which we will lay out the label
243                                                        if(!isNaN(val.py) && val.py > baseline){
244                                                                rect.x += ht(val.py);
245                                                                rect.width -= ht(val.py);
246                                                        }
247                                                        this.createLabel(s, value, rect, finalTheme);
248                                                        if(this.animate){
249                                                                this._animateBar(shape, offsets.l + baselineWidth, -w);
250                                                        }
251                                                }
252                                        }
253                                }
254                                this._eventSeries[run.name] = eventSeries;
255                                run.dirty = false;
256                        }
257                        this.dirty = false;
258                        // chart mirroring starts
259                        if(has("dojo-bidi")){
260                                this._checkOrientation(this.group, dim, offsets);
261                        }
262                        // chart mirroring ends
263                        return this;    //      dojox/charting/plot2d/Bars
264                },
265                getValue: function(value, j, seriesIndex, indexed){
266                        var y, x;
267                        if(indexed){
268                                if(typeof value == "number"){
269                                        y = value;
270                                }else{
271                                        y = value.y;
272                                }
273                                x = j;
274                        }else{
275                                y = value.y;
276                                x = value.x -1;
277                        }
278                        return {y:y, x:x};
279                },
280                getBarProperties: function(){
281                        var f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt);
282                        return {gap: f.gap, height: f.size, thickness: 0};
283                },
284                _animateBar: function(shape, hoffset, hsize){
285                        if(hsize==0){
286                                hsize = 1;
287                        }
288                        fx.animateTransform(lang.delegate({
289                                shape: shape,
290                                duration: 1200,
291                                transform: [
292                                        {name: "translate", start: [hoffset - (hoffset/hsize), 0], end: [0, 0]},
293                                        {name: "scale", start: [1/hsize, 1], end: [1, 1]},
294                                        {name: "original"}
295                                ]
296                        }, this.animate)).play();
297                }
298        });
299});
Note: See TracBrowser for help on using the repository browser.