Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dojox.charting.axis2d.Default"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dojox.charting.axis2d.Default"] = true;
3
dojo.provide("dojox.charting.axis2d.Default");
4
 
5
dojo.require("dojox.charting.scaler");
6
dojo.require("dojox.charting.axis2d.common");
7
dojo.require("dojox.charting.axis2d.Base");
8
 
9
dojo.require("dojo.colors");
10
dojo.require("dojox.gfx");
11
dojo.require("dojox.lang.functional");
12
dojo.require("dojox.lang.utils");
13
 
14
(function(){
15
	var dc = dojox.charting,
16
		df = dojox.lang.functional,
17
		du = dojox.lang.utils,
18
		g = dojox.gfx,
19
		labelGap = 4,				// in pixels
20
		labelFudgeFactor = 0.8;		// in percents (to convert font's heigth to label width)
21
 
22
	var eq = function(/* Number */ a, /* Number */ b){
23
		// summary: compare two FP numbers for equality
24
		return Math.abs(a - b) <= 1e-6 * (Math.abs(a) + Math.abs(b));	// Boolean
25
	};
26
 
27
	dojo.declare("dojox.charting.axis2d.Default", dojox.charting.axis2d.Base, {
28
		 defaultParams: {
29
			vertical:    false,		// true for vertical axis
30
			fixUpper:    "none",	// align the upper on ticks: "major", "minor", "micro", "none"
31
			fixLower:    "none",	// align the lower on ticks: "major", "minor", "micro", "none"
32
			natural:     false,		// all tick marks should be made on natural numbers
33
			leftBottom:  true,		// position of the axis, used with "vertical"
34
			includeZero: false,		// 0 should be included
35
			fixed:       true,		// all labels are fixed numbers
36
			majorLabels: true,		// draw major labels
37
			minorTicks:  true,		// draw minor ticks
38
			minorLabels: true,		// draw minor labels
39
			microTicks:  false,		// draw micro ticks
40
			htmlLabels:  true		// use HTML to draw labels
41
		},
42
		optionalParams: {
43
			"min":           0,		// minimal value on this axis
44
			"max":           1,		// maximal value on this axis
45
			"majorTickStep": 4,		// major tick step
46
			"minorTickStep": 2,		// minor tick step
47
			"microTickStep": 1,		// micro tick step
48
			"labels":        [],	// array of labels for major ticks
49
									// with corresponding numeric values
50
									// ordered by values
51
			// theme components
52
			"stroke":        {},	// stroke for an axis
53
			"majorTick":     {},	// stroke + length for a tick
54
			"minorTick":     {},	// stroke + length for a tick
55
			"font":          "",	// font for labels
56
			"fontColor":     ""		// color for labels as a string
57
		},
58
 
59
		constructor: function(chart, kwArgs){
60
			this.opt = dojo.clone(this.defaultParams);
61
			du.updateWithObject(this.opt, kwArgs);
62
			du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
63
		},
64
		dependOnData: function(){
65
			return !("min" in this.opt) || !("max" in this.opt);
66
		},
67
		clear: function(){
68
			delete this.scaler;
69
			this.dirty = true;
70
			return this;
71
		},
72
		initialized: function(){
73
			return "scaler" in this;
74
		},
75
		calculate: function(min, max, span, labels){
76
			if(this.initialized()){ return this; }
77
			this.labels = "labels" in this.opt ? this.opt.labels : labels;
78
			if("min" in this.opt){ min = this.opt.min; }
79
			if("max" in this.opt){ max = this.opt.max; }
80
			if(this.opt.includeZero){
81
				if(min > 0){ min = 0; }
82
				if(max < 0){ max = 0; }
83
			}
84
			var minMinorStep = 0, ta = this.chart.theme.axis,
85
				taFont = "font" in this.opt ? this.opt.font : ta.font,
86
				size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0;
87
			if(this.vertical){
88
				if(size){
89
					minMinorStep = size + labelGap;
90
				}
91
			}else{
92
				if(size){
93
					var labelLength = Math.ceil(Math.log(Math.max(Math.abs(min), Math.abs(max))) / Math.LN10);
94
					if(min < 0 || max < 0){ ++labelLength; }
95
					var precision = Math.floor(Math.log(max - min) / Math.LN10);
96
					if(precision > 0){ labelLength += precision; }
97
					if(this.labels){
98
						labelLength = df.foldl(df.map(this.labels, "x.text.length"), "Math.max(a, b)", labelLength);
99
					}
100
					minMinorStep = Math.floor(size * labelLength * labelFudgeFactor) + labelGap;
101
				}
102
			}
103
			var kwArgs = {
104
				fixUpper: this.opt.fixUpper,
105
				fixLower: this.opt.fixLower,
106
				natural:  this.opt.natural
107
			};
108
			if("majorTickStep" in this.opt){ kwArgs.majorTick = this.opt.majorTickStep; }
109
			if("minorTickStep" in this.opt){ kwArgs.minorTick = this.opt.minorTickStep; }
110
			if("microTickStep" in this.opt){ kwArgs.microTick = this.opt.microTickStep; }
111
			this.scaler = dojox.charting.scaler(min, max, span, kwArgs);
112
			this.scaler.minMinorStep = minMinorStep;
113
			return this;
114
		},
115
		getScaler: function(){
116
			return this.scaler;
117
		},
118
		getOffsets: function(){
119
			var offsets = {l: 0, r: 0, t: 0, b: 0};
120
			var offset = 0, ta = this.chart.theme.axis,
121
				taFont = "font" in this.opt ? this.opt.font : ta.font,
122
				taMajorTick = "majorTick" in this.opt ? this.opt.majorTick : ta.majorTick,
123
				taMinorTick = "minorTick" in this.opt ? this.opt.minorTick : ta.minorTick,
124
				size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0;
125
			if(this.vertical){
126
				if(size){
127
					var s = this.scaler,
128
						a = this._getLabel(s.major.start, s.major.prec).length,
129
						b = this._getLabel(s.major.start + s.major.count * s.major.tick, s.major.prec).length,
130
						c = this._getLabel(s.minor.start, s.minor.prec).length,
131
						d = this._getLabel(s.minor.start + s.minor.count * s.minor.tick, s.minor.prec).length,
132
						labelLength = Math.max(a, b, c, d);
133
					if(this.labels){
134
						labelLength = df.foldl(df.map(this.labels, "x.text.length"), "Math.max(a, b)", labelLength);
135
					}
136
					offset = Math.floor(size * labelLength * labelFudgeFactor) + labelGap;
137
				}
138
				offset += labelGap + Math.max(taMajorTick.length, taMinorTick.length);
139
				offsets[this.opt.leftBottom ? "l" : "r"] = offset;
140
				offsets.t = offsets.b = size / 2;
141
			}else{
142
				if(size){
143
					offset = size + labelGap;
144
				}
145
				offset += labelGap + Math.max(taMajorTick.length, taMinorTick.length);
146
				offsets[this.opt.leftBottom ? "b" : "t"] = offset;
147
				if(size){
148
					var s = this.scaler,
149
						a = this._getLabel(s.major.start, s.major.prec).length,
150
						b = this._getLabel(s.major.start + s.major.count * s.major.tick, s.major.prec).length,
151
						c = this._getLabel(s.minor.start, s.minor.prec).length,
152
						d = this._getLabel(s.minor.start + s.minor.count * s.minor.tick, s.minor.prec).length,
153
						labelLength = Math.max(a, b, c, d);
154
					if(this.labels){
155
						labelLength = df.foldl(df.map(this.labels, "x.text.length"), "Math.max(a, b)", labelLength);
156
					}
157
					offsets.l = offsets.r = Math.floor(size * labelLength * labelFudgeFactor) / 2;
158
				}
159
			}
160
			return offsets;
161
		},
162
		render: function(dim, offsets){
163
			if(!this.dirty){ return this; }
164
			// prepare variable
165
			var start, stop, axisVector, tickVector, labelOffset, labelAlign,
166
				ta = this.chart.theme.axis,
167
				taStroke = "stroke" in this.opt ? this.opt.stroke : ta.stroke,
168
				taMajorTick = "majorTick" in this.opt ? this.opt.majorTick : ta.majorTick,
169
				taMinorTick = "minorTick" in this.opt ? this.opt.minorTick : ta.minorTick,
170
				taFont = "font" in this.opt ? this.opt.font : ta.font,
171
				taFontColor = "fontColor" in this.opt ? this.opt.fontColor : ta.fontColor,
172
				tickSize = Math.max(taMajorTick.length, taMinorTick.length),
173
				size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0;
174
			if(this.vertical){
175
				start = {y: dim.height - offsets.b};
176
				stop  = {y: offsets.t};
177
				axisVector = {x: 0, y: -1};
178
				if(this.opt.leftBottom){
179
					start.x = stop.x = offsets.l;
180
					tickVector = {x: -1, y: 0};
181
					labelAlign = "end";
182
				}else{
183
					start.x = stop.x = dim.width - offsets.r;
184
					tickVector = {x: 1, y: 0};
185
					labelAlign = "start";
186
				}
187
				labelOffset = {x: tickVector.x * (tickSize + labelGap), y: size * 0.4};
188
			}else{
189
				start = {x: offsets.l};
190
				stop  = {x: dim.width - offsets.r};
191
				axisVector = {x: 1, y: 0};
192
				labelAlign = "middle";
193
				if(this.opt.leftBottom){
194
					start.y = stop.y = dim.height - offsets.b;
195
					tickVector = {x: 0, y: 1};
196
					labelOffset = {y: tickSize + labelGap + size};
197
				}else{
198
					start.y = stop.y = offsets.t;
199
					tickVector = {x: 0, y: -1};
200
					labelOffset = {y: -tickSize - labelGap};
201
				}
202
				labelOffset.x = 0;
203
			}
204
 
205
			// render shapes
206
			this.cleanGroup();
207
			var s = this.group, c = this.scaler, step, next,
208
				nextMajor = c.major.start, nextMinor = c.minor.start, nextMicro = c.micro.start;
209
			s.createLine({x1: start.x, y1: start.y, x2: stop.x, y2: stop.y}).setStroke(taStroke);
210
			if(this.opt.microTicks && c.micro.tick){
211
				step = c.micro.tick, next = nextMicro;
212
			}else if(this.opt.minorTicks && c.minor.tick){
213
				step = c.minor.tick, next = nextMinor;
214
			}else if(c.major.tick){
215
				step = c.major.tick, next = nextMajor;
216
			}else{
217
				// don't draw anything
218
				return this;
219
			}
220
			while(next <= c.bounds.upper + 1/c.scale){
221
				var offset = (next - c.bounds.lower) * c.scale,
222
					x = start.x + axisVector.x * offset,
223
					y = start.y + axisVector.y * offset;
224
				if(Math.abs(nextMajor - next) < step / 2){
225
					// major tick
226
					s.createLine({
227
						x1: x, y1: y,
228
						x2: x + tickVector.x * taMajorTick.length,
229
						y2: y + tickVector.y * taMajorTick.length
230
					}).setStroke(taMajorTick);
231
					if(this.opt.majorLabels){
232
						var elem = dc.axis2d.common.createText[this.opt.htmlLabels ? "html" : "gfx"]
233
										(this.chart, s, x + labelOffset.x, y + labelOffset.y, labelAlign,
234
											this._getLabel(nextMajor, c.major.prec), taFont, taFontColor);
235
						if(this.opt.htmlLabels){ this.htmlElements.push(elem); }
236
					}
237
					nextMajor += c.major.tick;
238
					nextMinor += c.minor.tick;
239
					nextMicro += c.micro.tick;
240
				}else if(Math.abs(nextMinor - next) < step / 2){
241
					// minor tick
242
					if(this.opt.minorTicks){
243
						s.createLine({
244
							x1: x, y1: y,
245
							x2: x + tickVector.x * taMinorTick.length,
246
							y2: y + tickVector.y * taMinorTick.length
247
						}).setStroke(taMinorTick);
248
						if(this.opt.minorLabels && (c.minMinorStep <= c.minor.tick * c.scale)){
249
							var elem = dc.axis2d.common.createText[this.opt.htmlLabels ? "html" : "gfx"]
250
											(this.chart, s, x + labelOffset.x, y + labelOffset.y, labelAlign,
251
												this._getLabel(nextMinor, c.minor.prec), taFont, taFontColor);
252
							if(this.opt.htmlLabels){ this.htmlElements.push(elem); }
253
						}
254
					}
255
					nextMinor += c.minor.tick;
256
					nextMicro += c.micro.tick;
257
				}else{
258
					// micro tick
259
					if(this.opt.microTicks){
260
						s.createLine({
261
							x1: x, y1: y,
262
							// use minor ticks for now
263
							x2: x + tickVector.x * taMinorTick.length,
264
							y2: y + tickVector.y * taMinorTick.length
265
						}).setStroke(taMinorTick);
266
					}
267
					nextMicro += c.micro.tick;
268
				}
269
				next += step;
270
			}
271
			this.dirty = false;
272
			return this;
273
		},
274
 
275
		// utilities
276
		_getLabel: function(number, precision){
277
			if(this.opt.labels){
278
				// classic binary search
279
				var l = this.opt.labels, lo = 0, hi = l.length;
280
				while(lo < hi){
281
					var mid = Math.floor((lo + hi) / 2), val = l[mid].value;
282
					if(val < number){
283
						lo = mid + 1;
284
					}else{
285
						hi = mid;
286
					}
287
				}
288
				// lets take into account FP errors
289
				if(lo < l.length && eq(l[lo].value, number)){
290
					return l[lo].text;
291
				}
292
				--lo;
293
				if(lo < l.length && eq(l[lo].value, number)){
294
					return l[lo].text;
295
				}
296
				lo += 2;
297
				if(lo < l.length && eq(l[lo].value, number)){
298
					return l[lo].text;
299
				}
300
				// otherwise we will produce a number
301
			}
302
			return this.opt.fixed ? number.toFixed(precision < 0 ? -precision : 0) : number.toString();
303
		}
304
	});
305
})();
306
 
307
}