Also apply the __toString fix to UserInfo
[cacert-mgr.git] / external / ZendFramework-1.9.5 / externals / dojo / demos / fonts / src / pie.js
1 dojo.provide("demos.fonts.src.pie");
2
3 dojo.require("dojox.gfx");
4 dojo.require("dojox.gfx.VectorText");
5 dojo.require("dojox.gfx.utils");
6
7 (function(){
8 demos.fonts.src.pie = function(node, font, data, args){
9 args = args || {};
10 this.font = font;
11 this.data = data || [];
12 this.stroke = { color: args.stroke || "white", width: 1 };
13 this.fill = args.fill || "#40b337";
14 this.radius = args.radius || 112;
15 this.center = args.center || this.radius + (this.stroke.width*2);
16 this.width = args.width || this.center*2;
17 this.height = args.height || this.center*2;
18 this.domNode = node || null;
19 this.rotation = args.rotation || 0;
20 this.mainFill = args.main || "#364c42";
21 this.surface = null;
22 this.otherData = [];
23 };
24
25 dojo.extend(demos.fonts.src.pie, {
26 findScale: function(txt, w){
27 // we do this manually here because there's some issues with font fitting in the font code.
28 // so it's a hack for now.
29 var g = dojo.map(this.font._normalize(txt).split(""), function(chr){
30 return this.font.glyphs[chr] || { path:"", xAdvance: this.font.advance.missing.x };
31 }, this);
32
33 var cw = 0;
34 for(var i=0; i<g.length; i++){
35 var tw = g[i].xAdvance;
36 if(i+1<g.length && g[i].kern && g[i+1] && g[i+1].code && g[i].kern[g[i+1].code]){
37 tw += g[i].kern[g[i+1].code].x;
38 }
39 cw += tw;
40 }
41 return this.font._round(w/cw);
42 },
43 draw: function(d){
44 var m=dojox.gfx.matrix, rad=(2*Math.PI)/360;
45 var r=this.radius, c=this.center, data=(this.data=d||this.data);
46
47 if(!this.surface && this.domNode){
48 this.surface = dojox.gfx.createSurface(this.domNode, this.width, this.height);
49 }
50 this.surface.clear();
51
52 // prepare our data.
53 var sum=0, idx=-1, max=0, valueLimit=5, other, otherSum, pct=0;
54 dojo.forEach(data, function(item){ sum += item.value; });
55 dojo.forEach(data, function(item, i){
56 item.pct = Math.round(item.value * (100/sum));
57 pct += item.pct;
58 if(item.pct > max){
59 max = item.pct;
60 idx = i;
61 }
62 if(item.pct < valueLimit){
63 if(!other){ other = { label: "Other", pct: 0, value: 0, isOther: true }; }
64 other.pct += item.pct;
65 other.value += item.value;
66 this.otherData.push(item);
67 }
68 }, this);
69 if(pct<100){ data[idx].pct += 100 - pct; }
70 if(other){
71 data.push(other);
72 }
73
74 // create the main group.
75 var g = this.surface.createGroup(), mm = m.rotategAt(this.rotation, c, c);
76
77 // rotate the whole chart
78 g.setTransform(mm);
79
80 // the background circle.
81 g.createCircle({ r: r, cx: c, cy: c })
82 .setStroke(this.stroke)
83 .setFill(this.mainFill);
84
85 // figure out the start and end angles for the arc overlay
86 var startAngle = 0,
87 endAngle = (360*(100-data[idx].pct))/100,
88 offset = (360-endAngle)/2;
89
90 // now that we know where the start angle is really supposed to be, recalculate start and end.
91 startAngle = offset, endAngle = (startAngle+(360*(100-data[idx].pct))/100)%360;
92
93 // do the biggest slice
94 var info = g.createGroup(),
95 txtArgs = { text: data[idx].label.toUpperCase(), x:0, y:0, width:r/1.65, height:r/1.65, align:"start", fitting:dojox.gfx.vectorFontFitting.NONE },
96 fontArgs = { size: "10px" };
97 var txt = this.font.draw(info, txtArgs, fontArgs, this.stroke.color),
98 txtscale = this.findScale(data[idx].label.toUpperCase(), r/1.65),
99 txty = Math.round(this.font.viewbox.height*txtscale)/2;
100 if(this.rotation>90 && this.rotation<270){
101 txt.setTransform(new dojox.gfx.Matrix2D([
102 m.translate((r*2)-10, c+txty),
103 m.scale(txtscale),
104 m.rotateg(180)
105 ]));
106 } else {
107 txt.setTransform(new dojox.gfx.Matrix2D([
108 m.translate((r*2)-6-(r/1.65), c-txty),
109 m.scale(txtscale)
110 ]));
111 }
112
113 var pct = this.font.draw(
114 info,
115 { text: (data[idx].pct).toString(), width: 24, height: 24, align:"start", fitting:dojox.gfx.vectorFontFitting.FLOW, x:0, y:0 },
116 fontArgs,
117 this.stroke.color
118 );
119 if(this.rotation>90 && this.rotation<270){
120 pct.setTransform(new dojox.gfx.Matrix2D([
121 m.translate(r+18, c+5),
122 pct.getTransform(),
123 m.rotateg(180)
124 ]));
125 } else {
126 pct.setTransform(new dojox.gfx.Matrix2D([
127 m.translate(r+12, c-5),
128 pct.getTransform()
129 ]));
130 }
131
132 // draw the background for the rest of the data
133 var main = g.createGroup(), st=Math.min(startAngle, endAngle), ed=Math.max(startAngle, endAngle);
134
135 var arc = main.createPath({})
136 .moveTo(c, c)
137 .lineTo(c+r*Math.cos(st*rad), c+r*Math.sin(st*rad))
138 .arcTo(r, r, 0, (Math.max(startAngle, endAngle)-Math.min(startAngle, endAngle)>180), true, { x:c+r*Math.cos(ed*rad), y:c+r*Math.sin(ed*rad) })
139 .lineTo(c, c)
140 .closePath()
141 .setStroke(this.stroke)
142 .setFill(this.fill);
143
144 // create the rest of the pie slice data
145 var lastAngle=startAngle;
146 for(var i=idx+1; (i%data.length)!=idx; i++){
147 var d=data[i%data.length], v=d.pct, a=lastAngle;
148 if(d.pct<valueLimit && !d.isOther){ continue; }
149
150 lastAngle += (d.pct*360)/100;
151 if(i%data.length!=idx-1){
152 main.createLine({ x1:c, y1: c, x2: c+r-8, y2: c})
153 .setStroke(this.stroke)
154 .setTransform(m.rotategAt(lastAngle, c, c));
155 }
156
157 // lets calculate some dimensions here for font fitting.
158 var _0 = (a+1)*rad;
159 var _1 = (lastAngle-1)*rad;
160 var _center = lastAngle-((lastAngle-a)/2);
161 var _2 = _center*rad;
162
163 // if this is the "other", define our anchor points.
164 if(d.isOther){
165 // we add the rotation because this is a virtual point, not actually plotted.
166 this.otherPoint = {
167 x: Math.round(c+(38*Math.cos(_2+(this.rotation*rad)))),
168 y: Math.round(c+(38*Math.sin(_2+(this.rotation*rad))))
169 };
170
171 // we already know where the center is, these would be the end points of the Other arc.
172 this.otherEnds = {
173 small: { x: c+r*Math.cos(_0), y: c+r*Math.sin(_0) },
174 large: { x: c+r*Math.cos(_1), y: c+r*Math.sin(_1) }
175 };
176
177 // determine the direction.
178 var quadrant = lastAngle + this.rotation;
179 if(quadrant <= 90){ this.otherDirection="SE"; }
180 else if(quadrant > 90 && quadrant <= 180){ this.otherDirection="SW"; }
181 else if(quadrant > 180 && quadrant <= 270){ this.otherDirection="NW"; }
182 else { this.otherDirection="NE"; }
183 }
184
185 var spoke = {
186 x1: c+((r*0.36)*Math.cos(_2)), y1: c+((r*0.36)*Math.sin(_2)),
187 x2: c+((r-16)*Math.cos(_2)), y2: c+((r-16)*Math.sin(_2))
188 };
189 spoke.dx = spoke.x2 - spoke.x1, spoke.dy = spoke.y2 - spoke.y1;
190
191 var tiny={
192 x1: c+(32*Math.cos(_0)), x2: c+(32*Math.cos(_1)),
193 y1: c+(32*Math.sin(_0)), y2: c+(32*Math.sin(_1))
194 };
195 tiny.dx = tiny.x2 - tiny.x1, tiny.dy = tiny.y2 - tiny.y1;
196
197 var small={
198 x1: c+((r*0.4)*Math.cos(_0)), x2: c+((r*0.4)*Math.cos(_1)),
199 y1: c+((r*0.4)*Math.sin(_0)), y2: c+((r*0.4)*Math.sin(_1))
200 };
201 small.dx = small.x2 - small.x1, small.dy = small.y2 - small.y1;
202
203 // whats the height limit? the inner distance.
204 var maxw = Math.sqrt(spoke.dx*spoke.dx + spoke.dy*spoke.dy);
205 var maxh = Math.sqrt(small.dx*small.dx + small.dy*small.dy);
206 var tinyh = Math.sqrt(tiny.dx*tiny.dx + tiny.dy*tiny.dy);
207
208 // the value
209 var label = main.createGroup(),
210 txtArgs = { text: dojo.trim(d.label.toUpperCase()), x:0, y:0, width:r, height:r, align:"start", fitting:dojox.gfx.vectorFontFitting.NONE },
211 fontArgs = { size: "8px" };
212 label.setTransform(m.rotategAt(lastAngle-((lastAngle-a)/2), c, c));
213
214 var pct = this.font.draw(
215 label,
216 { text: (d.pct).toString(), width: 12, height: 12, align:"start", fitting:dojox.gfx.vectorFontFitting.FLOW, x:0, y:0 },
217 fontArgs,
218 this.stroke.color
219 );
220
221 // figure out if we need to scale it down.
222 var pctscale=0;
223 if(tinyh < 8){
224 // 14 being the pixel scale we rendered the font at.
225 pctscale = tinyh/this.font.viewbox.height;
226 }
227 if(_center>=90-this.rotation && _center<=270-this.rotation){
228 mtrx=new dojox.gfx.Matrix2D([
229 m.translate(r+24, c+(pctscale?Math.round(this.font.viewbox.height*pctscale)/2:3)),
230 pctscale?m.scale(pctscale):pct.getTransform(),
231 m.rotateg(180)
232 ]);
233 } else {
234 mtrx=new dojox.gfx.Matrix2D([
235 m.translate(r+20, c-(pctscale?Math.round(this.font.viewbox.height*pctscale)/2:3)),
236 pctscale?m.scale(pctscale):pct.getTransform()
237 ]);
238 }
239 pct.setTransform(mtrx);
240
241 var txt = this.font.draw(label, txtArgs, fontArgs, this.stroke.color),
242 txtscale = this.findScale(d.label.toUpperCase(), r/1.65),
243 txty = Math.round(this.font.viewbox.height*txtscale)/2,
244 txtw = this.font.getWidth(d.label.toUpperCase(), txtscale);
245 if(Math.round(this.font.viewbox.height*txtscale) > maxh){
246 // recalc the scale based on height
247 txtscale = maxh/this.font.viewbox.height;
248 txty = Math.round(this.font.viewbox.height*txtscale)/2;
249 txtw = this.font.getWidth(d.label.toUpperCase(), txtscale);
250 }
251
252 if(_center>=90-this.rotation && _center<=270-this.rotation){
253 var mtrx=new dojox.gfx.Matrix2D([
254 m.translate(r*2-10, c+txty),
255 m.scale(txtscale),
256 m.rotateg(180)
257 ]);
258 } else {
259 var mtrx=new dojox.gfx.Matrix2D([
260 m.translate((r*2)-txtw-6, c-txty),
261 m.scale(txtscale)
262 ]);
263 }
264 txt.setTransform(mtrx);
265 }
266 return g; // dojox.gfx.Group
267 }
268 });
269 })();