source: Dev/branches/rest-dojo-ui/client/dojox/charting/plot2d/Default.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 12.1 KB
Line 
1define(["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array",
2                "./Base", "./common", "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"],
3        function(lang, declare, arr, Base, dc, df, dfr, du, fx){
4
5        /*=====
6        dojo.declare("dojox.charting.plot2d.__DefaultCtorArgs", dojox.charting.plot2d.__PlotCtorArgs, {
7                //      summary:
8                //              The arguments used for any/most plots.
9       
10                //      hAxis: String?
11                //              The horizontal axis name.
12                hAxis: "x",
13       
14                //      vAxis: String?
15                //              The vertical axis name
16                vAxis: "y",
17       
18                //      lines: Boolean?
19                //              Whether or not to draw lines on this plot.  Defaults to true.
20                lines:   true,
21       
22                //      areas: Boolean?
23                //              Whether or not to draw areas on this plot. Defaults to false.
24                areas:   false,
25       
26                //      markers: Boolean?
27                //              Whether or not to draw markers at data points on this plot. Default is false.
28                markers: false,
29       
30                //      tension: Number|String?
31                //              Whether or not to apply 'tensioning' to the lines on this chart.
32                //              Options include a number, "X", "x", or "S"; if a number is used, the
33                //              simpler bezier curve calculations are used to draw the lines.  If X, x or S
34                //              is used, the more accurate smoothing algorithm is used.
35                tension: "",
36       
37                //      animate: Boolean?
38                //              Whether or not to animate the chart to place.
39                animate: false,
40       
41                //      stroke: dojox.gfx.Stroke?
42                //              An optional stroke to use for any series on the plot.
43                stroke:         {},
44       
45                //      outline: dojox.gfx.Stroke?
46                //              An optional stroke used to outline any series on the plot.
47                outline:        {},
48       
49                //      shadow: dojox.gfx.Stroke?
50                //              An optional stroke to use to draw any shadows for a series on a plot.
51                shadow:         {},
52       
53                //      fill: dojox.gfx.Fill?
54                //              Any fill to be used for elements on the plot (such as areas).
55                fill:           {},
56       
57                //      font: String?
58                //              A font definition to be used for labels and other text-based elements on the plot.
59                font:           "",
60       
61                //      fontColor: String|dojo.Color?
62                //              The color to be used for any text-based elements on the plot.
63                fontColor:      "",
64       
65                //      markerStroke: dojo.gfx.Stroke?
66                //              An optional stroke to use for any markers on the plot.
67                markerStroke:           {},
68       
69                //      markerOutline: dojo.gfx.Stroke?
70                //              An optional outline to use for any markers on the plot.
71                markerOutline:          {},
72       
73                //      markerShadow: dojo.gfx.Stroke?
74                //              An optional shadow to use for any markers on the plot.
75                markerShadow:           {},
76       
77                //      markerFill: dojo.gfx.Fill?
78                //              An optional fill to use for any markers on the plot.
79                markerFill:                     {},
80       
81                //      markerFont: String?
82                //              An optional font definition to use for any markers on the plot.
83                markerFont:                     "",
84       
85                //      markerFontColor: String|dojo.Color?
86                //              An optional color to use for any marker text on the plot.
87                markerFontColor:        "",
88               
89                //      enableCache: Boolean?
90                //              Whether the markers are cached from one rendering to another. This improves the rendering performance of
91                //              successive rendering but penalize the first rendering.  Default false.
92                enableCache: false
93        });
94       
95        var Base = dojox.charting.plot2d.Base;
96=====*/
97
98        var purgeGroup = dfr.lambda("item.purgeGroup()");
99
100        var DEFAULT_ANIMATION_LENGTH = 1200;    // in ms
101
102        return declare("dojox.charting.plot2d.Default", Base, {
103                defaultParams: {
104                        hAxis: "x",             // use a horizontal axis named "x"
105                        vAxis: "y",             // use a vertical axis named "y"
106                        lines:   true,  // draw lines
107                        areas:   false, // draw areas
108                        markers: false, // draw markers
109                        tension: "",    // draw curved lines (tension is "X", "x", or "S")
110                        animate: false, // animate chart to place
111                        enableCache: false
112                },
113                optionalParams: {
114                        // theme component
115                        stroke:         {},
116                        outline:        {},
117                        shadow:         {},
118                        fill:           {},
119                        font:           "",
120                        fontColor:      "",
121                        markerStroke:           {},
122                        markerOutline:          {},
123                        markerShadow:           {},
124                        markerFill:                     {},
125                        markerFont:                     "",
126                        markerFontColor:        ""
127                },
128
129                constructor: function(chart, kwArgs){
130                        //      summary:
131                        //              Return a new plot.
132                        //      chart: dojox.charting.Chart
133                        //              The chart this plot belongs to.
134                        //      kwArgs: dojox.charting.plot2d.__DefaultCtorArgs?
135                        //              An optional arguments object to help define this plot.
136                        this.opt = lang.clone(this.defaultParams);
137            du.updateWithObject(this.opt, kwArgs);
138            du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
139                        this.series = [];
140                        this.hAxis = this.opt.hAxis;
141                        this.vAxis = this.opt.vAxis;
142
143                        // animation properties
144                        this.animate = this.opt.animate;
145                },
146
147                createPath: function(run, creator, params){
148                        var path;
149                        if(this.opt.enableCache && run._pathFreePool.length > 0){
150                                path = run._pathFreePool.pop();
151                                path.setShape(params);
152                                // was cleared, add it back
153                                creator.add(path);
154                        }else{
155                                path = creator.createPath(params);
156                        }
157                        if(this.opt.enableCache){
158                                run._pathUsePool.push(path);
159                        }
160                        return path;
161                },
162
163                render: function(dim, offsets){
164                        //      summary:
165                        //              Render/draw everything on this plot.
166                        //      dim: Object
167                        //              An object of the form { width, height }
168                        //      offsets: Object
169                        //              An object of the form { l, r, t, b }
170                        //      returns: dojox.charting.plot2d.Default
171                        //              A reference to this plot for functional chaining.
172
173                        // make sure all the series is not modified
174                        if(this.zoom && !this.isDataDirty()){
175                                return this.performZoom(dim, offsets);
176                        }
177
178                        this.resetEvents();
179                        this.dirty = this.isDirty();
180                        if(this.dirty){
181                                arr.forEach(this.series, purgeGroup);
182                                this._eventSeries = {};
183                                this.cleanGroup();
184                                this.group.setTransform(null);
185                                var s = this.group;
186                                df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
187                        }
188                        var t = this.chart.theme, stroke, outline, marker, events = this.events();
189
190                        for(var i = this.series.length - 1; i >= 0; --i){
191                                var run = this.series[i];
192                                if(!this.dirty && !run.dirty){
193                                        t.skip();
194                                        this._reconnectEvents(run.name);
195                                        continue;
196                                }
197                                run.cleanGroup();
198                                if(this.opt.enableCache){
199                                        run._pathFreePool = (run._pathFreePool?run._pathFreePool:[]).concat(run._pathUsePool?run._pathUsePool:[]);
200                                        run._pathUsePool = [];
201                                }
202                                if(!run.data.length){
203                                        run.dirty = false;
204                                        t.skip();
205                                        continue;
206                                }
207
208                                var theme = t.next(this.opt.areas ? "area" : "line", [this.opt, run], true),
209                                        s = run.group, rsegments = [], startindexes = [], rseg = null, lpoly,
210                                        ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
211                                        vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
212                                        eventSeries = this._eventSeries[run.name] = new Array(run.data.length);
213                               
214                                // optim works only for index based case
215                                var indexed = typeof run.data[0] == "number";
216                                var min = indexed?Math.max(0, Math.floor(this._hScaler.bounds.from - 1)):0,
217                                                max = indexed?Math.min(run.data.length, Math.ceil(this._hScaler.bounds.to)):run.data.length;
218
219                // split the run data into dense segments (each containing no nulls)
220                for(var j = min; j < max; j++){
221                    if(run.data[j] != null){
222                        if(!rseg){
223                            rseg = [];
224                            startindexes.push(j);
225                            rsegments.push(rseg);
226                        }
227                        rseg.push(run.data[j]);
228                    }else{
229                        rseg = null;
230                    }
231                }
232
233                for(var seg = 0; seg < rsegments.length; seg++){
234                                        if(typeof rsegments[seg][0] == "number"){
235                                                lpoly = arr.map(rsegments[seg], function(v, i){
236                                                        return {
237                                                                x: ht(i + startindexes[seg] + 1) + offsets.l,
238                                                                y: dim.height - offsets.b - vt(v)
239                                                        };
240                                                }, this);
241                                        }else{
242                                                lpoly = arr.map(rsegments[seg], function(v, i){
243                                                        return {
244                                                                x: ht(v.x) + offsets.l,
245                                                                y: dim.height - offsets.b - vt(v.y)
246                                                        };
247                                                }, this);
248                                        }
249
250                                        var lpath = this.opt.tension ? dc.curve(lpoly, this.opt.tension) : "";
251
252                                        if(this.opt.areas && lpoly.length > 1){
253                                                var fill = theme.series.fill;
254                                                var apoly = lang.clone(lpoly);
255                                                if(this.opt.tension){
256                                                        var apath = "L" + apoly[apoly.length-1].x + "," + (dim.height - offsets.b) +
257                                                                " L" + apoly[0].x + "," + (dim.height - offsets.b) +
258                                                                " L" + apoly[0].x + "," + apoly[0].y;
259                                                        run.dyn.fill = s.createPath(lpath + " " + apath).setFill(fill).getFill();
260                                                } else {
261                                                        apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b});
262                                                        apoly.push({x: lpoly[0].x, y: dim.height - offsets.b});
263                                                        apoly.push(lpoly[0]);
264                                                        run.dyn.fill = s.createPolyline(apoly).setFill(fill).getFill();
265                                                }
266                                        }
267                                        if(this.opt.lines || this.opt.markers){
268                                                // need a stroke
269                                                stroke = theme.series.stroke;
270                                                if(theme.series.outline){
271                                                        outline = run.dyn.outline = dc.makeStroke(theme.series.outline);
272                                                        outline.width = 2 * outline.width + stroke.width;
273                                                }
274                                        }
275                                        if(this.opt.markers){
276                                                run.dyn.marker = theme.symbol;
277                                        }
278                                        var frontMarkers = null, outlineMarkers = null, shadowMarkers = null;
279                                        if(stroke && theme.series.shadow && lpoly.length > 1){
280                                                var shadow = theme.series.shadow,
281                                                        spoly = arr.map(lpoly, function(c){
282                                                                return {x: c.x + shadow.dx, y: c.y + shadow.dy};
283                                                        });
284                                                if(this.opt.lines){
285                                                        if(this.opt.tension){
286                                                                run.dyn.shadow = s.createPath(dc.curve(spoly, this.opt.tension)).setStroke(shadow).getStroke();
287                                                        } else {
288                                                                run.dyn.shadow = s.createPolyline(spoly).setStroke(shadow).getStroke();
289                                                        }
290                                                }
291                                                if(this.opt.markers && theme.marker.shadow){
292                                                        shadow = theme.marker.shadow;
293                                                        shadowMarkers = arr.map(spoly, function(c){
294                                                                return this.createPath(run, s, "M" + c.x + " " + c.y + " " + theme.symbol).
295                                                                        setStroke(shadow).setFill(shadow.color);
296                                                        }, this);
297                                                }
298                                        }
299                                        if(this.opt.lines && lpoly.length > 1){
300                                                if(outline){
301                                                        if(this.opt.tension){
302                                                                run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke();
303                                                        } else {
304                                                                run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke();
305                                                        }
306                                                }
307                                                if(this.opt.tension){
308                                                        run.dyn.stroke = s.createPath(lpath).setStroke(stroke).getStroke();
309                                                } else {
310                                                        run.dyn.stroke = s.createPolyline(lpoly).setStroke(stroke).getStroke();
311                                                }
312                                        }
313                                        if(this.opt.markers){
314                                                frontMarkers = new Array(lpoly.length);
315                                                outlineMarkers = new Array(lpoly.length);
316                                                outline = null;
317                                                if(theme.marker.outline){
318                                                        outline = dc.makeStroke(theme.marker.outline);
319                                                        outline.width = 2 * outline.width + (theme.marker.stroke ? theme.marker.stroke.width : 0);
320                                                }
321                                                arr.forEach(lpoly, function(c, i){
322                                                        var path = "M" + c.x + " " + c.y + " " + theme.symbol;
323                                                        if(outline){
324                                                                outlineMarkers[i] = this.createPath(run, s, path).setStroke(outline);
325                                                        }
326                                                        frontMarkers[i] = this.createPath(run, s, path).setStroke(theme.marker.stroke).setFill(theme.marker.fill);
327                                                }, this);
328                                                run.dyn.markerFill = theme.marker.fill;
329                                                run.dyn.markerStroke = theme.marker.stroke;
330                                                if(events){
331                                                        arr.forEach(frontMarkers, function(s, i){
332                                                                var o = {
333                                                                        element: "marker",
334                                                                        index:   i + startindexes[seg],
335                                                                        run:     run,
336                                                                        shape:   s,
337                                                                        outline: outlineMarkers[i] || null,
338                                                                        shadow:  shadowMarkers && shadowMarkers[i] || null,
339                                                                        cx:      lpoly[i].x,
340                                                                        cy:      lpoly[i].y
341                                                                };
342                                                                if(typeof rsegments[seg][0] == "number"){
343                                                                        o.x = i + startindexes[seg] + 1;
344                                                                        o.y = rsegments[seg][i];
345                                                                }else{
346                                                                        o.x = rsegments[seg][i].x;
347                                                                        o.y = rsegments[seg][i].y;
348                                                                }
349                                                                this._connectEvents(o);
350                                                                eventSeries[i + startindexes[seg]] = o;
351                                                        }, this);
352                                                }else{
353                                                        delete this._eventSeries[run.name];
354                                                }
355                                        }
356                }
357                                run.dirty = false;
358                        }
359                        if(this.animate){
360                                // grow from the bottom
361                                var plotGroup = this.group;
362                                fx.animateTransform(lang.delegate({
363                                        shape: plotGroup,
364                                        duration: DEFAULT_ANIMATION_LENGTH,
365                                        transform:[
366                                                {name:"translate", start: [0, dim.height - offsets.b], end: [0, 0]},
367                                                {name:"scale", start: [1, 0], end:[1, 1]},
368                                                {name:"original"}
369                                        ]
370                                }, this.animate)).play();
371                        }
372                        this.dirty = false;
373                        return this;    //      dojox.charting.plot2d.Default
374                }
375        });
376});
Note: See TracBrowser for help on using the repository browser.