KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > chart2d > PieInfoArea


1 /**
2  * Chart2D, a java library for drawing two dimensional charts.
3  * Copyright (C) 2001 Jason J. Simas
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * The author of this library may be contacted at:
19  * E-mail: jjsimas@users.sourceforge.net
20  * Street Address: J J Simas, 887 Tico Road, Ojai, CA 93023-3555 USA
21  */

22
23
24 package net.sourceforge.chart2d;
25
26
27 import java.awt.*;
28 import java.util.Date JavaDoc;
29
30
31 /**
32  * This class manages a set of labels that can be used to encircle a PieArea,
33  * labeling its pie sectors. The way it works is that you must set the size of
34  * the max size for the class and also the size that it is supposed to
35  * encircle.
36  * This provides three different labeling types.
37  * The text of the label can be the data number of that sector, the text of
38  * the label can be a percent of the total on the data number of that sector,
39  * and the text of the label can be both.
40  * The font properties can be set using the methods of this' parent class.
41  * This class can return a point centered near each label so that lines can
42  * be drawn from the labels to their corresponding pie sectors.
43  */

44 final class PieInfoArea extends FontArea {
45
46
47   /**
48    * Static variable for setLabelsType (int) method.
49    * RAW indicates that the actual number represented by the sector should be
50    * present.
51    */

52   final static int RAW = 1;
53
54
55   /**
56    * Static variable for setLabelsType (int) method.
57    * PERCENT indicates that the percent the number represented by the sector
58    * makes of the whole should should be present.
59    */

60   final static int PERCENT = 2;
61
62
63   private int labelsType;
64   private int rawLabelsPrecision;
65   private boolean betweenLabelsGapExistence;
66   private int betweenLabelsGapThicknessModel;
67   private TextArea[] labels;
68   private Point[] pointsNearLabels;
69   private boolean labelsPointsGapExistence;
70   private int labelsPointsGapThicknessModel;
71   private PieArea pieArea;
72   private Dimension interiorSize;
73   private Rectangle interiorBounds;
74   private boolean customSizing;
75   private Dimension customSize;
76   private float[] dataset;
77   private Color[] datasetColors;
78   private boolean pieLabelsExistence;
79
80   private boolean needsUpdate;
81
82
83   /**
84    * The general constructor for this class.
85    */

86   PieInfoArea () {
87
88     pieArea = new PieArea();
89     setAutoSizes (false, false);
90     setBackgroundExistence (false);
91     setBorderExistence (false);
92     setGapExistence (false);
93     setAutoJustifys (false, false);
94     setFontPointModel (10);
95     setLabelsType (RAW + PERCENT);
96     setRawLabelsPrecision (0);
97     setBetweenLabelsGapExistence (true);
98     setBetweenLabelsGapThicknessModel (3);
99     setLabelsPointsGapExistence (true);
100     setLabelsPointsGapThicknessModel (2);
101     setCustomSize (false, new Dimension());
102     setPieLabelsExistence (true);
103     resetPieInfoAreaModel (true);
104     needsUpdate = true;
105   }
106
107
108   /**
109    * Sets whether the labels exist or not. If the labels do not exist, their
110    * space will be taken up by the pie.
111    * @param existence A boolean indicating whether the labels are painted.
112    */

113    final void setPieLabelsExistence (boolean existence) {
114
115     needsUpdate = true;
116     pieLabelsExistence = existence;
117    }
118
119
120   /**
121    * Returns whether the labels exist or not. If the labels do not exist, their
122    * space will be taken up by the pie.
123    * @return A boolean indicating whether the labels are painted.
124    */

125    final boolean getPieLabelsExistence() {
126
127     return pieLabelsExistence;
128    }
129
130
131   /**
132    * For input of the raw numbers to represent by the pie. Array element i
133    * is sector i, clockwise from degree 135.
134    * @param values The raw numbers to represent by the pie.
135    */

136   final void setDataset (float[] values) {
137
138     needsUpdate = true;
139     dataset = values;
140   }
141
142
143   /**
144    * For input of the color of each sector that represents a datum of the data
145    * set. Array element i is sector i, clockise from degree 135.
146    * @param colors The colors of the sectors.
147    */

148   final void setDatasetColors (Color[] colors) {
149
150     needsUpdate = true;
151     datasetColors = colors;
152   }
153
154
155   /**
156    * Returns the raw numbers to represent by the pie.
157    * @return The raw numbers to represent by the pie.
158    */

159   final float[] getDataset() {
160
161     return dataset;
162   }
163
164
165   /**
166    * Returns this property.
167    * @return The colors of the lines.
168    */

169   final Color[] getDatasetColors() {
170
171     return datasetColors;
172   }
173
174
175   /**
176    * Indicates the final size of the area.
177    * Everything is calculated using the non-custom properties. When laying
178    * out the labels, the labels are mereley laid out wider than normal to the
179    * point that their ends touch the edges of the custom size...
180    * Hence, all extra space is added to the interior size.
181    * @param customize If true, then the custom size will be used.
182    * @param size The custom size if used.
183    */

184   final void setCustomSize (boolean customize, Dimension size) {
185
186     needsUpdate = true;
187     customSizing = customize;
188     customSize = size;
189   }
190
191
192   /**
193    * Gets in the PieArea to encircle with labels.
194    * @return The PieArea.
195    */

196   final PieArea getPieArea() {
197     return pieArea;
198   }
199
200
201   /**
202    * Specifies whether the gaps between the labels and the points near each
203    * label exist.
204    * @param existence If true, the gaps exist.
205    */

206   final void setLabelsPointsGapExistence (boolean existence) {
207
208     needsUpdate = true;
209     labelsPointsGapExistence = existence;
210   }
211
212
213   /**
214    * Indicates how far from the labels, the points on each label should be.
215    * The points are returned by the getPointsNearLabels(...) method.
216    * @param thickness The model thickness of the gap between the label and the
217    * point.
218    */

219   final void setLabelsPointsGapThicknessModel (int thickness) {
220
221     needsUpdate = true;
222     labelsPointsGapThicknessModel = thickness;
223   }
224
225
226   /**
227    * Indicates how many significant digits are wanted.
228    * For example, if you want two decimal places, then pass -2.
229    * If you want no decimal places, then pass 0.
230    * For more information see ChartArea.getPrecisionRound(...).
231    * @param The desired precision of the raw labels.
232    */

233   final void setRawLabelsPrecision (int precision) {
234
235     needsUpdate = true;
236     rawLabelsPrecision = precision;
237   }
238
239
240   /**
241    * Indicates whether a gap should exist between the labels.
242    * This method overides setBetweenLabelsGapThicknessModel(...).
243    * @param existence If true, the gaps will exist.
244    */

245   final void setBetweenLabelsGapExistence (boolean existence) {
246
247     needsUpdate = true;
248     betweenLabelsGapExistence = existence;
249   }
250
251
252   /**
253    * Indicates the model thickness of the gap between each label.
254    * This thickness is actually the minimum model thickness. If there is
255    * extra space that the labels don't need it is divided evenly between the
256    * labels, but the gap will be at least what is specified here.
257    * @param thickness The model minimum thickness of the gap.
258    */

259   final void setBetweenLabelsGapThicknessModel (int thickness) {
260
261     needsUpdate = true;
262     betweenLabelsGapThicknessModel = thickness;
263   }
264
265
266   /**
267    * Indirectly sets the text of the labels. Possible values are RAW, PERCENT,
268    * and RAW + PERCENT. RAW causes the text of the label to be the actual data
269    * numbers. PERCENT causes the text to be the percent of the whole of the
270    * data. RAW + PERCENT causes the text of the label to be both, in the format
271    * of "p% - d" were p is the percent and d is the data number.
272    * @param type What text occurrs in each label.
273    */

274   final void setLabelsType (int type) {
275
276     needsUpdate = true;
277     labelsType = type;
278   }
279
280
281   /**
282    * Returns how far from the labels, the points on each label should be.
283    * The points are returned by the getPointsNearLabels(...) method.
284    * @return The model thickness of the gap between the label and the point.
285    */

286   final int getLabelsPointsGapThicknessModel() {
287
288     return labelsPointsGapThicknessModel;
289   }
290
291
292   /**
293    * Returns how many significant digits are wanted.
294    * For example, if you want two decimal places, then pass -2.
295    * If you want no decimal places, then pass 0.
296    * For more information see ChartArea.getPrecisionRound(...).
297    * @return The desired precision of the raw labels.
298    */

299   final int getRawLabelsPrecision() {
300
301     return rawLabelsPrecision;
302   }
303
304
305   /**
306    * Indirectly returns the text of the labels. Possible values are RAW,
307    * PERCENT,
308    * and RAW + PERCENT. RAW causes the text of the label to be the actual data
309    * numbers. PERCENT causes the text to be the percent of the whole of the
310    * data. RAW + PERCENT causes the text of the label to be both, in the format
311    * of "p% - d" were p is the percent and d is the data number.
312    * @return What text occurrs in each label.
313    */

314   final int getLabelsType() {
315
316     return labelsType;
317   }
318
319
320   /**
321    * Returns a bounding rectangle of the area the labels encircle.
322    * @return The bounding rectangle of the interior.
323    */

324   final Rectangle getInteriorBounds (Graphics2D g2D) {
325
326     updatePieInfoArea (g2D);
327     return interiorBounds;
328   }
329
330
331   /**
332    * Returns whether the gaps between the labels and the points near each
333    * label exist.
334    * @return boolean If true, the gaps exist.
335    */

336   final boolean getLabelsPointsGapExistence() {
337     return labelsPointsGapExistence;
338   }
339
340
341   /**
342    * Returns an array of points, one for each label, that are near the labels.
343    * These points can be used for drawing lines from pie sectors to labels.
344    * @return Point[] The array of points.
345    */

346   final Point[] getPointsNearLabels (Graphics2D g2D) {
347
348     updatePieInfoArea (g2D);
349     return pointsNearLabels;
350   }
351
352
353   /**
354    * Indicates whether some property of this class has changed.
355    * @return True if some property has changed.
356    */

357   final boolean getPieInfoAreaNeedsUpdate() {
358     return (needsUpdate || getFontAreaNeedsUpdate() || pieArea.getPieAreaNeedsUpdate());
359   }
360
361
362   /**
363    * Resets the model for this class. The model is used for shrinking and
364    * growing of its components based on the maximum size of this class. If this
365    * method is called, then the next time the maximum size is set, this classes
366    * model maximum size will be made equal to the new maximum size. Effectively
367    * what this does is ensure that whenever this objects maximum size is equal
368    * to the one given, then all of the components will take on their default
369    * model sizes. Note: This is only useful when auto model max sizing is
370    * disabled.
371    * @param reset True causes the max model size to be set upon the next max
372    * sizing.
373    */

374   final void resetPieInfoAreaModel (boolean reset) {
375
376     needsUpdate = true;
377     resetFontAreaModel (reset);
378     pieArea.resetPieAreaModel (reset);
379   }
380
381
382   /**
383    * Updates all this classes variables. First updates it's parent class, then
384    * then updates its own variables.
385    */

386   final void updatePieInfoArea (Graphics2D g2D) {
387
388     if (getPieInfoAreaNeedsUpdate()) {
389
390       updateFontArea();
391       update (g2D);
392       pieArea.updatePieArea();
393       for (int i = 0; i < labels.length; ++i) {
394         labels[i].updateTextArea (g2D);
395       }
396     }
397     needsUpdate = false;
398   }
399
400
401   /**
402    * Paints this class. Updates all variables, then paints its parent, since
403    * this class itself doesn't have anything to paint.
404    * @param g2D The graphics context for calculations and painting.
405    */

406   final void paintComponent (Graphics2D g2D) {
407
408     updatePieInfoArea (g2D);
409     super.paintComponent (g2D);
410
411     pieArea.paintComponent (g2D);
412     for (int i = 0; i < pieArea.getDataset().length; ++i) {
413       labels[i].paintComponent (g2D);
414     }
415   }
416
417
418   private void update (Graphics2D g2D) {
419
420     float widthRatio = getRatio (WIDTH);
421     float heightRatio = getRatio (HEIGHT);
422     pieArea.setCustomRatio (WIDTH, true, widthRatio);
423     pieArea.setCustomRatio (HEIGHT, true, heightRatio);
424
425     pieArea.setDataset (dataset);
426     pieArea.setColors (datasetColors);
427     pieArea.setSize (MAX, new Dimension (100, 100)); //fake for accurate calculation
428
pieArea.setCustomSpaceSize (true, new Dimension (100, 100)); //fake for accurate calculation
429
pieArea.updatePieArea();
430     int[] numLabelsInSectors = pieArea.getNumSectorsInQuarters();
431     int[] numLabelsInQuarters = new int[4];
432     numLabelsInQuarters[TOP] = numLabelsInSectors[TOP];
433     numLabelsInQuarters[RIGHT] = numLabelsInSectors[RIGHT];
434     numLabelsInQuarters[BOTTOM] = numLabelsInSectors[BOTTOM];
435     numLabelsInQuarters[LEFT] = numLabelsInSectors[LEFT];
436     pieArea.setCustomSpaceSize (false, null);
437     pieArea.updatePieArea();
438
439     int maxLabelsHorizontally =
440       numLabelsInQuarters[TOP] > numLabelsInQuarters[BOTTOM] ?
441       numLabelsInQuarters[TOP] : numLabelsInQuarters[BOTTOM];
442     int maxLabelsVertically =
443       numLabelsInQuarters[RIGHT] > numLabelsInQuarters[LEFT] ?
444       numLabelsInQuarters[RIGHT] : numLabelsInQuarters[LEFT];
445
446     int betweenLabelsGapThickness = 0;
447     if (betweenLabelsGapExistence && pieLabelsExistence) {
448       betweenLabelsGapThickness = applyRatio (betweenLabelsGapThicknessModel, getRatio (LESSER));
449     }
450
451     Dimension labelsSizeMax;
452     if (pieLabelsExistence) {
453       int labelsMaxWidth1 = getSpaceSize (MAX).width / 2 - betweenLabelsGapThickness;
454       int labelsMaxWidth2 = Integer.MAX_VALUE;
455       if (maxLabelsHorizontally > 0) {
456         labelsMaxWidth2 =
457           (getSpaceSize (MAX).width - (maxLabelsHorizontally - 1) * betweenLabelsGapThickness) /
458           maxLabelsHorizontally;
459       }
460       int labelsMaxWidth = labelsMaxWidth1 < labelsMaxWidth2 ? labelsMaxWidth1 : labelsMaxWidth2;
461       labelsMaxWidth = labelsMaxWidth > 0 ? labelsMaxWidth : 0;
462
463       int labelsMaxHeight1 = getSpaceSize (MAX).height / 2 - betweenLabelsGapThickness;
464       int labelsMaxHeight2 =
465         (getSpaceSize (MAX).height - (maxLabelsVertically + 1) * betweenLabelsGapThickness) /
466         (maxLabelsVertically + 2);
467       int labelsMaxHeight =
468         labelsMaxHeight1 < labelsMaxHeight2 ? labelsMaxHeight1 : labelsMaxHeight2;
469       labelsMaxHeight = labelsMaxHeight > 0 ? labelsMaxHeight : 0;
470       labelsSizeMax = new Dimension (labelsMaxWidth, labelsMaxHeight);
471     }
472     else labelsSizeMax = new Dimension();
473
474     labels = new TextArea[dataset.length];
475     float datasetTotal = ChartArea.getDatasetTotal (dataset);
476     int labelsWidthMin = 0;
477     int labelsHeightMin = 0;
478     for (int i = 0; i < dataset.length; ++i) {
479
480       TextArea label = new TextArea();
481       label.setCustomRatio (WIDTH, true, getRatio (WIDTH));
482       label.setCustomRatio (HEIGHT, true, getRatio (HEIGHT));
483       label.setAutoJustifys (false, false);
484       label.setAutoSizes (true, false);
485       label.setSize (MAX, labelsSizeMax);
486       label.setBackgroundExistence (false);
487       label.setBorderExistence (false);
488       label.setGapExistence (false);
489       label.setFontColor (getFontColor());
490       label.setFontName (getFontName());
491       label.setFontPointModel (getFontPointModel());
492       label.setFontStyle (getFontStyle());
493
494       String JavaDoc text = "";
495       if (labelsType == RAW) {
496         text = ChartArea.getFloatToString (
497           ChartArea.getPrecisionRound (dataset[i], rawLabelsPrecision), rawLabelsPrecision);
498       }
499       else if (labelsType == PERCENT) {
500         text = ChartArea.getFloatToString (
501           ChartArea.getPrecisionRound (100 * dataset[i] / datasetTotal, 0), 0) + "%";
502       }
503       else {
504         String JavaDoc text1 = ChartArea.getFloatToString (
505           ChartArea.getPrecisionRound (dataset[i], rawLabelsPrecision), rawLabelsPrecision);
506         String JavaDoc text2 = ChartArea.getFloatToString (
507           ChartArea.getPrecisionRound (100 * dataset[i] / datasetTotal, 0), 0) + "%";
508         text = text1 + " (" + text2 + ")";
509       }
510       label.setText (text);
511
512       label.updateTextArea (g2D);
513       labelsWidthMin =
514         label.getSize (MIN).width > labelsWidthMin ? label.getSize (MIN).width : labelsWidthMin;
515       labelsHeightMin =
516         label.getSize (MIN).height > labelsHeightMin ? label.getSize (MIN).height : labelsHeightMin;
517       labels[i] = label;
518     }
519
520     Dimension labelsSizeMin = new Dimension (labelsWidthMin, labelsHeightMin);
521
522     int widthMin1 =
523       (maxLabelsHorizontally - 1) * betweenLabelsGapThickness +
524       maxLabelsHorizontally * labelsWidthMin;
525     int widthMin2 = 2 * labelsWidthMin;
526     int widthMin = widthMin1 > widthMin2 ? widthMin1 : widthMin2;
527
528     int heightMin1 =
529       (maxLabelsVertically + 1) * betweenLabelsGapThickness +
530       (maxLabelsVertically + 2) * labelsHeightMin;
531     int heightMin2 = 2 * labelsHeightMin;
532     int heightMin = heightMin1 > heightMin2 ? heightMin1 : heightMin2;
533
534     int pieSize = 0;
535     if (!getAutoSize (MIN) && !customSizing) {
536
537       int availableWidth = getSpaceSize (MAX).width - widthMin;
538       int availableHeight = getSpaceSize (MAX).height - heightMin;
539       int available = availableWidth < availableHeight ? availableWidth : availableHeight;
540       pieArea.setSize (MAX, new Dimension (available, available));
541       pieArea.updatePieArea();
542       pieSize = pieArea.getSize (MIN).width;
543
544       widthMin += pieSize;
545       heightMin += pieSize;
546
547       setSpaceSize (MIN, new Dimension (widthMin, heightMin));
548     }
549     else if (!getAutoSize (MIN) && customSizing) {
550
551       setSpaceSize (MIN, customSize);
552     }
553
554     Dimension sizeMin = getSpaceSize (MIN);
555
556     float midPointX = getSpaceSizeLocation (MIN).x + sizeMin.width / 2f;
557     float midPointY = getSpaceSizeLocation (MIN).y + sizeMin.height / 2f;
558
559     pointsNearLabels = new Point[dataset.length];
560
561     int labelsPointsGapThickness =
562       labelsPointsGapExistence ? applyRatio (labelsPointsGapThicknessModel, getRatio (LESSER)) : 0;
563
564     int topInteriorY = 0, leftInteriorX = 0;
565     Point originTop = new Point (0, getSpaceSizeLocation (MIN).y);
566     int betweenGapTop =
567       (sizeMin.width - numLabelsInQuarters[TOP] * labelsWidthMin) / (numLabelsInQuarters[TOP] + 1);
568     if (numLabelsInQuarters[TOP] % 2 == 0) {
569       originTop.setLocation (
570         midPointX - (numLabelsInQuarters[TOP] / 2) * labelsWidthMin -
571         ((numLabelsInQuarters[TOP] / 2) - 1/2f) * betweenGapTop, originTop.y);
572     }
573     else {
574       originTop.setLocation ((int)(
575       midPointX - (numLabelsInQuarters[TOP] / 2f) * labelsWidthMin -
576         (int)(numLabelsInQuarters[TOP] / 2) * betweenGapTop),
577         originTop.y);
578     }
579
580     topInteriorY = originTop.y + labelsHeightMin;
581     for (int i = 0; i < numLabelsInQuarters[TOP]; ++i) {
582       labels[i].setSpaceSizeLocation (MIN, new Point (
583         (int)(originTop.x + i * (labelsWidthMin + betweenGapTop) +
584         (labelsWidthMin - labels[i].getSize(MIN).width) / 2f),
585         originTop.y));
586       pointsNearLabels[i] = new Point (
587         (int)(labels[i].getSpaceSizeLocation (MIN).x +
588         (labels[i].getSize (MIN).width / 2f)),
589         originTop.y + labelsHeightMin + labelsPointsGapThickness);
590     }
591
592     Point originRight = new Point (
593       getSpaceSizeLocation (MIN).x + sizeMin.width - labelsWidthMin, 0);
594     int betweenGapRight =
595       (sizeMin.height - (numLabelsInQuarters[RIGHT] + 2) * labelsHeightMin) /
596       (numLabelsInQuarters[RIGHT] + 1);
597     if (numLabelsInQuarters[RIGHT] % 2 == 0) {
598       originRight.setLocation (originRight.x,
599         (int)(midPointY - (numLabelsInQuarters[RIGHT] / 2) * labelsHeightMin -
600         ((numLabelsInQuarters[RIGHT] / 2) - 1/2f) * betweenGapRight));
601     }
602     else {
603       originRight.setLocation (originRight.x,
604         (int)(midPointY - (numLabelsInQuarters[RIGHT] / 2f) * labelsHeightMin -
605         (int)(numLabelsInQuarters[RIGHT] / 2) * betweenGapRight));
606     }
607
608     int datasetOffsetRight = numLabelsInQuarters[TOP];
609     for (int i = 0; i < numLabelsInQuarters[RIGHT]; ++i) {
610       labels[i + datasetOffsetRight].setSpaceSizeLocation (MIN, new Point (
611         originRight.x +
612         (labelsWidthMin - labels[i + datasetOffsetRight].getSize(MIN).width),
613         (int)(originRight.y + i * (labelsHeightMin + betweenGapRight) +
614         (labelsHeightMin - labels[i + datasetOffsetRight].getSize(MIN).height) /
615         2f)));
616       pointsNearLabels[i + datasetOffsetRight] = new Point (
617         originRight.x - labelsPointsGapThickness,
618         (int)(labels[i + datasetOffsetRight].getSpaceSizeLocation (MIN).y +
619         (labels[i + datasetOffsetRight].getSize (MIN).height / 2f)));
620     }
621
622     Point originBottom = new Point (0,
623       getSpaceSizeLocation (MIN).y + getSpaceSize (MIN).height -
624       labelsHeightMin);
625     int betweenGapBottom =
626       (sizeMin.width - numLabelsInQuarters[BOTTOM] * labelsWidthMin) /
627       (numLabelsInQuarters[BOTTOM] + 1);
628     if (numLabelsInQuarters[BOTTOM] % 2 == 0) {
629       originBottom.setLocation (
630         midPointX - (numLabelsInQuarters[BOTTOM] / 2) * labelsWidthMin -
631         ((numLabelsInQuarters[BOTTOM] / 2) - 1/2f) * betweenGapBottom,
632         originBottom.y);
633     }
634     else {
635       originBottom.setLocation ((int)(
636       midPointX - (numLabelsInQuarters[BOTTOM] / 2f) * labelsWidthMin -
637         (int)(numLabelsInQuarters[BOTTOM] / 2) * betweenGapBottom),
638         originBottom.y);
639     }
640
641     int datasetOffsetBottom =
642       numLabelsInQuarters[TOP] + numLabelsInQuarters[RIGHT];
643     int j = numLabelsInQuarters[BOTTOM] - 1;
644     for (int i = 0; i < numLabelsInQuarters[BOTTOM]; ++i) {
645       labels[i + datasetOffsetBottom].setSpaceSizeLocation (
646         MIN, new Point ((int)(originBottom.x +
647         j * (labelsWidthMin + betweenGapBottom) +
648         (labelsWidthMin - labels[i + datasetOffsetBottom].getSize(MIN).width) /
649         2f),
650         originBottom.y + (labelsHeightMin -
651         labels[i + datasetOffsetBottom].getSize(MIN).height)));
652       --j;
653       pointsNearLabels[i + datasetOffsetBottom] = new Point (
654         (int)(labels[i + datasetOffsetBottom].getSpaceSizeLocation (MIN).x +
655         (labels[i + datasetOffsetBottom].getSize (MIN).width / 2f)),
656         originBottom.y - labelsPointsGapThickness);
657     }
658
659     Point originLeft = new Point (getSpaceSizeLocation (MIN).x, 0);
660     int betweenGapLeft =
661       (sizeMin.height - (numLabelsInQuarters[LEFT] + 2) * labelsHeightMin) /
662       (numLabelsInQuarters[LEFT] + 1);
663     if (numLabelsInQuarters[LEFT] % 2 == 0) {
664       originLeft.setLocation (originLeft.x,
665         (int)(midPointY - (numLabelsInQuarters[LEFT] / 2) * labelsHeightMin -
666         ((numLabelsInQuarters[LEFT] / 2) - 1/2f) * betweenGapLeft));
667     }
668     else {
669       originLeft.setLocation (originLeft.x,
670         (int)(midPointY - (numLabelsInQuarters[LEFT] / 2f) * labelsHeightMin -
671         (int)(numLabelsInQuarters[LEFT] / 2) * betweenGapLeft));
672     }
673     leftInteriorX = originLeft.x + labelsWidthMin;
674
675     int datasetOffsetLeft = numLabelsInQuarters[TOP] +
676       numLabelsInQuarters[RIGHT] + numLabelsInQuarters[BOTTOM];
677     j = numLabelsInQuarters[LEFT] - 1;
678     for (int i = 0; i < numLabelsInQuarters[LEFT]; ++i) {
679       labels[i + datasetOffsetLeft].setSpaceSizeLocation (MIN, new Point (
680         originLeft.x + labelsWidthMin -
681         labels[i + datasetOffsetLeft].getSize(MIN).width,
682         (int)(originLeft.y + j * (labelsHeightMin + betweenGapLeft) +
683         (labelsHeightMin -
684         labels[i + datasetOffsetLeft].getSize(MIN).height) / 2f)));
685       --j;
686       pointsNearLabels[i + datasetOffsetLeft] = new Point (
687         originLeft.x + labelsWidthMin + labelsPointsGapThickness,
688         (int)(labels[i + datasetOffsetLeft].getSpaceSizeLocation (MIN).y +
689         (labels[i + datasetOffsetLeft].getSize (MIN).height / 2f)));
690     }
691
692     pieArea.setCustomSpaceSize (true, new Dimension (
693       originRight.x - originLeft.x - labelsWidthMin - 2 * pieArea.getOffsetThickness(),
694       originBottom.y - originTop.y - labelsHeightMin - 2 * pieArea.getOffsetThickness()));
695     pieArea.setSpaceSizeLocation (MIN, new Point (
696       originLeft.x + labelsWidthMin + pieArea.getOffsetThickness(),
697       originTop.y + labelsHeightMin + pieArea.getOffsetThickness()));
698   }
699 }
Popular Tags