1 | define(["dojo/_base/lang", "dojo/_base/array" ,"dojo/_base/declare", |
---|
2 | "./Base", "./_PlotEvents", "./common", |
---|
3 | "dojox/gfx", "dojox/gfx/matrix", "dojox/lang/functional", "dojox/lang/utils","dojo/has"], |
---|
4 | function(lang, arr, declare, Base, PlotEvents, dc, g, m, df, du, has){ |
---|
5 | |
---|
6 | /*===== |
---|
7 | declare("dojox.charting.plot2d.__PieCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, { |
---|
8 | // summary: |
---|
9 | // Specialized keyword arguments object for use in defining parameters on a Pie chart. |
---|
10 | |
---|
11 | // labels: Boolean? |
---|
12 | // Whether or not to draw labels for each pie slice. Default is true. |
---|
13 | labels: true, |
---|
14 | |
---|
15 | // ticks: Boolean? |
---|
16 | // Whether or not to draw ticks to labels within each slice. Default is false. |
---|
17 | ticks: false, |
---|
18 | |
---|
19 | // fixed: Boolean? |
---|
20 | // Whether a fixed precision must be applied to data values for display. Default is true. |
---|
21 | fixed: true, |
---|
22 | |
---|
23 | // precision: Number? |
---|
24 | // The precision at which to round data values for display. Default is 0. |
---|
25 | precision: 1, |
---|
26 | |
---|
27 | // labelOffset: Number? |
---|
28 | // The amount in pixels by which to offset labels. Default is 20. |
---|
29 | labelOffset: 20, |
---|
30 | |
---|
31 | // labelStyle: String? |
---|
32 | // Options as to where to draw labels. Values include "default", and "columns". Default is "default". |
---|
33 | labelStyle: "default", // default/columns |
---|
34 | |
---|
35 | // omitLabels: Boolean? |
---|
36 | // Whether labels of slices small to the point of not being visible are omitted. Default false. |
---|
37 | omitLabels: false, |
---|
38 | |
---|
39 | // htmlLabels: Boolean? |
---|
40 | // Whether or not to use HTML to render slice labels. Default is true. |
---|
41 | htmlLabels: true, |
---|
42 | |
---|
43 | // radGrad: String? |
---|
44 | // The type of radial gradient to use in rendering. Default is "native". |
---|
45 | radGrad: "native", |
---|
46 | |
---|
47 | // fanSize: Number? |
---|
48 | // The amount for a radial gradient. Default is 5. |
---|
49 | fanSize: 5, |
---|
50 | |
---|
51 | // startAngle: Number? |
---|
52 | // Where to being rendering gradients in slices, in degrees. Default is 0. |
---|
53 | startAngle: 0, |
---|
54 | |
---|
55 | // radius: Number? |
---|
56 | // The size of the radial gradient. Default is 0. |
---|
57 | radius: 0, |
---|
58 | |
---|
59 | // shadow: dojox.gfx.Stroke? |
---|
60 | // An optional stroke to use to draw any shadows for a series on a plot. |
---|
61 | shadow: {}, |
---|
62 | |
---|
63 | // fill: dojox.gfx.Fill? |
---|
64 | // Any fill to be used for elements on the plot. |
---|
65 | fill: {}, |
---|
66 | |
---|
67 | // filter: dojox.gfx.Filter? |
---|
68 | // An SVG filter to be used for elements on the plot. gfx SVG renderer must be used and dojox/gfx/svgext must |
---|
69 | // be required for this to work. |
---|
70 | filter: {}, |
---|
71 | |
---|
72 | // styleFunc: Function? |
---|
73 | // A function that returns a styling object for the a given data item. |
---|
74 | styleFunc: null |
---|
75 | }); |
---|
76 | =====*/ |
---|
77 | |
---|
78 | var FUDGE_FACTOR = 0.2; // use to overlap fans |
---|
79 | |
---|
80 | return declare("dojox.charting.plot2d.Pie", [Base, PlotEvents], { |
---|
81 | // summary: |
---|
82 | // The plot that represents a typical pie chart. |
---|
83 | defaultParams: { |
---|
84 | labels: true, |
---|
85 | ticks: false, |
---|
86 | fixed: true, |
---|
87 | precision: 1, |
---|
88 | labelOffset: 20, |
---|
89 | labelStyle: "default", // default/columns |
---|
90 | htmlLabels: true, // use HTML to draw labels |
---|
91 | radGrad: "native", // or "linear", or "fan" |
---|
92 | fanSize: 5, // maximum fan size in degrees |
---|
93 | startAngle: 0 // start angle for slices in degrees |
---|
94 | }, |
---|
95 | optionalParams: { |
---|
96 | radius: 0, |
---|
97 | omitLabels: false, |
---|
98 | // theme components |
---|
99 | stroke: {}, |
---|
100 | outline: {}, |
---|
101 | shadow: {}, |
---|
102 | fill: {}, |
---|
103 | filter: {}, |
---|
104 | styleFunc: null, |
---|
105 | font: "", |
---|
106 | fontColor: "", |
---|
107 | labelWiring: {} |
---|
108 | }, |
---|
109 | |
---|
110 | constructor: function(chart, kwArgs){ |
---|
111 | // summary: |
---|
112 | // Create a pie plot. |
---|
113 | this.opt = lang.clone(this.defaultParams); |
---|
114 | du.updateWithObject(this.opt, kwArgs); |
---|
115 | du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
---|
116 | this.axes = []; |
---|
117 | this.run = null; |
---|
118 | this.dyn = []; |
---|
119 | }, |
---|
120 | clear: function(){ |
---|
121 | // summary: |
---|
122 | // Clear out all of the information tied to this plot. |
---|
123 | // returns: dojox/charting/plot2d/Pie |
---|
124 | // A reference to this plot for functional chaining. |
---|
125 | this.inherited(arguments); |
---|
126 | this.dyn = []; |
---|
127 | this.run = null; |
---|
128 | return this; // dojox/charting/plot2d/Pie |
---|
129 | }, |
---|
130 | setAxis: function(axis){ |
---|
131 | // summary: |
---|
132 | // Dummy method, since axes are irrelevant with a Pie chart. |
---|
133 | // returns: dojox/charting/plot2d/Pie |
---|
134 | // The reference to this plot for functional chaining. |
---|
135 | return this; // dojox/charting/plot2d/Pie |
---|
136 | }, |
---|
137 | addSeries: function(run){ |
---|
138 | // summary: |
---|
139 | // Add a series of data to this plot. |
---|
140 | // returns: dojox/charting/plot2d/Pie |
---|
141 | // The reference to this plot for functional chaining. |
---|
142 | this.run = run; |
---|
143 | return this; // dojox/charting/plot2d/Pie |
---|
144 | }, |
---|
145 | getSeriesStats: function(){ |
---|
146 | // summary: |
---|
147 | // Returns default stats (irrelevant for this type of plot). |
---|
148 | // returns: Object |
---|
149 | // {hmin, hmax, vmin, vmax} min/max in both directions. |
---|
150 | return lang.delegate(dc.defaultStats); // Object |
---|
151 | }, |
---|
152 | getRequiredColors: function(){ |
---|
153 | // summary: |
---|
154 | // Return the number of colors needed to draw this plot. |
---|
155 | return this.run ? this.run.data.length : 0; |
---|
156 | }, |
---|
157 | render: function(dim, offsets){ |
---|
158 | // summary: |
---|
159 | // Render the plot on the chart. |
---|
160 | // dim: Object |
---|
161 | // An object of the form { width, height }. |
---|
162 | // offsets: Object |
---|
163 | // An object of the form { l, r, t, b }. |
---|
164 | // returns: dojox/charting/plot2d/Pie |
---|
165 | // A reference to this plot for functional chaining. |
---|
166 | if(!this.dirty){ return this; } |
---|
167 | this.resetEvents(); |
---|
168 | this.dirty = false; |
---|
169 | this._eventSeries = {}; |
---|
170 | this.cleanGroup(); |
---|
171 | var s = this.group, t = this.chart.theme; |
---|
172 | |
---|
173 | if(!this.run || !this.run.data.length){ |
---|
174 | return this; |
---|
175 | } |
---|
176 | |
---|
177 | // calculate the geometry |
---|
178 | var rx = (dim.width - offsets.l - offsets.r) / 2, |
---|
179 | ry = (dim.height - offsets.t - offsets.b) / 2, |
---|
180 | r = Math.min(rx, ry), |
---|
181 | labelFont = "font" in this.opt ? this.opt.font : t.series.font, |
---|
182 | size, |
---|
183 | startAngle = m._degToRad(this.opt.startAngle), |
---|
184 | start = startAngle, filteredRun, slices, labels, shift, labelR, |
---|
185 | run = this.run.data, |
---|
186 | events = this.events(); |
---|
187 | |
---|
188 | this.dyn = []; |
---|
189 | |
---|
190 | if("radius" in this.opt){ |
---|
191 | r = this.opt.radius; |
---|
192 | labelR = r - this.opt.labelOffset; |
---|
193 | } |
---|
194 | var circle = { |
---|
195 | cx: offsets.l + rx, |
---|
196 | cy: offsets.t + ry, |
---|
197 | r: r |
---|
198 | }; |
---|
199 | |
---|
200 | // draw shadow |
---|
201 | if(this.opt.shadow || t.shadow){ |
---|
202 | var shadow = this.opt.shadow || t.shadow; |
---|
203 | var scircle = lang.clone(circle); |
---|
204 | scircle.cx += shadow.dx; |
---|
205 | scircle.cy += shadow.dy; |
---|
206 | s.createCircle(scircle).setFill(shadow.color).setStroke(shadow); |
---|
207 | } |
---|
208 | if(s.setFilter && (this.opt.filter || t.filter)){ |
---|
209 | s.createCircle(circle).setFill(t.series.stroke).setFilter(this.opt.filter || t.filter); |
---|
210 | } |
---|
211 | |
---|
212 | if(typeof run[0] == "number"){ |
---|
213 | filteredRun = df.map(run, "x ? Math.max(x, 0) : 0"); |
---|
214 | if(df.every(filteredRun, "<= 0")){ |
---|
215 | s.createCircle(circle).setStroke(t.series.stroke); |
---|
216 | this.dyn = arr.map(filteredRun, function(){ |
---|
217 | return { }; |
---|
218 | }); |
---|
219 | return this; |
---|
220 | }else{ |
---|
221 | slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); |
---|
222 | if(this.opt.labels){ |
---|
223 | labels = arr.map(slices, function(x){ |
---|
224 | return x > 0 ? this._getLabel(x * 100) + "%" : ""; |
---|
225 | }, this); |
---|
226 | } |
---|
227 | } |
---|
228 | }else{ |
---|
229 | filteredRun = df.map(run, "x ? Math.max(x.y, 0) : 0"); |
---|
230 | if(df.every(filteredRun, "<= 0")){ |
---|
231 | s.createCircle(circle).setStroke(t.series.stroke); |
---|
232 | this.dyn = arr.map(filteredRun, function(){ |
---|
233 | return { }; |
---|
234 | }); |
---|
235 | return this; |
---|
236 | }else{ |
---|
237 | slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); |
---|
238 | if(this.opt.labels){ |
---|
239 | labels = arr.map(slices, function(x, i){ |
---|
240 | if(x < 0){ return ""; } |
---|
241 | var v = run[i]; |
---|
242 | return "text" in v ? v.text : this._getLabel(x * 100) + "%"; |
---|
243 | }, this); |
---|
244 | } |
---|
245 | } |
---|
246 | } |
---|
247 | var themes = df.map(run, function(v, i){ |
---|
248 | var tMixin = [this.opt, this.run]; |
---|
249 | if(v !== null && typeof v != "number"){ |
---|
250 | tMixin.push(v); |
---|
251 | } |
---|
252 | if(this.opt.styleFunc){ |
---|
253 | tMixin.push(this.opt.styleFunc(v)); |
---|
254 | } |
---|
255 | return t.next("slice", tMixin, true); |
---|
256 | }, this); |
---|
257 | |
---|
258 | if(this.opt.labels){ |
---|
259 | size = labelFont ? g.normalizedLength(g.splitFontString(labelFont).size) : 0; |
---|
260 | shift = df.foldl1(df.map(labels, function(label, i){ |
---|
261 | var font = themes[i].series.font; |
---|
262 | return g._base._getTextBox(label, {font: font}).w; |
---|
263 | }, this), "Math.max(a, b)") / 2; |
---|
264 | if(this.opt.labelOffset < 0){ |
---|
265 | r = Math.min(rx - 2 * shift, ry - size) + this.opt.labelOffset; |
---|
266 | } |
---|
267 | labelR = r - this.opt.labelOffset; |
---|
268 | } |
---|
269 | |
---|
270 | // draw slices |
---|
271 | var eventSeries = new Array(slices.length); |
---|
272 | arr.some(slices, function(slice, i){ |
---|
273 | if(slice < 0){ |
---|
274 | // degenerated slice |
---|
275 | return false; // continue |
---|
276 | } |
---|
277 | if(slice == 0){ |
---|
278 | this.dyn.push({fill: null, stroke: null}); |
---|
279 | return false; |
---|
280 | } |
---|
281 | var v = run[i], theme = themes[i], specialFill, o; |
---|
282 | if(slice >= 1){ |
---|
283 | // whole pie |
---|
284 | specialFill = this._plotFill(theme.series.fill, dim, offsets); |
---|
285 | specialFill = this._shapeFill(specialFill, |
---|
286 | { |
---|
287 | x: circle.cx - circle.r, y: circle.cy - circle.r, |
---|
288 | width: 2 * circle.r, height: 2 * circle.r |
---|
289 | }); |
---|
290 | specialFill = this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, circle.r); |
---|
291 | var shape = s.createCircle(circle).setFill(specialFill).setStroke(theme.series.stroke); |
---|
292 | this.dyn.push({fill: specialFill, stroke: theme.series.stroke}); |
---|
293 | |
---|
294 | if(events){ |
---|
295 | o = { |
---|
296 | element: "slice", |
---|
297 | index: i, |
---|
298 | run: this.run, |
---|
299 | shape: shape, |
---|
300 | x: i, |
---|
301 | y: typeof v == "number" ? v : v.y, |
---|
302 | cx: circle.cx, |
---|
303 | cy: circle.cy, |
---|
304 | cr: r |
---|
305 | }; |
---|
306 | this._connectEvents(o); |
---|
307 | eventSeries[i] = o; |
---|
308 | } |
---|
309 | |
---|
310 | return false; // we continue because we want to collect null data points for legend |
---|
311 | } |
---|
312 | // calculate the geometry of the slice |
---|
313 | var end = start + slice * 2 * Math.PI; |
---|
314 | if(i + 1 == slices.length){ |
---|
315 | end = startAngle + 2 * Math.PI; |
---|
316 | } |
---|
317 | var step = end - start, |
---|
318 | x1 = circle.cx + r * Math.cos(start), |
---|
319 | y1 = circle.cy + r * Math.sin(start), |
---|
320 | x2 = circle.cx + r * Math.cos(end), |
---|
321 | y2 = circle.cy + r * Math.sin(end); |
---|
322 | // draw the slice |
---|
323 | var fanSize = m._degToRad(this.opt.fanSize); |
---|
324 | if(theme.series.fill && theme.series.fill.type === "radial" && this.opt.radGrad === "fan" && step > fanSize){ |
---|
325 | var group = s.createGroup(), nfans = Math.ceil(step / fanSize), delta = step / nfans; |
---|
326 | specialFill = this._shapeFill(theme.series.fill, |
---|
327 | {x: circle.cx - circle.r, y: circle.cy - circle.r, width: 2 * circle.r, height: 2 * circle.r}); |
---|
328 | for(var j = 0; j < nfans; ++j){ |
---|
329 | var fansx = j == 0 ? x1 : circle.cx + r * Math.cos(start + (j - FUDGE_FACTOR) * delta), |
---|
330 | fansy = j == 0 ? y1 : circle.cy + r * Math.sin(start + (j - FUDGE_FACTOR) * delta), |
---|
331 | fanex = j == nfans - 1 ? x2 : circle.cx + r * Math.cos(start + (j + 1 + FUDGE_FACTOR) * delta), |
---|
332 | faney = j == nfans - 1 ? y2 : circle.cy + r * Math.sin(start + (j + 1 + FUDGE_FACTOR) * delta); |
---|
333 | group.createPath(). |
---|
334 | moveTo(circle.cx, circle.cy). |
---|
335 | lineTo(fansx, fansy). |
---|
336 | arcTo(r, r, 0, delta > Math.PI, true, fanex, faney). |
---|
337 | lineTo(circle.cx, circle.cy). |
---|
338 | closePath(). |
---|
339 | setFill(this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, r, start + (j + 0.5) * delta, start + (j + 0.5) * delta)); |
---|
340 | } |
---|
341 | group.createPath(). |
---|
342 | moveTo(circle.cx, circle.cy). |
---|
343 | lineTo(x1, y1). |
---|
344 | arcTo(r, r, 0, step > Math.PI, true, x2, y2). |
---|
345 | lineTo(circle.cx, circle.cy). |
---|
346 | closePath(). |
---|
347 | setStroke(theme.series.stroke); |
---|
348 | shape = group; |
---|
349 | }else{ |
---|
350 | shape = s.createPath(). |
---|
351 | moveTo(circle.cx, circle.cy). |
---|
352 | lineTo(x1, y1). |
---|
353 | arcTo(r, r, 0, step > Math.PI, true, x2, y2). |
---|
354 | lineTo(circle.cx, circle.cy). |
---|
355 | closePath(). |
---|
356 | setStroke(theme.series.stroke); |
---|
357 | specialFill = theme.series.fill; |
---|
358 | if(specialFill && specialFill.type === "radial"){ |
---|
359 | specialFill = this._shapeFill(specialFill, {x: circle.cx - circle.r, y: circle.cy - circle.r, width: 2 * circle.r, height: 2 * circle.r}); |
---|
360 | if(this.opt.radGrad === "linear"){ |
---|
361 | specialFill = this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, r, start, end); |
---|
362 | } |
---|
363 | }else if(specialFill && specialFill.type === "linear"){ |
---|
364 | specialFill = this._plotFill(specialFill, dim, offsets); |
---|
365 | specialFill = this._shapeFill(specialFill, shape.getBoundingBox()); |
---|
366 | } |
---|
367 | shape.setFill(specialFill); |
---|
368 | } |
---|
369 | this.dyn.push({fill: specialFill, stroke: theme.series.stroke}); |
---|
370 | |
---|
371 | if(events){ |
---|
372 | o = { |
---|
373 | element: "slice", |
---|
374 | index: i, |
---|
375 | run: this.run, |
---|
376 | shape: shape, |
---|
377 | x: i, |
---|
378 | y: typeof v == "number" ? v : v.y, |
---|
379 | cx: circle.cx, |
---|
380 | cy: circle.cy, |
---|
381 | cr: r |
---|
382 | }; |
---|
383 | this._connectEvents(o); |
---|
384 | eventSeries[i] = o; |
---|
385 | } |
---|
386 | |
---|
387 | start = end; |
---|
388 | |
---|
389 | return false; // continue |
---|
390 | }, this); |
---|
391 | // draw labels |
---|
392 | if(this.opt.labels){ |
---|
393 | var isRtl = has("dojo-bidi") && this.chart.isRightToLeft(); |
---|
394 | if(this.opt.labelStyle == "default"){ // inside or outside based on labelOffset |
---|
395 | start = startAngle; |
---|
396 | arr.some(slices, function(slice, i){ |
---|
397 | if(slice <= 0){ |
---|
398 | // degenerated slice |
---|
399 | return false; // continue |
---|
400 | } |
---|
401 | var theme = themes[i]; |
---|
402 | if(slice >= 1){ |
---|
403 | // whole pie |
---|
404 | this.renderLabel(s, circle.cx, circle.cy + size / 2, labels[i], theme, this.opt.labelOffset > 0); |
---|
405 | return true; // stop iteration |
---|
406 | } |
---|
407 | // calculate the geometry of the slice |
---|
408 | var end = start + slice * 2 * Math.PI; |
---|
409 | if(i + 1 == slices.length){ |
---|
410 | end = startAngle + 2 * Math.PI; |
---|
411 | } |
---|
412 | if(this.opt.omitLabels && end-start < 0.001){ |
---|
413 | return false; // continue |
---|
414 | } |
---|
415 | var labelAngle = (start + end) / 2, |
---|
416 | x = circle.cx + labelR * Math.cos(labelAngle), |
---|
417 | y = circle.cy + labelR * Math.sin(labelAngle) + size / 2; |
---|
418 | // draw the label |
---|
419 | this.renderLabel(s, isRtl ? dim.width - x : x, y, labels[i], theme, this.opt.labelOffset > 0); |
---|
420 | start = end; |
---|
421 | return false; // continue |
---|
422 | }, this); |
---|
423 | }else if(this.opt.labelStyle == "columns"){ |
---|
424 | start = startAngle; |
---|
425 | var omitLabels = this.opt.omitLabels; |
---|
426 | //calculate label angles |
---|
427 | var labeledSlices = []; |
---|
428 | arr.forEach(slices, function(slice, i){ |
---|
429 | var end = start + slice * 2 * Math.PI; |
---|
430 | if(i + 1 == slices.length){ |
---|
431 | end = startAngle + 2 * Math.PI; |
---|
432 | } |
---|
433 | var labelAngle = (start + end) / 2; |
---|
434 | labeledSlices.push({ |
---|
435 | angle: labelAngle, |
---|
436 | left: Math.cos(labelAngle) < 0, |
---|
437 | theme: themes[i], |
---|
438 | index: i, |
---|
439 | omit: omitLabels?end - start < 0.001:false |
---|
440 | }); |
---|
441 | start = end; |
---|
442 | }); |
---|
443 | //calculate label radius to each slice |
---|
444 | var labelHeight = g._base._getTextBox("a",{ font: labelFont }).h; |
---|
445 | this._getProperLabelRadius(labeledSlices, labelHeight, circle.r * 1.1); |
---|
446 | //draw label and wiring |
---|
447 | arr.forEach(labeledSlices, function(slice, i){ |
---|
448 | if(!slice.omit){ |
---|
449 | var leftColumn = circle.cx - circle.r * 2, |
---|
450 | rightColumn = circle.cx + circle.r * 2, |
---|
451 | labelWidth = g._base._getTextBox(labels[i], {font: slice.theme.series.font}).w, |
---|
452 | x = circle.cx + slice.labelR * Math.cos(slice.angle), |
---|
453 | y = circle.cy + slice.labelR * Math.sin(slice.angle), |
---|
454 | jointX = (slice.left) ? (leftColumn + labelWidth) : (rightColumn - labelWidth), |
---|
455 | labelX = (slice.left) ? leftColumn : jointX; |
---|
456 | var wiring = s.createPath().moveTo(circle.cx + circle.r * Math.cos(slice.angle), circle.cy + circle.r * Math.sin(slice.angle)); |
---|
457 | if(Math.abs(slice.labelR * Math.cos(slice.angle)) < circle.r * 2 - labelWidth){ |
---|
458 | wiring.lineTo(x, y); |
---|
459 | } |
---|
460 | wiring.lineTo(jointX, y).setStroke(slice.theme.series.labelWiring); |
---|
461 | this.renderLabel(s, isRtl ? dim.width - labelWidth - labelX : labelX, y, labels[i], slice.theme, false, "left"); |
---|
462 | } |
---|
463 | },this); |
---|
464 | } |
---|
465 | } |
---|
466 | // post-process events to restore the original indexing |
---|
467 | var esi = 0; |
---|
468 | this._eventSeries[this.run.name] = df.map(run, function(v){ |
---|
469 | return v <= 0 ? null : eventSeries[esi++]; |
---|
470 | }); |
---|
471 | // chart mirroring starts |
---|
472 | if(has("dojo-bidi")){ |
---|
473 | this._checkOrientation(this.group, dim, offsets); |
---|
474 | } |
---|
475 | // chart mirroring ends |
---|
476 | return this; // dojox/charting/plot2d/Pie |
---|
477 | }, |
---|
478 | _getProperLabelRadius: function(slices, labelHeight, minRidius){ |
---|
479 | var leftCenterSlice, rightCenterSlice, |
---|
480 | leftMinSIN = 1, rightMinSIN = 1; |
---|
481 | if(slices.length == 1){ |
---|
482 | slices[0].labelR = minRidius; |
---|
483 | return; |
---|
484 | } |
---|
485 | for(var i = 0; i < slices.length; i++){ |
---|
486 | var tempSIN = Math.abs(Math.sin(slices[i].angle)); |
---|
487 | if(slices[i].left){ |
---|
488 | if(leftMinSIN >= tempSIN){ |
---|
489 | leftMinSIN = tempSIN; |
---|
490 | leftCenterSlice = slices[i]; |
---|
491 | } |
---|
492 | }else{ |
---|
493 | if(rightMinSIN >= tempSIN){ |
---|
494 | rightMinSIN = tempSIN; |
---|
495 | rightCenterSlice = slices[i]; |
---|
496 | } |
---|
497 | } |
---|
498 | } |
---|
499 | leftCenterSlice.labelR = rightCenterSlice.labelR = minRidius; |
---|
500 | this._calculateLabelR(leftCenterSlice, slices, labelHeight); |
---|
501 | this._calculateLabelR(rightCenterSlice, slices, labelHeight); |
---|
502 | }, |
---|
503 | _calculateLabelR: function(firstSlice, slices, labelHeight){ |
---|
504 | var i = firstSlice.index,length = slices.length, |
---|
505 | currentLabelR = firstSlice.labelR, nextLabelR; |
---|
506 | while(!(slices[i%length].left ^ slices[(i+1)%length].left)){ |
---|
507 | if(!slices[(i + 1) % length].omit){ |
---|
508 | nextLabelR = (Math.sin(slices[i % length].angle) * currentLabelR + ((slices[i % length].left) ? (-labelHeight) : labelHeight)) / |
---|
509 | Math.sin(slices[(i + 1) % length].angle); |
---|
510 | currentLabelR = (nextLabelR < firstSlice.labelR) ? firstSlice.labelR : nextLabelR; |
---|
511 | slices[(i + 1) % length].labelR = currentLabelR; |
---|
512 | } |
---|
513 | i++; |
---|
514 | } |
---|
515 | i = firstSlice.index; |
---|
516 | var j = (i == 0)?length-1 : i - 1; |
---|
517 | while(!(slices[i].left ^ slices[j].left)){ |
---|
518 | if(!slices[j].omit){ |
---|
519 | nextLabelR = (Math.sin(slices[i].angle) * currentLabelR + ((slices[i].left) ? labelHeight : (-labelHeight))) / |
---|
520 | Math.sin(slices[j].angle); |
---|
521 | currentLabelR = (nextLabelR < firstSlice.labelR) ? firstSlice.labelR : nextLabelR; |
---|
522 | slices[j].labelR = currentLabelR; |
---|
523 | } |
---|
524 | i--;j--; |
---|
525 | i = (i < 0)?i+slices.length:i; |
---|
526 | j = (j < 0)?j+slices.length:j; |
---|
527 | } |
---|
528 | } |
---|
529 | }); |
---|
530 | }); |
---|