1 | define(["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojo/_base/array", |
---|
2 | "../Element", "./common", "dojox/lang/utils", "dojox/gfx/fx"], |
---|
3 | function(lang, declare, hub, arr, Element, dc, du, fx){ |
---|
4 | |
---|
5 | /*===== |
---|
6 | dojo.declare("dojox.charting.plot2d.__GridCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, { |
---|
7 | // summary: |
---|
8 | // A special keyword arguments object that is specific to a grid "plot". |
---|
9 | |
---|
10 | // hMajorLines: Boolean? |
---|
11 | // Whether to show lines at the major ticks along the horizontal axis. Default is true. |
---|
12 | hMajorLines: true, |
---|
13 | |
---|
14 | // hMinorLines: Boolean? |
---|
15 | // Whether to show lines at the minor ticks along the horizontal axis. Default is false. |
---|
16 | hMinorLines: false, |
---|
17 | |
---|
18 | // vMajorLines: Boolean? |
---|
19 | // Whether to show lines at the major ticks along the vertical axis. Default is true. |
---|
20 | vMajorLines: true, |
---|
21 | |
---|
22 | // vMinorLines: Boolean? |
---|
23 | // Whether to show lines at the major ticks along the vertical axis. Default is false. |
---|
24 | vMinorLines: false, |
---|
25 | |
---|
26 | // hStripes: String? |
---|
27 | // Whether or not to show stripes (alternating fills) along the horizontal axis. Default is "none". |
---|
28 | hStripes: "none", |
---|
29 | |
---|
30 | // vStripes: String? |
---|
31 | // Whether or not to show stripes (alternating fills) along the vertical axis. Default is "none". |
---|
32 | vStripes: "none", |
---|
33 | |
---|
34 | // enableCache: Boolean? |
---|
35 | // Whether the grid lines are cached from one rendering to another. This improves the rendering performance of |
---|
36 | // successive rendering but penalize the first rendering. Default false. |
---|
37 | enableCache: false |
---|
38 | }); |
---|
39 | var Element = dojox.charting.plot2d.Element; |
---|
40 | =====*/ |
---|
41 | |
---|
42 | return declare("dojox.charting.plot2d.Grid", Element, { |
---|
43 | // summary: |
---|
44 | // A "faux" plot that can be placed behind other plots to represent |
---|
45 | // a grid against which other plots can be easily measured. |
---|
46 | defaultParams: { |
---|
47 | hAxis: "x", // use a horizontal axis named "x" |
---|
48 | vAxis: "y", // use a vertical axis named "y" |
---|
49 | hMajorLines: true, // draw horizontal major lines |
---|
50 | hMinorLines: false, // draw horizontal minor lines |
---|
51 | vMajorLines: true, // draw vertical major lines |
---|
52 | vMinorLines: false, // draw vertical minor lines |
---|
53 | hStripes: "none", // TBD |
---|
54 | vStripes: "none", // TBD |
---|
55 | animate: null, // animate bars into place |
---|
56 | enableCache: false |
---|
57 | }, |
---|
58 | optionalParams: {}, // no optional parameters |
---|
59 | |
---|
60 | constructor: function(chart, kwArgs){ |
---|
61 | // summary: |
---|
62 | // Create the faux Grid plot. |
---|
63 | // chart: dojox.charting.Chart |
---|
64 | // The chart this plot belongs to. |
---|
65 | // kwArgs: dojox.charting.plot2d.__GridCtorArgs? |
---|
66 | // An optional keyword arguments object to help define the parameters of the underlying grid. |
---|
67 | this.opt = lang.clone(this.defaultParams); |
---|
68 | du.updateWithObject(this.opt, kwArgs); |
---|
69 | this.hAxis = this.opt.hAxis; |
---|
70 | this.vAxis = this.opt.vAxis; |
---|
71 | this.dirty = true; |
---|
72 | this.animate = this.opt.animate; |
---|
73 | this.zoom = null, |
---|
74 | this.zoomQueue = []; // zooming action task queue |
---|
75 | this.lastWindow = {vscale: 1, hscale: 1, xoffset: 0, yoffset: 0}; |
---|
76 | if(this.opt.enableCache){ |
---|
77 | this._lineFreePool = []; |
---|
78 | this._lineUsePool = []; |
---|
79 | } |
---|
80 | }, |
---|
81 | clear: function(){ |
---|
82 | // summary: |
---|
83 | // Clear out any parameters set on this plot. |
---|
84 | // returns: dojox.charting.plot2d.Grid |
---|
85 | // The reference to this plot for functional chaining. |
---|
86 | this._hAxis = null; |
---|
87 | this._vAxis = null; |
---|
88 | this.dirty = true; |
---|
89 | return this; // dojox.charting.plot2d.Grid |
---|
90 | }, |
---|
91 | setAxis: function(axis){ |
---|
92 | // summary: |
---|
93 | // Set an axis for this plot. |
---|
94 | // returns: dojox.charting.plot2d.Grid |
---|
95 | // The reference to this plot for functional chaining. |
---|
96 | if(axis){ |
---|
97 | this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; |
---|
98 | } |
---|
99 | return this; // dojox.charting.plot2d.Grid |
---|
100 | }, |
---|
101 | addSeries: function(run){ |
---|
102 | // summary: |
---|
103 | // Ignored but included as a dummy method. |
---|
104 | // returns: dojox.charting.plot2d.Grid |
---|
105 | // The reference to this plot for functional chaining. |
---|
106 | return this; // dojox.charting.plot2d.Grid |
---|
107 | }, |
---|
108 | getSeriesStats: function(){ |
---|
109 | // summary: |
---|
110 | // Returns default stats (irrelevant for this type of plot). |
---|
111 | // returns: Object |
---|
112 | // {hmin, hmax, vmin, vmax} min/max in both directions. |
---|
113 | return lang.delegate(dc.defaultStats); |
---|
114 | }, |
---|
115 | initializeScalers: function(){ |
---|
116 | // summary: |
---|
117 | // Does nothing (irrelevant for this type of plot). |
---|
118 | return this; |
---|
119 | }, |
---|
120 | isDirty: function(){ |
---|
121 | // summary: |
---|
122 | // Return whether or not this plot needs to be redrawn. |
---|
123 | // returns: Boolean |
---|
124 | // If this plot needs to be rendered, this will return true. |
---|
125 | return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; // Boolean |
---|
126 | }, |
---|
127 | performZoom: function(dim, offsets){ |
---|
128 | // summary: |
---|
129 | // Create/alter any zooming windows on this plot. |
---|
130 | // dim: Object |
---|
131 | // An object of the form { width, height }. |
---|
132 | // offsets: Object |
---|
133 | // An object of the form { l, r, t, b }. |
---|
134 | // returns: dojox.charting.plot2d.Grid |
---|
135 | // A reference to this plot for functional chaining. |
---|
136 | |
---|
137 | // get current zooming various |
---|
138 | var vs = this._vAxis.scale || 1, |
---|
139 | hs = this._hAxis.scale || 1, |
---|
140 | vOffset = dim.height - offsets.b, |
---|
141 | hBounds = this._hAxis.getScaler().bounds, |
---|
142 | xOffset = (hBounds.from - hBounds.lower) * hBounds.scale, |
---|
143 | vBounds = this._vAxis.getScaler().bounds, |
---|
144 | yOffset = (vBounds.from - vBounds.lower) * vBounds.scale, |
---|
145 | // get incremental zooming various |
---|
146 | rVScale = vs / this.lastWindow.vscale, |
---|
147 | rHScale = hs / this.lastWindow.hscale, |
---|
148 | rXOffset = (this.lastWindow.xoffset - xOffset)/ |
---|
149 | ((this.lastWindow.hscale == 1)? hs : this.lastWindow.hscale), |
---|
150 | rYOffset = (yOffset - this.lastWindow.yoffset)/ |
---|
151 | ((this.lastWindow.vscale == 1)? vs : this.lastWindow.vscale), |
---|
152 | |
---|
153 | shape = this.group, |
---|
154 | anim = fx.animateTransform(lang.delegate({ |
---|
155 | shape: shape, |
---|
156 | duration: 1200, |
---|
157 | transform:[ |
---|
158 | {name:"translate", start:[0, 0], end: [offsets.l * (1 - rHScale), vOffset * (1 - rVScale)]}, |
---|
159 | {name:"scale", start:[1, 1], end: [rHScale, rVScale]}, |
---|
160 | {name:"original"}, |
---|
161 | {name:"translate", start: [0, 0], end: [rXOffset, rYOffset]} |
---|
162 | ]}, this.zoom)); |
---|
163 | |
---|
164 | lang.mixin(this.lastWindow, {vscale: vs, hscale: hs, xoffset: xOffset, yoffset: yOffset}); |
---|
165 | //add anim to zooming action queue, |
---|
166 | //in order to avoid several zooming action happened at the same time |
---|
167 | this.zoomQueue.push(anim); |
---|
168 | //perform each anim one by one in zoomQueue |
---|
169 | hub.connect(anim, "onEnd", this, function(){ |
---|
170 | this.zoom = null; |
---|
171 | this.zoomQueue.shift(); |
---|
172 | if(this.zoomQueue.length > 0){ |
---|
173 | this.zoomQueue[0].play(); |
---|
174 | } |
---|
175 | }); |
---|
176 | if(this.zoomQueue.length == 1){ |
---|
177 | this.zoomQueue[0].play(); |
---|
178 | } |
---|
179 | return this; // dojox.charting.plot2d.Grid |
---|
180 | }, |
---|
181 | getRequiredColors: function(){ |
---|
182 | // summary: |
---|
183 | // Ignored but included as a dummy method. |
---|
184 | // returns: Number |
---|
185 | // Returns 0, since there are no series associated with this plot type. |
---|
186 | return 0; // Number |
---|
187 | }, |
---|
188 | cleanGroup: function(){ |
---|
189 | this.inherited(arguments); |
---|
190 | if(this.opt.enableCache){ |
---|
191 | this._lineFreePool = this._lineFreePool.concat(this._lineUsePool); |
---|
192 | this._lineUsePool = []; |
---|
193 | } |
---|
194 | }, |
---|
195 | createLine: function(creator, params){ |
---|
196 | var line; |
---|
197 | if(this.opt.enableCache && this._lineFreePool.length > 0){ |
---|
198 | line = this._lineFreePool.pop(); |
---|
199 | line.setShape(params); |
---|
200 | // was cleared, add it back |
---|
201 | creator.add(line); |
---|
202 | }else{ |
---|
203 | line = creator.createLine(params); |
---|
204 | } |
---|
205 | if(this.opt.enableCache){ |
---|
206 | this._lineUsePool.push(line); |
---|
207 | } |
---|
208 | return line; |
---|
209 | }, |
---|
210 | render: function(dim, offsets){ |
---|
211 | // summary: |
---|
212 | // Render the plot on the chart. |
---|
213 | // dim: Object |
---|
214 | // An object of the form { width, height }. |
---|
215 | // offsets: Object |
---|
216 | // An object of the form { l, r, t, b }. |
---|
217 | // returns: dojox.charting.plot2d.Grid |
---|
218 | // A reference to this plot for functional chaining. |
---|
219 | if(this.zoom){ |
---|
220 | return this.performZoom(dim, offsets); |
---|
221 | } |
---|
222 | this.dirty = this.isDirty(); |
---|
223 | if(!this.dirty){ return this; } |
---|
224 | this.cleanGroup(); |
---|
225 | var s = this.group, ta = this.chart.theme.axis; |
---|
226 | // draw horizontal stripes and lines |
---|
227 | try{ |
---|
228 | var vScaler = this._vAxis.getScaler(), |
---|
229 | vt = vScaler.scaler.getTransformerFromModel(vScaler), |
---|
230 | ticks = this._vAxis.getTicks(); |
---|
231 | if(ticks != null){ |
---|
232 | if(this.opt.hMinorLines){ |
---|
233 | arr.forEach(ticks.minor, function(tick){ |
---|
234 | var y = dim.height - offsets.b - vt(tick.value); |
---|
235 | var hMinorLine = this.createLine(s, { |
---|
236 | x1: offsets.l, |
---|
237 | y1: y, |
---|
238 | x2: dim.width - offsets.r, |
---|
239 | y2: y |
---|
240 | }).setStroke(ta.minorTick); |
---|
241 | if(this.animate){ |
---|
242 | this._animateGrid(hMinorLine, "h", offsets.l, offsets.r + offsets.l - dim.width); |
---|
243 | } |
---|
244 | }, this); |
---|
245 | } |
---|
246 | if(this.opt.hMajorLines){ |
---|
247 | arr.forEach(ticks.major, function(tick){ |
---|
248 | var y = dim.height - offsets.b - vt(tick.value); |
---|
249 | var hMajorLine = this.createLine(s, { |
---|
250 | x1: offsets.l, |
---|
251 | y1: y, |
---|
252 | x2: dim.width - offsets.r, |
---|
253 | y2: y |
---|
254 | }).setStroke(ta.majorTick); |
---|
255 | if(this.animate){ |
---|
256 | this._animateGrid(hMajorLine, "h", offsets.l, offsets.r + offsets.l - dim.width); |
---|
257 | } |
---|
258 | }, this); |
---|
259 | } |
---|
260 | } |
---|
261 | }catch(e){ |
---|
262 | // squelch |
---|
263 | } |
---|
264 | // draw vertical stripes and lines |
---|
265 | try{ |
---|
266 | var hScaler = this._hAxis.getScaler(), |
---|
267 | ht = hScaler.scaler.getTransformerFromModel(hScaler), |
---|
268 | ticks = this._hAxis.getTicks(); |
---|
269 | if(this != null){ |
---|
270 | if(ticks && this.opt.vMinorLines){ |
---|
271 | arr.forEach(ticks.minor, function(tick){ |
---|
272 | var x = offsets.l + ht(tick.value); |
---|
273 | var vMinorLine = this.createLine(s, { |
---|
274 | x1: x, |
---|
275 | y1: offsets.t, |
---|
276 | x2: x, |
---|
277 | y2: dim.height - offsets.b |
---|
278 | }).setStroke(ta.minorTick); |
---|
279 | if(this.animate){ |
---|
280 | this._animateGrid(vMinorLine, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t); |
---|
281 | } |
---|
282 | }, this); |
---|
283 | } |
---|
284 | if(ticks && this.opt.vMajorLines){ |
---|
285 | arr.forEach(ticks.major, function(tick){ |
---|
286 | var x = offsets.l + ht(tick.value); |
---|
287 | var vMajorLine = this.createLine(s, { |
---|
288 | x1: x, |
---|
289 | y1: offsets.t, |
---|
290 | x2: x, |
---|
291 | y2: dim.height - offsets.b |
---|
292 | }).setStroke(ta.majorTick); |
---|
293 | if(this.animate){ |
---|
294 | this._animateGrid(vMajorLine, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t); |
---|
295 | } |
---|
296 | }, this); |
---|
297 | } |
---|
298 | } |
---|
299 | }catch(e){ |
---|
300 | // squelch |
---|
301 | } |
---|
302 | this.dirty = false; |
---|
303 | return this; // dojox.charting.plot2d.Grid |
---|
304 | }, |
---|
305 | _animateGrid: function(shape, type, offset, size){ |
---|
306 | var transStart = type == "h" ? [offset, 0] : [0, offset]; |
---|
307 | var scaleStart = type == "h" ? [1/size, 1] : [1, 1/size]; |
---|
308 | fx.animateTransform(lang.delegate({ |
---|
309 | shape: shape, |
---|
310 | duration: 1200, |
---|
311 | transform: [ |
---|
312 | {name: "translate", start: transStart, end: [0, 0]}, |
---|
313 | {name: "scale", start: scaleStart, end: [1, 1]}, |
---|
314 | {name: "original"} |
---|
315 | ] |
---|
316 | }, this.animate)).play(); |
---|
317 | } |
---|
318 | }); |
---|
319 | }); |
---|