KickJava   Java API By Example, From Geeks To Geeks.

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


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.awt.geom.*;
29
30
31 /**
32  * The area that the x axis and y axis attach to, and in which bars, lines, or
33  * dots are painted to represent the data set. The "LL" in the name of this
34  * class stands for Labels Left. This graph should always be used when the
35  * data descriptors for the the graph are located on the left. Data
36  * descriptors have values such as September and November, and not like 0 or 50.
37  * <b>Features:</b><br>
38  * Provides bordering functionality. Allows lines to be painted that match
39  * up with y axis and x axis tick marks in order to know where the bars, dots,
40  * or plot lines are in relation to the x axis values. Supports vertical
41  * bar graphs, line charts, and scatter charts (dots), and any combintation
42  * thereof. If a bars are present in any graph, then it is highly recommended
43  * that the GraphArea method, allowComponentAlignment be passed the value of
44  * false. This will ensure that all the bars are visible on the graph. For
45  * graphs that do not have bars present, the opposite is advised. The GraphArea
46  * method should be passed the value of true. This provides a more intuitive
47  * representation of the data.
48  */

49 final class LLGraphArea extends GraphArea {
50
51
52   private FancyBar[][] bars;
53   private FancyDot[][] dots;
54   private FancyLine[] lines;
55   private boolean needsUpdate;
56
57
58   /**
59    * Creates a graph area with GraphArea's default values, except with vertical
60    * lines instead of horizontal alignment lines. The default values:<br>
61    * setType (LABELSLEFT);<br>
62    * setHorizontalLinesExistence (false);<br>
63    * setVerticalLinesExistence (true);<br>
64    * resetLLGraphAreaModel (true);<br>
65    */

66   LLGraphArea() {
67
68     bars = new FancyBar[0][0];
69     dots = new FancyDot[0][0];
70     lines = new FancyLine[0];
71
72     setBarRoundingRatio (.25f);
73
74     setType (LABELSLEFT);
75     setHorizontalLinesExistence (false);
76     setVerticalLinesExistence (true);
77
78     resetLLGraphAreaModel (true);
79     needsUpdate = true;
80   }
81
82
83   /**
84    * Does a quick calculation of the preferred height of the graph.
85    * @param numSets The number of data series.
86    * @param numComps The number of data categories per series.
87    * @param numCompsPerCat The number of data per series, per category.
88    * @return The preferred width.
89    */

90   final int getPrefSpaceHeight (int numSets, int numCats, int numCompsPerCat) {
91
92     float ratio = getRatio (HEIGHT);
93     int barsHeight = 0, dotsHeight = 0, linesHeight = 0, prefHeight = 0;
94     if (getAllowComponentAlignment()) {
95       barsHeight = getBarsExistence() ?
96         (int)(numCats * (1 + (1 - getBarsWithinCategoryOverlapRatio()) *
97         (numCompsPerCat - 1)) *
98         applyRatio (getBarsThicknessModel(), ratio)) : 0;
99       dotsHeight = getDotsExistence() ?
100         (int)(numCats * (1 + (1 - getDotsWithinCategoryOverlapRatio()) *
101         (numCompsPerCat - 1)) *
102         applyRatio (getDotsThicknessModel(), ratio)) : 0;
103       linesHeight = getLinesExistence() ?
104         (int)(numCats * (1 + (1 - getLinesWithinCategoryOverlapRatio()) *
105         (numCompsPerCat - 1)) *
106         applyRatio (getLinesThicknessModel(), ratio)) : 0;
107     }
108     else {
109       barsHeight = getBarsExistence() ?
110         (int)(numSets * numCats *
111         (1 + (1 - getBarsWithinCategoryOverlapRatio()) *
112         (numCompsPerCat - 1)) *
113         applyRatio (getBarsThicknessModel(), ratio)) : 0;
114       dotsHeight = getDotsExistence() ?
115         (int)(numSets * numCats * (1 +
116         (1 - getDotsWithinCategoryOverlapRatio()) *
117         (numCompsPerCat - 1)) *
118         applyRatio (getDotsThicknessModel(), ratio)) : 0;
119       linesHeight = getLinesExistence() ?
120         (int)(numSets * numCats * (1 +
121         (1 - getLinesWithinCategoryOverlapRatio()) *
122         (numCompsPerCat - 1)) *
123         applyRatio (getLinesThicknessModel(), ratio)) : 0;
124
125     }
126     prefHeight = barsHeight > dotsHeight ? barsHeight : dotsHeight;
127     prefHeight = prefHeight > linesHeight ? prefHeight : linesHeight;
128     int gapsHeight = getBetweenComponentsGapExistence() ?
129       numCats * applyRatio (getBetweenComponentsGapThicknessModel(), ratio) : 0;
130     prefHeight = prefHeight + gapsHeight;
131     prefHeight = prefHeight < getSpaceSize(MAX).height ? prefHeight : getSpaceSize(MAX).height;
132     return (prefHeight);
133   }
134
135
136   /**
137    * Indicates whether some property of this class has changed.
138    * @return True if some property has changed.
139    */

140   final boolean getLLGraphAreaNeedsUpdate() {
141
142     return (needsUpdate || getGraphAreaNeedsUpdate());
143   }
144
145
146   /**
147    * Resets the model for this class. The model is used for shrinking and
148    * growing of its components based on the maximum size of this class. If this
149    * method is called, then the next time the maximum size is set, this classes
150    * model maximum size will be made equal to the new maximum size. Effectively
151    * what this does is ensure that whenever this objects maximum size is equal
152    * to the one given, then all of the components will take on their default
153    * model sizes. Note: This is only useful when auto model max sizing is
154    * disabled.
155    * @param reset True causes the max model size to be set upon the next max
156    * sizing.
157    */

158   final void resetLLGraphAreaModel (boolean reset) {
159
160     needsUpdate = true;
161     resetGraphAreaModel (reset);
162   }
163
164
165   /**
166    * Updates this parent's variables, and this' variables.
167    */

168   final void updateLLGraphArea() {
169
170     if (getLLGraphAreaNeedsUpdate()) {
171       updateGraphArea();
172       update();
173     }
174     needsUpdate = false;
175   }
176
177
178   /**
179    * Paints all the components of this class. First all variables are updated.
180    * @param g2D The graphics context for calculations and painting.
181    */

182   final void paintComponent (Graphics2D g2D) {
183
184     updateLLGraphArea();
185     super.paintComponent (g2D);
186
187
188     Shape oldClip = g2D.getClip();
189     if (getClip()) g2D.setClip (new Rectangle (getSpaceSizeLocation (MIN), getSpaceSize (MIN)));
190
191     Composite oldComposite = g2D.getComposite();
192     g2D.setComposite (getComponentsAlphaComposite());
193
194     int numBars = bars.length > 0 ? bars[0].length : 0;
195     int numDots = dots.length > 0 ? dots[0].length : 0;
196     int numLines = lines.length;
197     int numSets = getGraphValues().length;
198     if (!getAllowComponentAlignment() && numBars > 0) {
199       for (int i = 0; i < numSets; ++i) {
200         for (int j = 0; j < numBars; ++j) {
201           bars[i][j].paint (g2D);
202         }
203       }
204     }
205     else if (numBars > 0) {
206       int[][] graphValues = getGraphValues();
207       graphValues = stackedBarConvert (graphValues, getBarLowValues());
208       for (int j = 0; j < numBars; ++j) {
209         int[] sorted = stackedBarSort (graphValues, j);
210         for (int i = 0; i < numSets; ++i) {
211           bars[sorted[i]][j].paint (g2D);
212         }
213       }
214     }
215
216     for (int i = numLines - 1; i >= 0 ; --i) lines[i].paint (g2D);
217
218     for (int i = numSets - 1; i >= 0; --i) {
219       for (int j = numDots - 1; j >= 0 ; --j) {
220         dots[i][j].paint (g2D);
221       }
222     }
223
224     g2D.setClip (oldClip);
225     g2D.setComposite (oldComposite);
226   }
227
228
229   private void update() {
230
231     if (getAllowComponentAlignment()) updateAllowAlignment();
232     else updateDisallowAlignment();
233   }
234
235
236   private void updateDisallowAlignment() {
237
238     int[][] graphLengths = getGraphValues();
239     int numBars = 0, numDots = 0, numLinePoints = 0, numGaps = 0;
240     int numSets = graphLengths.length;
241     Rectangle[] yTicks = getYTicks();
242     int numCompsPerCat = 0;
243     int numCats = 0;
244     if (numSets > 0) {
245       numCats = getLabelsAxisTicksAlignment() == BETWEEN ?
246         yTicks.length + 1 : yTicks.length;
247       numBars = getBarsExistence() ? numCats : 0;
248       numDots = getDotsExistence() ? numCats : 0;
249       numLinePoints = getLinesExistence() ? numCats : 0;
250       numGaps = getBetweenComponentsGapExistence() ? numCats : 0;
251       numCompsPerCat =
252         numCats > 0 ? (int)(graphLengths[0].length / numCats) : 0;
253     }
254     if (numSets > 0 && numCats > 0 && numCompsPerCat > 0) {
255       float ratio = getRatio (HEIGHT);
256       int availableThickness = getSpaceSize(MIN).height;
257
258       int betweenComponentsGapThickness = 0;
259       if (numGaps > 0) {
260         betweenComponentsGapThickness =
261           applyRatio (getBetweenComponentsGapThicknessModel(), ratio);
262         betweenComponentsGapThickness =
263           numGaps * betweenComponentsGapThickness <= availableThickness ?
264           betweenComponentsGapThickness : availableThickness / numGaps;
265         availableThickness -= numGaps * betweenComponentsGapThickness;
266       }
267
268       int barsThickness = 0;
269       if (numBars > 0) {
270         barsThickness = applyRatio (getBarsThicknessModel(), ratio);
271         if ((numSets * numBars * numCompsPerCat) * barsThickness <=
272           availableThickness) {
273           float leftover =
274             (availableThickness - barsThickness *
275             (numSets * numBars * numCompsPerCat)) /
276             (numSets * numBars * numCompsPerCat);
277           barsThickness =
278             barsThickness + (int)(getBarsExcessSpaceFeedbackRatio() * leftover);
279         }
280         else {
281           float numOverlapBarsPerCat =
282             (1 + (1 - getBarsWithinCategoryOverlapRatio()) *
283             (numCompsPerCat - 1));
284           if (numSets * numBars * numOverlapBarsPerCat * barsThickness >
285             availableThickness) {
286             barsThickness = (int)(availableThickness /
287               (numSets * numBars * numOverlapBarsPerCat));
288           }
289         }
290       }
291       int dotsThickness = 0;
292       if (numDots > 0) {
293         dotsThickness = applyRatio (getDotsThicknessModel(), getRatio (LESSER));
294         if ((numSets * numDots * numCompsPerCat) * dotsThickness <=
295           availableThickness) {
296           float leftover =
297             (availableThickness - dotsThickness *
298             (numSets * numDots * numCompsPerCat)) /
299             (numSets * numDots * numCompsPerCat);
300           dotsThickness =
301             dotsThickness + (int)(getDotsExcessSpaceFeedbackRatio() * leftover);
302         }
303         else {
304           float numOverlapDotsPerCat =
305             (1 + (1 - getDotsWithinCategoryOverlapRatio()) *
306             (numCompsPerCat - 1));
307           if (numSets * numDots * numOverlapDotsPerCat * dotsThickness >
308             availableThickness) {
309             dotsThickness = (int)(availableThickness /
310               (numSets * numDots * numOverlapDotsPerCat));
311           }
312         }
313       }
314       int linesThickness = 0;
315       if (numLinePoints > 0) {
316         linesThickness = applyRatio (getLinesThicknessModel(), getRatio (LESSER));
317         if ((numSets * numLinePoints * numCompsPerCat) * linesThickness <=
318           availableThickness) {
319           float leftover =
320             (availableThickness - linesThickness *
321             (numSets * numLinePoints * numCompsPerCat)) /
322             (numSets * numLinePoints * numCompsPerCat);
323           linesThickness =
324             linesThickness + (int)(getLinesExcessSpaceFeedbackRatio() * leftover);
325         }
326         else {
327           float numOverlapLinesPerCat =
328             (1 + (1 - getLinesWithinCategoryOverlapRatio()) *
329             (numCompsPerCat - 1));
330           if (numSets * numLinePoints * numOverlapLinesPerCat * linesThickness >
331             availableThickness) {
332             linesThickness = (int)(availableThickness /
333               (numSets * numLinePoints * numOverlapLinesPerCat));
334           }
335         }
336       }
337
338       int componentsThickness = barsThickness;
339       componentsThickness = dotsThickness > componentsThickness ?
340         dotsThickness : componentsThickness;
341       componentsThickness = linesThickness > componentsThickness ?
342         linesThickness : componentsThickness;
343       int setsThickness = componentsThickness * numSets;
344       setsThickness =
345         setsThickness > availableThickness / (numCats * numCompsPerCat) ?
346         availableThickness / (numCats * numCompsPerCat) : setsThickness;
347       componentsThickness = setsThickness / numSets;
348
349       Rectangle2D.Float boundsGraph = new Rectangle2D.Float (
350         getSpaceSizeLocation (MIN).x, getSpaceSizeLocation (MIN).y,
351         getSpaceSize (MIN).width, getSpaceSize (MIN).height);
352
353       bars = new FancyBar[numSets][numBars * numCompsPerCat];
354       int[][] barLowValues = getBarLowValues();
355       if (numBars > 0) {
356         int x = getSpaceSizeLocation (MIN).x - (getOutlineComponents() ? 1 : 0), y = 0;
357         float catDelta =
358           getSpaceSize (MIN).height / (float)(numBars * numCompsPerCat);
359         if (numBars == 1) {
360           y = getSpaceSizeLocation (MIN).y +
361             (getSpaceSize(MIN).height - setsThickness) / 2;
362           y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
363           for (int k = 0; k < numCompsPerCat; ++k) {
364             for (int j = 0; j < numSets; ++j) {
365               int compY = y + j * componentsThickness +
366                 (componentsThickness - barsThickness) / 2;
367               bars[j][k] = new FancyBar();
368               bars[j][k].setDataSign (getDataSign());
369               bars[j][k].setBaseValue (x + getLinesFillInteriorBaseValue());
370               if (graphLengths[j][k] > barLowValues[j][k]) {
371                 bars[j][k].setBounds (new Rectangle2D.Float (
372                   x + barLowValues[j][k], compY + k * catDelta,
373                   graphLengths[j][k] - barLowValues[j][k], barsThickness));
374               }
375               else {
376                 bars[j][k].setBounds (new Rectangle2D.Float (
377                   x + graphLengths[j][k], compY + k * catDelta,
378                   barLowValues[j][k] - graphLengths[j][k], barsThickness));
379               }
380               Rectangle2D.Float clipBounds = new Rectangle2D.Float (
381                 bars[j][k].getBounds().x, boundsGraph.y,
382                 bars[j][k].getBounds().width, boundsGraph.height);
383               bars[j][k].setClipBounds (clipBounds);
384               bars[j][k].setLightBounds (
385                 getComponentsLightType() == COMPONENT ? bars[j][k].getBounds() : boundsGraph);
386               bars[j][k].setLightSource (getComponentsLightSource());
387               bars[j][k].setColor (!getComponentsColoringByCat() ?
388                 getBarColors()[j] : getComponentsColorsByCat()[0]);
389               bars[j][k].setOutlineExistence (getOutlineComponents());
390               bars[j][k].setOutlineColor (getOutlineComponentsColor());
391               bars[j][k].setArcw (getBarRoundingRatio() * barsThickness);
392               bars[j][k].setArch (getBarRoundingRatio() * barsThickness);
393               bars[j][k].setWarningRegions (getWarningRegions());
394               bars[j][k].setType (FancyShape.LABELSLEFT);
395               bars[j][k].setGraphBounds (boundsGraph);
396             }
397           }
398         }
399         else {
400           float minY, maxY, tickHalfHeight;
401           minY = getSpaceSizeLocation (MIN).y;
402           tickHalfHeight = getXTicks()[0].height / 2f;
403           maxY = yTicks[0].y + tickHalfHeight;
404           int i = 0;
405           do {
406             if (getLabelsAxisTicksAlignment() == this.BETWEEN) {
407               y = (int)(minY + Math.floor((maxY - minY - setsThickness) / 2f));
408             }
409             else y = (int)Math.floor (maxY - setsThickness / 2f);
410             y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
411             for (int k = 0; k < numCompsPerCat; ++k) {
412               for (int j = 0; j < numSets; ++j) {
413                 int compY = y + j * componentsThickness +
414                   (componentsThickness - barsThickness) / 2;
415                 bars[j][i * numCompsPerCat + k] = new FancyBar();
416                 bars[j][i * numCompsPerCat + k].setDataSign (getDataSign());
417                 bars[j][i * numCompsPerCat + k].setBaseValue (x + getLinesFillInteriorBaseValue());
418                 if (graphLengths[j][i * numCompsPerCat + k] >
419                   barLowValues[j][i * numCompsPerCat + k]) {
420                   bars[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float (
421                     x + barLowValues[j][i * numCompsPerCat + k], compY + k * catDelta,
422                     graphLengths[j][i * numCompsPerCat + k] -
423                     barLowValues[j][i * numCompsPerCat + k], barsThickness));
424                 }
425                 else {
426                   bars[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float (
427                     x + graphLengths[j][i * numCompsPerCat + k], compY + k * catDelta,
428                     barLowValues[j][i * numCompsPerCat + k] -
429                     graphLengths[j][i * numCompsPerCat + k], barsThickness));
430                 }
431                 Rectangle2D.Float clipBounds = new Rectangle2D.Float (
432                   bars[j][i * numCompsPerCat + k].getBounds().x, boundsGraph.y,
433                   bars[j][i * numCompsPerCat + k].getBounds().width, boundsGraph.height);
434                 bars[j][i * numCompsPerCat + k].setClipBounds (clipBounds);
435                 bars[j][i * numCompsPerCat + k].setLightBounds (
436                   getComponentsLightType() == COMPONENT ?
437                   bars[j][i * numCompsPerCat + k].getBounds() : boundsGraph);
438                 bars[j][i * numCompsPerCat + k].setLightSource (getComponentsLightSource());
439                 bars[j][i * numCompsPerCat + k].setColor (!getComponentsColoringByCat() ?
440                   getBarColors()[j] : getComponentsColorsByCat()[i]);
441                 bars[j][i * numCompsPerCat + k].setOutlineExistence (getOutlineComponents());
442                 bars[j][i * numCompsPerCat + k].setOutlineColor (getOutlineComponentsColor());
443                 bars[j][i * numCompsPerCat + k].setArcw (
444                   getBarRoundingRatio() * barsThickness);
445                 bars[j][i * numCompsPerCat + k].setArch (
446                   getBarRoundingRatio() * barsThickness);
447                 bars[j][i * numCompsPerCat + k].setWarningRegions (getWarningRegions());
448                 bars[j][i * numCompsPerCat + k].setType (FancyShape.LABELSLEFT);
449                 bars[j][i * numCompsPerCat + k].setGraphBounds (boundsGraph);
450               }
451             }
452             if (i + 1 == numBars) break;
453             minY = maxY;
454             if (i + 2 == numBars &&
455               getLabelsAxisTicksAlignment() == this.BETWEEN) {
456               maxY = getSpaceSizeLocation (MIN).y + getSpaceSize (MIN).height;
457             }
458             else maxY = yTicks[i + 1].y + tickHalfHeight;
459             ++i;
460           } while (true);
461         }
462       }
463
464       dots = new FancyDot[numSets][numDots * numCompsPerCat];
465       if (numDots > 0) {
466         int x = getSpaceSizeLocation (MIN).x - dotsThickness / 2, y;
467         float catDelta =
468           getSpaceSize (MIN).height / (float)(numDots * numCompsPerCat);
469         if (numDots == 1) {
470           y = getSpaceSizeLocation (MIN).y +
471             (getSpaceSize(MIN).height - setsThickness) / 2;
472           y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
473           for (int k = 0; k < numCompsPerCat; ++k) {
474             for (int j = 0; j < numSets; ++j) {
475               int compY = y + j * componentsThickness +
476                 (componentsThickness - dotsThickness) / 2;
477               dots[j][k] = new FancyDot();
478               dots[j][k].setBounds (new Rectangle2D.Float (
479                 x + graphLengths[j][k], compY + k * catDelta, dotsThickness, dotsThickness));
480               dots[j][k].setClipBounds (dots[j][k].getBounds());
481               dots[j][k].setColor (!getComponentsColoringByCat() ?
482                 getDotColors()[j] : getComponentsColorsByCat()[0]);
483               dots[j][k].setOutlineExistence (getOutlineComponents());
484               dots[j][k].setOutlineColor (getOutlineComponentsColor());
485               dots[j][k].setLightBounds (
486                 getComponentsLightType() == COMPONENT ? dots[j][k].getBounds() : boundsGraph);
487               dots[j][k].setLightSource (getComponentsLightSource());
488               dots[j][k].setWarningRegions (getWarningRegions());
489               dots[j][k].setType (FancyShape.LABELSLEFT);
490             }
491           }
492         }
493         else {
494           float minY, maxY, tickHalfHeight;
495           minY = getSpaceSizeLocation (MIN).y;
496           tickHalfHeight = yTicks[0].height / 2f;
497           maxY = yTicks[0].y + tickHalfHeight;
498           int i = 0;
499           do {
500             if (getLabelsAxisTicksAlignment() == this.BETWEEN) {
501               y = (int)(minY + Math.floor((maxY - minY - setsThickness) / 2f));
502             }
503             else y = (int)Math.floor (maxY - setsThickness / 2f);
504             y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
505             for (int k = 0; k < numCompsPerCat; ++k) {
506               for (int j = 0; j < numSets; ++j) {
507                 int compY = y + j * componentsThickness +
508                   (componentsThickness - dotsThickness) / 2;
509                 dots[j][i * numCompsPerCat + k] = new FancyDot();
510                 dots[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float (
511                   x + graphLengths[j][i * numCompsPerCat + k], compY + k * catDelta,
512                   dotsThickness, dotsThickness));
513                 dots[j][i * numCompsPerCat + k].setClipBounds (
514                   dots[j][i * numCompsPerCat + k].getBounds());
515                 dots[j][i * numCompsPerCat + k].setColor (!getComponentsColoringByCat() ?
516                   getDotColors()[j] : getComponentsColorsByCat()[i]);
517                 dots[j][i * numCompsPerCat + k].setOutlineExistence (getOutlineComponents());
518                 dots[j][i * numCompsPerCat + k].setOutlineColor (getOutlineComponentsColor());
519                 dots[j][i * numCompsPerCat + k].setLightBounds (
520                   getComponentsLightType() == COMPONENT ?
521                   dots[j][i * numCompsPerCat + k].getBounds() : boundsGraph);
522                 dots[j][i * numCompsPerCat + k].setLightSource (getComponentsLightSource());
523                 dots[j][i * numCompsPerCat + k].setWarningRegions (getWarningRegions());
524                 dots[j][i * numCompsPerCat + k].setType (FancyShape.LABELSLEFT);
525               }
526             }
527             if (i + 1 == numDots) break;
528             minY = maxY;
529             if (i + 2 == numDots &&
530               getLabelsAxisTicksAlignment() == this.BETWEEN) {
531               maxY = getSpaceSizeLocation (MIN).y + getSpaceSize (MIN).height;
532             }
533             else maxY = yTicks[i + 1].y + tickHalfHeight;
534             ++i;
535           } while (true);
536         }
537       }
538
539       if ((numCats * numCompsPerCat) < 2 || linesThickness < 1) lines = new FancyLine[0];
540       else {
541         lines = new FancyLine[numSets];
542         for (int i = 0; i < numSets; ++i) {
543           lines[i] = new FancyLine();
544           lines[i].setThickness (linesThickness);
545           lines[i].setFillArea (getLinesFillInterior());
546           lines[i].setColor (getLineColors()[i]);
547           lines[i].setOutlineExistence (getOutlineComponents());
548           lines[i].setOutlineColor (getOutlineComponentsColor());
549           lines[i].setLightSource (getComponentsLightSource());
550           lines[i].setWarningRegions (getWarningRegions());
551           lines[i].setType (FancyShape.LABELSLEFT);
552         }
553         Point firstPoints[] = new Point[numSets];
554         int x = getSpaceSizeLocation (MIN).x, y;
555         float minY, maxY, tickHalfHeight;
556         minY = getSpaceSizeLocation (MIN).y;
557         tickHalfHeight = yTicks[0].height / 2f;
558         maxY = yTicks[0].y + tickHalfHeight;
559         float catDelta =
560           getSpaceSize (MIN).height / (float)(numLinePoints * numCompsPerCat);
561         int i = 0;
562         boolean first = true;
563         do {
564           if (getLabelsAxisTicksAlignment() == this.BETWEEN) {
565             y = (int)(minY + Math.floor((maxY - minY - setsThickness) / 2f));
566           }
567           else y = (int)Math.floor (maxY - setsThickness / 2f);
568           y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
569           for (int k = 0; k < numCompsPerCat; ++k) {
570             for (int j = 0; j < numSets; ++j) {
571               int compY = y + j * componentsThickness + componentsThickness / 2;
572               Point thisPoint = new Point (
573                 (int)(x + graphLengths[j][i * numCompsPerCat + k]), (int)(compY + k * catDelta));
574               if (k == 0 && i == 0) {
575                 if (getLinesFillInterior()) {
576                   firstPoints[j] =
577                     new Point (x + getLinesFillInteriorBaseValue(), (int)(compY + k * catDelta));
578                   lines[j].getLine().moveTo (firstPoints[j].x, firstPoints[j].y);
579                   lines[j].getLine().lineTo (thisPoint.x, thisPoint.y);
580                 }
581                 else {
582                   lines[j].getLine().moveTo (thisPoint.x, thisPoint.y);
583                 }
584               }
585               else {
586                 lines[j].getLine().lineTo (thisPoint.x, thisPoint.y);
587                 if (getLinesFillInterior() &&
588                   k == numCompsPerCat - 1 && i == numLinePoints - 1) {
589                     lines[j].getLine().lineTo (firstPoints[j].x, thisPoint.y);
590                     lines[j].getLine().lineTo (firstPoints[j].x, firstPoints[j].y);
591                 }
592               }
593             }
594           }
595           if (i + 1 == numLinePoints) break;
596           first = false;
597           minY = maxY;
598           if (i + 2 == numLinePoints &&
599             getLabelsAxisTicksAlignment() == this.BETWEEN) {
600             maxY = getSpaceSizeLocation (MIN).y + getSpaceSize (MIN).height;
601           }
602           else maxY = yTicks[i + 1].y + tickHalfHeight;
603           ++i;
604         } while (true);
605         for (int g = 0; g < numSets; ++g) {
606           lines[g].setClipBounds (boundsGraph);
607           Rectangle2D.Float bounds = (Rectangle2D.Float)lines[g].getLine().getBounds2D();
608           lines[g].setLightBounds (getComponentsLightType() == COMPONENT ? bounds : boundsGraph);
609         }
610       }
611     }
612     else {
613       bars = new FancyBar[0][0];
614       dots = new FancyDot[0][0];
615       lines = new FancyLine[0];
616     }
617   }
618
619
620   private void updateAllowAlignment() {
621
622     int[][] graphLengths = getGraphValues();
623     int numBars = 0, numDots = 0, numLinePoints = 0, numGaps = 0;
624     int numSets = graphLengths.length;
625     Rectangle[] yTicks = getYTicks();
626     int numCompsPerCat = 0;
627     int numCats = 0;
628     if (numSets > 0) {
629       numCats = getLabelsAxisTicksAlignment() == BETWEEN ?
630         yTicks.length + 1 : yTicks.length;
631       numBars = getBarsExistence() ? numCats : 0;
632       numDots = getDotsExistence() ? numCats : 0;
633       numLinePoints = getLinesExistence() ? numCats : 0;
634       numGaps = getBetweenComponentsGapExistence() ? numCats : 0;
635       numCompsPerCat = numCats > 0 ? (int)(graphLengths[0].length / numCats) : 0;
636     }
637     if (numSets > 0 && numCats > 0 && numCompsPerCat > 0) {
638       float ratio = getRatio (HEIGHT);
639       int availableThickness = getSpaceSize(MIN).height;
640
641       int betweenComponentsGapThickness = 0;
642       if (numGaps > 0) {
643         betweenComponentsGapThickness =
644           applyRatio (getBetweenComponentsGapThicknessModel(), ratio);
645         betweenComponentsGapThickness =
646           numGaps * betweenComponentsGapThickness <= availableThickness ?
647           betweenComponentsGapThickness : availableThickness / numGaps;
648         availableThickness -= numGaps * betweenComponentsGapThickness;
649       }
650
651       int barsThickness = 0;
652       if (numBars > 0) {
653         barsThickness = applyRatio (getBarsThicknessModel(), ratio);
654         if (numBars * numCompsPerCat * barsThickness <= availableThickness) {
655           float leftover =
656             (availableThickness - barsThickness *
657             (numBars * numCompsPerCat)) /
658             (numBars * numCompsPerCat);
659           barsThickness =
660             barsThickness + (int)(getBarsExcessSpaceFeedbackRatio() * leftover);
661         }
662         else {
663           float numOverlapBarsPerCat =
664             (1 + (1 - getBarsWithinCategoryOverlapRatio()) *
665             (numCompsPerCat - 1));
666           if (numBars * numOverlapBarsPerCat * barsThickness >
667             availableThickness) {
668             barsThickness =
669               (int)(availableThickness / (numBars * numOverlapBarsPerCat));
670           }
671         }
672       }
673       int dotsThickness = 0;
674       if (numDots > 0) {
675         dotsThickness = applyRatio (getDotsThicknessModel(), getRatio (LESSER));
676         if (numDots * numCompsPerCat * dotsThickness <=
677           availableThickness) {
678           float leftover =
679             (availableThickness - dotsThickness *
680             (numDots * numCompsPerCat)) /
681             (numDots * numCompsPerCat);
682           dotsThickness =
683             dotsThickness + (int)(getDotsExcessSpaceFeedbackRatio() * leftover);
684         }
685         else {
686           float numOverlapDotsPerCat =
687             (1 + (1 - getDotsWithinCategoryOverlapRatio()) *
688             (numCompsPerCat - 1));
689           if (numDots * numOverlapDotsPerCat * dotsThickness >
690             availableThickness) {
691             dotsThickness =
692               (int)(availableThickness / (numDots * numOverlapDotsPerCat));
693           }
694         }
695       }
696       int linesThickness = 0;
697       if (numLinePoints > 0) {
698         linesThickness = applyRatio (getLinesThicknessModel(), getRatio (LESSER));
699         if (numLinePoints * numCompsPerCat * linesThickness <=
700           availableThickness) {
701           float leftover =
702             (availableThickness - linesThickness *
703             (numLinePoints * numCompsPerCat)) /
704             (numLinePoints * numCompsPerCat);
705           linesThickness =
706             linesThickness + (int)(getLinesExcessSpaceFeedbackRatio() * leftover);
707         }
708         else {
709           float numOverlapLinesPerCat =
710             (1 + (1 - getLinesWithinCategoryOverlapRatio()) *
711             (numCompsPerCat - 1));
712           if (numLinePoints * numOverlapLinesPerCat * linesThickness >
713             availableThickness) {
714             linesThickness =
715               (int)(availableThickness / (numLinePoints * numOverlapLinesPerCat));
716           }
717         }
718       }
719
720       Rectangle2D.Float boundsGraph = new Rectangle2D.Float (
721         getSpaceSizeLocation (MIN).x, getSpaceSizeLocation (MIN).y,
722         getSpaceSize (MIN).width, getSpaceSize (MIN).height);
723
724       bars = new FancyBar[numSets][numBars * numCompsPerCat];
725       int[][] barLowValues = getBarLowValues();
726       if (numBars > 0) {
727         int x = getSpaceSizeLocation (MIN).x, y;
728         float catDelta =
729           getSpaceSize (MIN).height / (float)(numBars * numCompsPerCat);
730         if (numBars == 1) {
731           y = getSpaceSizeLocation (MIN).y +
732             (getSpaceSize(MIN).height - barsThickness) / 2;
733           y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
734           for (int k = 0; k < numCompsPerCat; ++k) {
735             for (int j = 0; j < numSets; ++j) {
736               bars[j][k] = new FancyBar();
737               bars[j][k].setDataSign (getDataSign());
738               bars[j][k].setBaseValue (x + getLinesFillInteriorBaseValue());
739               if (graphLengths[j][k] > barLowValues[j][k]) {
740                 bars[j][k].setBounds (new Rectangle2D.Float (
741                   x + barLowValues[j][k] + (getOutlineComponents() ? -1 : 0), y + k * catDelta,
742                   graphLengths[j][k] - barLowValues[j][k], barsThickness));
743               }
744               else {
745                 bars[j][k].setBounds (new Rectangle2D.Float (
746                   x + graphLengths[j][k] + (getOutlineComponents() ? -1 : 0),
747                   (int)(y + k * catDelta),
748                   barLowValues[j][k] - graphLengths[j][k], barsThickness));
749               }
750               Rectangle2D.Float clipBounds = new Rectangle2D.Float (
751                 bars[j][k].getBounds().x, boundsGraph.y,
752                 bars[j][k].getBounds().width, boundsGraph.height);
753               bars[j][k].setClipBounds (clipBounds);
754               bars[j][k].setLightBounds (
755                 getComponentsLightType() == COMPONENT ? bars[j][k].getBounds() : boundsGraph);
756               bars[j][k].setLightSource (getComponentsLightSource());
757               bars[j][k].setColor (!getComponentsColoringByCat() ?
758                 getBarColors()[j] : getComponentsColorsByCat()[0]);
759               bars[j][k].setOutlineExistence (getOutlineComponents());
760               bars[j][k].setOutlineColor (getOutlineComponentsColor());
761               bars[j][k].setArcw (getBarRoundingRatio() * barsThickness);
762               bars[j][k].setArch (getBarRoundingRatio() * barsThickness);
763               bars[j][k].setWarningRegions (getWarningRegions());
764               bars[j][k].setType (FancyShape.LABELSLEFT);
765               bars[j][k].setGraphBounds (boundsGraph);
766             }
767           }
768         }
769         else {
770           float minY, maxY, tickHalfHeight;
771           minY = getSpaceSizeLocation (MIN).y;
772           tickHalfHeight = getXTicks()[0].height / 2f;
773           maxY = yTicks[0].y + tickHalfHeight;
774           int i = 0;
775           do {
776             if (getLabelsAxisTicksAlignment() == this.BETWEEN) {
777               y = (int)(minY + Math.floor((maxY - minY - barsThickness) / 2f));
778             }
779             else y = (int)Math.floor (maxY - barsThickness / 2f);
780             y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
781             for (int k = 0; k < numCompsPerCat; ++k) {
782               for (int j = 0; j < numSets; ++j) {
783                 bars[j][i * numCompsPerCat + k] = new FancyBar();
784                 bars[j][i * numCompsPerCat + k].setDataSign (getDataSign());
785                 bars[j][i * numCompsPerCat + k].setBaseValue (x + getLinesFillInteriorBaseValue());
786                 if (graphLengths[j][i * numCompsPerCat + k] >
787                   barLowValues[j][i * numCompsPerCat + k]) {
788                   bars[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float (
789                     x + barLowValues[j][i * numCompsPerCat + k] +
790                     (getOutlineComponents() ? -1 : 0), y + k * catDelta,
791                     graphLengths[j][i * numCompsPerCat + k] -
792                     barLowValues[j][i * numCompsPerCat + k], barsThickness));
793                 }
794                 else {
795                   bars[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float (
796                     x + graphLengths[j][i * numCompsPerCat + k] +
797                     (getOutlineComponents() ? -1 : 0), y + k * catDelta,
798                     barLowValues[j][i * numCompsPerCat + k] -
799                     graphLengths[j][i * numCompsPerCat + k], barsThickness));
800                 }
801                 Rectangle2D.Float clipBounds = new Rectangle2D.Float (
802                   bars[j][i * numCompsPerCat + k].getBounds().x, boundsGraph.y,
803                   bars[j][i * numCompsPerCat + k].getBounds().width, boundsGraph.height);
804                 bars[j][i * numCompsPerCat + k].setClipBounds (clipBounds);
805                 bars[j][i * numCompsPerCat + k].setLightBounds (
806                   getComponentsLightType() == COMPONENT ?
807                   bars[j][i * numCompsPerCat + k].getBounds() : boundsGraph);
808                 bars[j][i * numCompsPerCat + k].setLightSource (getComponentsLightSource());
809                 bars[j][i * numCompsPerCat + k].setColor (!getComponentsColoringByCat() ?
810                   getBarColors()[j] : getComponentsColorsByCat()[i]);
811                 bars[j][i * numCompsPerCat + k].setOutlineExistence (getOutlineComponents());
812                 bars[j][i * numCompsPerCat + k].setOutlineColor (getOutlineComponentsColor());
813                 bars[j][i * numCompsPerCat + k].setArcw (getBarRoundingRatio() * barsThickness);
814                 bars[j][i * numCompsPerCat + k].setArch (getBarRoundingRatio() * barsThickness);
815                 bars[j][i * numCompsPerCat + k].setWarningRegions (getWarningRegions());
816                 bars[j][i * numCompsPerCat + k].setType (FancyShape.LABELSLEFT);
817                 bars[j][i * numCompsPerCat + k].setGraphBounds (boundsGraph);
818               }
819             }
820             if (i + 1 == numBars) break;
821             minY = maxY;
822             if (i + 2 == numBars &&
823               getLabelsAxisTicksAlignment() == this.BETWEEN) {
824               maxY = getSpaceSizeLocation (MIN).y + getSpaceSize (MIN).height;
825             }
826             else maxY = yTicks[i + 1].y + tickHalfHeight;
827             ++i;
828           } while (true);
829         }
830       }
831
832       dots = new FancyDot[numSets][numDots * numCompsPerCat];
833       if (numDots > 0) {
834         int x = getSpaceSizeLocation (MIN).x - dotsThickness / 2, y;
835         float catDelta =
836           getSpaceSize (MIN).height / (float)(numDots * numCompsPerCat);
837         if (numDots == 1) {
838           y = getSpaceSizeLocation (MIN).y +
839             (getSpaceSize(MIN).height - dotsThickness) / 2;
840           y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
841           for (int k = 0; k < numCompsPerCat; ++k) {
842             for (int j = 0; j < numSets; ++j) {
843               dots[j][k] = new FancyDot();
844               dots[j][k].setBounds (new Rectangle2D.Float (
845                 x + graphLengths[j][k], y + k * catDelta,
846                 dotsThickness, dotsThickness));
847               dots[j][k].setClipBounds (dots[j][k].getBounds());
848               dots[j][k].setColor (!getComponentsColoringByCat() ?
849                 getDotColors()[j] : getComponentsColorsByCat()[0]);
850               dots[j][k].setOutlineExistence (getOutlineComponents());
851               dots[j][k].setOutlineColor (getOutlineComponentsColor());
852               dots[j][k].setLightBounds (
853                 getComponentsLightType() == COMPONENT ? dots[j][k].getBounds() : boundsGraph);
854               dots[j][k].setLightSource (getComponentsLightSource());
855               dots[j][k].setWarningRegions (getWarningRegions());
856               dots[j][k].setType (FancyShape.LABELSLEFT);
857             }
858           }
859         }
860         else {
861           float minY, maxY, tickHalfHeight;
862           minY = getSpaceSizeLocation (MIN).y;
863           tickHalfHeight = yTicks[0].height / 2f;
864           maxY = yTicks[0].y + tickHalfHeight;
865           int i = 0;
866           do {
867             if (getLabelsAxisTicksAlignment() == BETWEEN) {
868               y = (int)(minY + Math.floor((maxY - minY - dotsThickness) / 2f));
869             }
870             else y = (int)Math.floor (maxY - dotsThickness / 2f);
871             y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
872             for (int k = 0; k < numCompsPerCat; ++k) {
873               for (int j = 0; j < numSets; ++j) {
874                 dots[j][i * numCompsPerCat + k] = new FancyDot();
875                 dots[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float (
876                   (float)(x + graphLengths[j][i * numCompsPerCat + k]), y + k * catDelta,
877                   dotsThickness, dotsThickness));
878                 dots[j][i * numCompsPerCat + k].setClipBounds (
879                   dots[j][i * numCompsPerCat + k].getBounds());
880                 dots[j][i * numCompsPerCat + k].setColor (!getComponentsColoringByCat() ?
881                   getDotColors()[j] : getComponentsColorsByCat()[i]);
882                 dots[j][i * numCompsPerCat + k].setOutlineExistence (getOutlineComponents());
883                 dots[j][i * numCompsPerCat + k].setOutlineColor (getOutlineComponentsColor());
884                 dots[j][i * numCompsPerCat + k].setLightBounds (
885                   getComponentsLightType() == COMPONENT ?
886                   dots[j][i * numCompsPerCat + k].getBounds() : boundsGraph);
887                 dots[j][i * numCompsPerCat + k].setLightSource (getComponentsLightSource());
888                 dots[j][i * numCompsPerCat + k].setWarningRegions (getWarningRegions());
889                 dots[j][i * numCompsPerCat + k].setType (FancyShape.LABELSLEFT);
890               }
891             }
892             if (i + 1 == numDots) break;
893             minY = maxY;
894             if (i + 2 == numDots &&
895               getLabelsAxisTicksAlignment() == this.BETWEEN) {
896               maxY = getSpaceSizeLocation (MIN).y + getSpaceSize (MIN).height;
897             }
898             else maxY = yTicks[i + 1].y + tickHalfHeight;
899             ++i;
900           } while (true);
901         }
902       }
903
904       if ((numCats * numCompsPerCat) < 2 || linesThickness < 1) lines = new FancyLine[0];
905       else {
906         lines = new FancyLine[numSets];
907         for (int i = 0; i < numSets; ++i) {
908           lines[i] = new FancyLine();
909           lines[i].setThickness (linesThickness);
910           lines[i].setFillArea (getLinesFillInterior());
911           lines[i].setColor (getLineColors()[i]);
912           lines[i].setOutlineExistence (getOutlineComponents());
913           lines[i].setOutlineColor (getOutlineComponentsColor());
914           lines[i].setLightSource (getComponentsLightSource());
915           lines[i].setWarningRegions (getWarningRegions());
916           lines[i].setType (FancyShape.LABELSLEFT);
917         }
918         Point firstPoints[] = new Point[numSets];
919         int x = getSpaceSizeLocation (MIN).x, y;
920         float minY, maxY, tickHalfHeight;
921         minY = getSpaceSizeLocation (MIN).y;
922         tickHalfHeight = yTicks[0].height / 2f;
923         maxY = yTicks[0].y + tickHalfHeight;
924         float catDelta = getSpaceSize (MIN).height / (float)(numLinePoints * numCompsPerCat);
925         int i = 0;
926         do {
927           if (getLabelsAxisTicksAlignment() == this.BETWEEN) {
928             y = (int)(minY + Math.floor((maxY - minY) / 2f));
929           }
930           else y = (int)maxY;
931           y = (int)(y - ((numCompsPerCat - 1) / 2f) * catDelta);
932
933           for (int k = 0; k < numCompsPerCat; ++k) {
934             for (int j = 0; j < numSets; ++j) {
935
936               Point thisPoint = new Point (
937                 (int)(x + graphLengths[j][i * numCompsPerCat + k]),
938                 (int)(y + k * catDelta));
939
940               if (k == 0 && i == 0) {
941                 if (getLinesFillInterior()) {
942                   firstPoints[j] =
943                     new Point (x + getLinesFillInteriorBaseValue(), (int)(y + k * catDelta));
944                   lines[j].getLine().moveTo (firstPoints[j].x, firstPoints[j].y);
945                   lines[j].getLine().lineTo (thisPoint.x, thisPoint.y);
946                 }
947                 else {
948                   lines[j].getLine().moveTo (thisPoint.x, thisPoint.y);
949                 }
950               }
951               else {
952                 lines[j].getLine().lineTo (thisPoint.x, thisPoint.y);
953                 if (getLinesFillInterior() &&
954                   k == numCompsPerCat - 1 && i == numLinePoints - 1) {
955                     lines[j].getLine().lineTo (firstPoints[j].x, thisPoint.y);
956                     lines[j].getLine().lineTo (firstPoints[j].x, firstPoints[j].y);
957                 }
958               }
959             }
960           }
961           if (i + 1 == numLinePoints) break;
962           minY = maxY;
963           if (i + 2 == numLinePoints &&
964             getLabelsAxisTicksAlignment() == this.BETWEEN) {
965             maxY = getSpaceSizeLocation (MIN).y + getSpaceSize (MIN).height;
966           }
967           else maxY = yTicks[i + 1].y + tickHalfHeight;
968           ++i;
969         } while (true);
970         for (int g = 0; g < numSets; ++g) {
971           lines[g].setClipBounds (boundsGraph);
972           Rectangle2D.Float bounds = (Rectangle2D.Float)lines[g].getLine().getBounds2D();
973           lines[g].setLightBounds (
974             getComponentsLightType() == COMPONENT ? bounds : boundsGraph);
975         }
976       }
977     }
978     else {
979       bars = new FancyBar[0][0];
980       dots = new FancyDot[0][0];
981       lines = new FancyLine[0];
982     }
983   }
984 }
Popular Tags