source: code/Website/open-flash-chart/charts/Pie.as@ 7856

Last change on this file since 7856 was 7849, checked in by dennisw, 16 years ago
File size: 10.3 KB
Line 
1package charts {
2 import charts.series.pies.PieLabel;
3 import flash.external.ExternalInterface;
4 import string.Utils;
5 import charts.series.Element;
6 import charts.series.pies.PieSliceContainer;
7 import charts.series.pies.DefaultPieProperties;
8 import global.Global;
9
10 import flash.display.Sprite;
11
12 public class Pie extends Base
13 {
14
15 private var labels:Array;
16 private var links:Array;
17 private var colours:Array;
18 private var gradientFill:String = 'true'; //toggle gradients
19 private var border_width:Number = 1;
20 private var label_line:Number;
21 private var easing:Function;
22 public var style:Object;
23 public var total_value:Number = 0;
24
25 // new:
26 private var props:Properties;
27 //
28
29 public function Pie( json:Object )
30 {
31 this.labels = new Array();
32 this.links = new Array();
33 this.colours = new Array();
34
35 this.style = {
36 colours: ["#900000", "#009000"] // slices colours
37 }
38
39 object_helper.merge_2( json, this.style );
40
41 for each( var colour:String in this.style.colours )
42 this.colours.push( string.Utils.get_colour( colour ) );
43
44 //
45 //
46 //
47 this.props = new DefaultPieProperties(json);
48 //
49 //
50 //
51
52 this.label_line = 10;
53
54 this.values = json.values;
55 this.add_values();
56 }
57
58
59 //
60 // Pie chart make is quite different to a normal make
61 //
62 public override function add_values():void {
63// this.Elements= new Array();
64
65 //
66 // Warning: this is our global singleton
67 //
68 var g:Global = Global.getInstance();
69
70 var total:Number = 0;
71 var slice_start:Number = this.props.get('start-angle');
72 var i:Number;
73 var val:Object;
74
75 for each ( val in this.values ) {
76 if( val is Number )
77 total += val;
78 else
79 total += val.value;
80 }
81 this.total_value = total;
82
83 i = 0;
84 for each ( val in this.values ) {
85
86 var value:Number = val is Number ? val as Number : val.value;
87 var slice_angle:Number = value*360/total;
88
89 if( slice_angle >= 0 )
90 {
91
92 var t:String = this.props.get('tip').replace('#total#', NumberUtils.formatNumber( this.total_value ));
93 t = t.replace('#percent#', NumberUtils.formatNumber( value / this.total_value * 100 ) + '%');
94
95 this.addChild(
96 this.add_slice(
97 i,
98 slice_start,
99 slice_angle,
100 val, // <-- NOTE: val (object) NOT value (a number)
101 t,
102 this.colours[(i % this.colours.length)]
103 )
104 );
105
106 // TODO: fix this and remove
107 // tmp.make_tooltip( this.key );
108 }
109 i++;
110 slice_start += slice_angle;
111 }
112 }
113
114 private function add_slice( index:Number, start:Number, angle:Number, value:Object, tip:String, colour:String ): PieSliceContainer {
115
116
117 // Properties chain:
118 // pie-slice -> calculated-stuff -> pie
119 //
120 // calculated-stuff:
121 var calculated_stuff:Properties = new Properties(
122 {
123 colour: colour, // <-- from the colour cycle array
124 tip: tip, // <-- replaced the #total# & #percent# for this slice
125 start: start, // <-- calculated
126 angle: angle // <-- calculated
127 },
128 this.props );
129
130 var tmp:Object = {};
131 if ( value is Number )
132 tmp.value = value;
133 else
134 tmp = value;
135
136 var p:Properties = new Properties( tmp, calculated_stuff );
137
138 // no user defined label?
139 if ( !p.has('label') )
140 p.set('label', p.get('value').toString());
141
142 // tr.aces( 'value', p.get('value'), p.get('label'), p.get('colour') );
143 return new PieSliceContainer( index, p );
144 }
145
146
147 public override function closest( x:Number, y:Number ): Object {
148 // PIE charts don't do closest to mouse tooltips
149 return { Element:null, distance_x:0, distance_y:0 };
150 }
151
152
153 public override function resize( sc:ScreenCoordsBase ): void {
154 var radius:Number = this.style.radius;
155 if (isNaN(radius)){
156 radius = ( Math.min( sc.width, sc.height ) / 2.0 );
157 var offsets:Object = {top:0, right:0, bottom:0, left:0};
158 trace("sc.width, sc.height, radius", sc.width, sc.height, radius);
159
160 var i:Number;
161 var sliceContainer:PieSliceContainer;
162
163 // loop to gather and merge offsets
164 for ( i = 0; i < this.numChildren; i++ ) {
165 sliceContainer = this.getChildAt(i) as PieSliceContainer;
166 var pie_offsets:Object = sliceContainer.get_radius_offsets();
167 for (var key:Object in offsets) {
168 if ( pie_offsets[key] > offsets[key] ) {
169 offsets[key] = pie_offsets[key];
170 }
171 }
172 }
173 var vRadius:Number = radius;
174 // Calculate minimum radius assuming the contraint is vertical
175 // Shrink radius by the largest top/bottom offset
176 vRadius -= Math.max(offsets.top, offsets.bottom);
177 // check to see if the left/right labels will fit
178 if ((vRadius + offsets.left) > (sc.width / 2))
179 {
180 //radius -= radius + offsets.left - (sc.width / 2);
181 vRadius = (sc.width / 2) - offsets.left;
182 }
183 if ((vRadius + offsets.right) > (sc.width / 2))
184 {
185 //radius -= radius + offsets.right - (sc.width / 2);
186 vRadius = (sc.width / 2) - offsets.right;
187 }
188
189 // Make sure the radius is at least 10
190 radius = Math.max(vRadius, 10);
191 }
192
193 var rightTopTicAngle:Number = 720;
194 var rightTopTicIdx:Number = -1;
195 var rightBottomTicAngle:Number = -720;
196 var rightBottomTicIdx:Number = -1;
197
198 var leftTopTicAngle:Number = 720;
199 var leftTopTicIdx:Number = -1;
200 var leftBottomTicAngle:Number = -720;
201 var leftBottomTicIdx:Number = -1;
202
203 // loop and resize
204 for ( i = 0; i < this.numChildren; i++ )
205 {
206 sliceContainer = this.getChildAt(i) as PieSliceContainer;
207 sliceContainer.pie_resize(sc, radius);
208
209 // While we are looping through the children, we determine which
210 // labels are the starting points in each quadrant so that we
211 // move the labels around to prevent overlaps
212 var ticAngle:Number = sliceContainer.getTicAngle();
213 if (ticAngle >= 270)
214 {
215 // Right side - Top
216 if ((ticAngle < rightTopTicAngle) || (rightTopTicAngle <= 90))
217 {
218 rightTopTicAngle = ticAngle;
219 rightTopTicIdx = i;
220 }
221 // Just in case no tics in Right-Bottom
222 if ((rightBottomTicAngle < 0) ||
223 ((rightBottomTicAngle > 90) && (rightBottomTicAngle < ticAngle)))
224 {
225 rightBottomTicAngle = ticAngle;
226 rightBottomTicIdx = i;
227 }
228 }
229 else if (ticAngle <= 90)
230 {
231 // Right side - Bottom
232 if ((ticAngle > rightBottomTicAngle) || (rightBottomTicAngle > 90))
233 {
234 rightBottomTicAngle = ticAngle;
235 rightBottomTicIdx = i;
236 }
237 // Just in case no tics in Right-Top
238 if ((rightTopTicAngle > 360) ||
239 ((rightTopTicAngle <= 90) && (ticAngle < rightBottomTicAngle)))
240 {
241 rightTopTicAngle = ticAngle;
242 rightTopTicIdx = i;
243 }
244 }
245 else if (ticAngle <= 180)
246 {
247 // Left side - Bottom
248 if ((leftBottomTicAngle < 0) || (ticAngle < leftBottomTicAngle))
249 {
250 leftBottomTicAngle = ticAngle;
251 leftBottomTicIdx = i;
252 }
253 // Just in case no tics in Left-Top
254 if ((leftTopTicAngle > 360) || (leftTopTicAngle < ticAngle))
255 {
256 leftTopTicAngle = ticAngle;
257 leftTopTicIdx = i;
258 }
259 }
260 else
261 {
262 // Left side - Top
263 if ((leftTopTicAngle > 360) || (ticAngle > leftTopTicAngle))
264 {
265 leftTopTicAngle = ticAngle;
266 leftTopTicIdx = i;
267 }
268 // Just in case no tics in Left-Bottom
269 if ((leftBottomTicAngle < 0) || (leftBottomTicAngle > ticAngle))
270 {
271 leftBottomTicAngle = ticAngle;
272 leftBottomTicIdx = i;
273 }
274 }
275 }
276
277 // Make a clockwise pass on right side of pie trying to move
278 // the labels so that they do not overlap
279 var childIdx:Number = rightTopTicIdx;
280 var yVal:Number = sc.top;
281 var bDone:Boolean = false;
282 while ((childIdx >= 0) && (!bDone))
283 {
284 sliceContainer = this.getChildAt(childIdx) as PieSliceContainer;
285 ticAngle = sliceContainer.getTicAngle();
286 if ((ticAngle >= 270) || (ticAngle <= 90))
287 {
288 yVal = sliceContainer.moveLabelDown(sc, yVal);
289
290 childIdx++;
291 if (childIdx >= this.numChildren) childIdx = 0;
292
293 bDone = (childIdx == rightTopTicIdx);
294 }
295 else
296 {
297 bDone = true;
298 }
299 }
300
301 // Make a counter-clockwise pass on right side of pie trying to move
302 // the labels so that they do not overlap
303 childIdx = rightBottomTicIdx;
304 yVal = sc.bottom;
305 bDone = false;
306 while ((childIdx >= 0) && (!bDone))
307 {
308 sliceContainer = this.getChildAt(childIdx) as PieSliceContainer;
309 ticAngle = sliceContainer.getTicAngle();
310 if ((ticAngle >= 270) || (ticAngle <= 90))
311 {
312 yVal = sliceContainer.moveLabelUp(sc, yVal);
313
314 childIdx--;
315 if (childIdx < 0) childIdx = this.numChildren - 1;
316
317 bDone = (childIdx == rightBottomTicIdx);
318 }
319 else
320 {
321 bDone = true;
322 }
323 }
324
325 // Make a clockwise pass on left side of pie trying to move
326 // the labels so that they do not overlap
327 childIdx = leftBottomTicIdx;
328 yVal = sc.bottom;
329 bDone = false;
330 while ((childIdx >= 0) && (!bDone))
331 {
332 sliceContainer = this.getChildAt(childIdx) as PieSliceContainer;
333 ticAngle = sliceContainer.getTicAngle();
334 if ((ticAngle > 90) && (ticAngle < 270))
335 {
336 yVal = sliceContainer.moveLabelUp(sc, yVal);
337
338 childIdx++;
339 if (childIdx >= this.numChildren) childIdx = 0;
340
341 bDone = (childIdx == leftBottomTicIdx);
342 }
343 else
344 {
345 bDone = true;
346 }
347 }
348
349 // Make a counter-clockwise pass on left side of pie trying to move
350 // the labels so that they do not overlap
351 childIdx = leftTopTicIdx;
352 yVal = sc.top;
353 bDone = false;
354 while ((childIdx >= 0) && (!bDone))
355 {
356 sliceContainer = this.getChildAt(childIdx) as PieSliceContainer;
357 ticAngle = sliceContainer.getTicAngle();
358 if ((ticAngle > 90) && (ticAngle < 270))
359 {
360 yVal = sliceContainer.moveLabelDown(sc, yVal);
361
362 childIdx--;
363 if (childIdx < 0) childIdx = this.numChildren - 1;
364
365 bDone = (childIdx == leftTopTicIdx);
366 }
367 else
368 {
369 bDone = true;
370 }
371 }
372 }
373
374
375 public override function toString():String {
376 return "Pie with "+ this.numChildren +" children";
377 }
378 }
379}
Note: See TracBrowser for help on using the repository browser.