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