001: /**
002: * Chart2D, a java library for drawing two dimensional charts.
003: * Copyright (C) 2001 Jason J. Simas
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: * The author of this library may be contacted at:
019: * E-mail: jjsimas@users.sourceforge.net
020: * Street Address: J J Simas, 887 Tico Road, Ojai, CA 93023-3555 USA
021: */package net.sourceforge.chart2d;
022:
023: import java.awt.*;
024:
025: /**
026: * An y Axis for chart graphs. Supports both vertical and horizontal bar
027: * charts, low number of points line and scatter charts. Bullets can be either
028: * aligned with the labels as in vertical bar charts or between the labels as
029: * int horizontal bar charts. Label font size, type, style, and color are
030: * adjustable. Minimum gaps between labels, ticks, and labels and bullets
031: * may be specified. Ticks size and color may be specified. A title and
032: * its font may also be customized. The title may be justified within the
033: * width of the axis, bottom, top or center. Supports all of bordered areas
034: * customizability except for auto min sizing.
035: * If auto minimum sizing, then the title will likely be far apart from the
036: * axis. It does support everything with auto min sizing disabled. It is
037: * recommended that the auto justification be disabled. The yAxis must be
038: * butted up against a graph area, this is best done manually.
039: * This is its default.
040: */
041: final class YAxisArea extends AxisArea {
042:
043: private VerticalTextListArea textList;
044: private Color ticksColor;
045: private int numTicks;
046: private boolean needsUpdate;
047:
048: /**
049: * Creates a new YAxisArea with the following default settings:<br>
050: * setAutoSizes (false, false);<br>
051: * setAutoJustifys (false, false);<br>
052: * setTitleJustifications (LEFT, CENTER);<br>
053: * setTicksSizeModel (new Dimension (3, 3));<br>
054: * setType (LABELSBOTTOM);<br>
055: * setTextListJustifications (RIGHT, CENTER);<br>
056: * setLabels (new String[0]);<br>
057: * setTicksColor (Color.black);<br>
058: * setNumTicks (0);<br>
059: * setTitleRotateLeft (true);<br>
060: * setBackgroundExistence (false);<br>
061: * setBorderExistences (false, false, false, false);<br>
062: * setGapExistences (false, false, false, false);<br>
063: * textList.setBulletsRelation (TOP);<br>
064: * textList.setAutoJustifys (false, false);<br>
065: * textList.setBorderExistences (false, false, false, false);<br>
066: * textList.setGapExistences (false, false, false, false);<br>
067: * textList.setBackgroundExistence (false);<br>
068: * resetYAxisModel (true);<br>
069: */
070: YAxisArea() {
071:
072: textList = new VerticalTextListArea();
073:
074: setAutoSizes(false, false);
075: setAutoJustifys(false, false);
076: setTitleJustifications(LEFT, CENTER);
077: setTitleRotateLeft(true);
078: setBackgroundExistence(false);
079: setBorderExistence(false);
080: setGapExistence(false);
081: setTicksSizeModel(new Dimension(3, 3));
082: setType(LABELSBOTTOM);
083: setTicksColor(Color.black);
084: setNumTicks(0);
085: textList.setBulletsRelation(TOP);
086: textList.setAutoJustifys(false, false);
087: textList.setBorderExistence(false);
088: textList.setGapExistence(false);
089: textList.setBackgroundExistence(false);
090: textList.setBulletsOutline(false);
091: resetYAxisModel(true);
092: needsUpdate = true;
093: }
094:
095: /**
096: * Specifies the type of the y Axis. The type refers to what type of chart
097: * it supports. In any chart the objects are plotted against one side,
098: * the values side, the values side has raw numbers like 0, 100, 200, etc.
099: * The other side, the labels side, has the labels for the data being plotted,
100: * like September, November, etc. If the labels side is along the bottom
101: * of the graph, then set the type to LABELSBOTTOM. If the labels side is
102: * along the left/right side of the graph then set the type to LABELSLEFT.
103: * @param type Whether this axis is used for labels bottom or labels left
104: * applications.
105: */
106: final void setType(int type) {
107:
108: needsUpdate = true;
109: if (type == LABELSBOTTOM)
110: textList.setBulletsAlignment(CENTERED);
111: else
112: textList.setBulletsAlignment(BETWEEN);
113: }
114:
115: /**
116: * The color for the ticks.
117: * @param color The y Axis tick color.
118: */
119: final void setTicksColor(Color color) {
120:
121: needsUpdate = true;
122: ticksColor = color;
123: }
124:
125: /**
126: * The vertical alignment of the ticks respective to the labels. The
127: * bullets can either be place in line with each label, or in in line with
128: * the middle of the space between each label. That is, bullets can be
129: * centered in the middle of the label, or placed between each label.
130: * @param alignment With values of either Area.CENTERED or Area.BETWEEN
131: */
132: final void setTicksAlignment(int alignment) {
133:
134: textList.setBulletsAlignment(alignment);
135: }
136:
137: /**
138: * The number of ticks should be equal to the number of x axis labels at all
139: * times, EXCEPT with a type of chart with a (LABELSBOTTOM x axis and a
140: * graph components alignment is true).
141: * @param num The number of y axis ticks.
142: */
143: final void setNumTicks(int num) {
144:
145: needsUpdate = true;
146: numTicks = num;
147: }
148:
149: /**
150: * The model size for the ticks. If auto maximum sizing is enabled,
151: * then the actual tick size can grow and shrink; in this case a ratio based
152: * on the maximum area size / model area size is computed and applied to the
153: * model size in order to find the actual size. With maximum sizing
154: * disabled, the actual size is the model size.
155: * @param size The model size for the ticks. [Do not pass null]
156: */
157: final void setTicksSizeModel(Dimension size) {
158:
159: needsUpdate = true;
160: textList.setBulletsSizeModel(size);
161: }
162:
163: /**
164: * The model size for the ticks. If auto maximum sizing is enabled,
165: * then the actual tick size can grow and shrink; in this case a ratio based
166: * on the maximum area size / model area size is computed and applied to the
167: * model size in order to find the actual size. With maximum sizing
168: * disabled, the actual size is the model size.
169: * @return The model size for the ticks. [Do not pass null]
170: */
171: final Dimension getTicksSizeModel() {
172: return textList.getBulletsSizeModel();
173: }
174:
175: /**
176: * The existence of a gap between each label and the next. If the gap does
177: * not exist, then it will not be used in calculations.
178: * @param existence The existence of a gap between each label and the next. If
179: * true, then they do.
180: */
181: final void setBetweenLabelsGapExistence(boolean existence) {
182:
183: needsUpdate = true;
184: textList.setBetweenLabelsGapExistence(existence);
185: }
186:
187: /**
188: * The existence of a gap between each tick and the next. If the gap does
189: * not exist, then it will not be used in calculations.
190: * @param existence The existence of a gap between each tick and the next. If
191: * true, then they do.
192: */
193: final void setBetweenTicksGapExistence(boolean existence) {
194:
195: needsUpdate = true;
196: textList.setBetweenBulletsGapExistence(existence);
197: }
198:
199: /**
200: * The model thickness for the gap between each tick. If auto maximum sizing
201: * is enabled,
202: * then the actual thickness size can grow and shrink; in this case a ratio
203: * based
204: * on the maximum area size / model area size is computed and applied to the
205: * model thickness in order to find the actual thickness. With maximum sizing
206: * disabled, the actual thickness is the model thickness.
207: * @param gap The model thickness for the gap between each tick.
208: */
209: final void setBetweenTicksGapThicknessModel(int gap) {
210:
211: needsUpdate = true;
212: textList.setBetweenBulletsGapThicknessModel(gap);
213: }
214:
215: /**
216: * The existence of a gap between the row of labels and the row of ticks. If
217: * the gap does
218: * not exist, then it will not be used in calculations.
219: * @param existence The existence of a gap between the labels and ticks. If
220: * true, then they do.
221: */
222: final void setBetweenTicksAndLabelsGapExistence(boolean existence) {
223:
224: needsUpdate = true;
225: textList.setBetweenBulletsAndLabelsGapExistence(existence);
226: }
227:
228: /**
229: * The model thickness for the gap between the row of labels and the row of
230: * ticks. If auto maximum sizing
231: * is enabled,
232: * then the actual thickness size can grow and shrink; in this case a ratio
233: * based
234: * on the maximum area size / model area size is computed and applied to the
235: * model thickness in order to find the actual thickness. With maximum sizing
236: * disabled, the actual thickness is the model thickness. This thickness
237: * is not used in calculations if either the ticks or labels do not exist.
238: * @param gap The model thickness for the gap between the labels and ticks.
239: */
240: final void setBetweenTicksAndLabelsGapThicknessModel(int gap) {
241:
242: needsUpdate = true;
243: textList.setBetweenBulletsAndLabelsGapThicknessModel(gap);
244: }
245:
246: /**
247: * Returns the Text List Area for this Y Axis.
248: * Get for advanced configuration of the y axis.
249: * @return This y axis component.
250: */
251: final VerticalTextListArea getTextList() {
252:
253: return textList;
254: }
255:
256: /**
257: * The labels of the axis. The lowest order array label is the top
258: * most label.
259: * @param g2D The graphics context to use for calculations.
260: * @return The text labels. This will never be null.
261: */
262: final TextArea[] getLabels(Graphics2D g2D) {
263:
264: updateYAxisArea(g2D);
265: return textList.getLabels(g2D);
266: }
267:
268: /**
269: * The bounds of the ticks. The bounds of the ticks specify the locations
270: * and sizes of each actual tick. The lowest order array tick is the top
271: * most tick.
272: * @param g2D The graphics context to use for calculations.
273: * @return The bounds of the ticks. This will never be null.
274: */
275: final Rectangle[] getTicks(Graphics2D g2D) {
276:
277: updateYAxisArea(g2D);
278: return textList.getBullets(g2D);
279: }
280:
281: /**
282: * Returns the model thickness of the gap between the ticks.
283: * @return The thickness.
284: */
285: final int getBetweenTicksGapThicknessModel() {
286:
287: return textList.getBetweenBulletsGapThicknessModel();
288: }
289:
290: /**
291: * Returns the color of the ticks.
292: * @return The color.
293: */
294: final Color getTicksColor() {
295:
296: return ticksColor;
297: }
298:
299: /**
300: * Returns how the ticks are aligned with respect to the labels.
301: * @return int With values of either Area.CENTERED or Area.BETWEEN
302: */
303: final int getTicksAlignment() {
304:
305: return textList.getBulletsAlignment();
306: }
307:
308: /**
309: * Indicates whether some property of this class has changed.
310: * @return True if some property has changed.
311: */
312: final boolean getYAxisAreaNeedsUpdate() {
313:
314: return (needsUpdate || getTitledAreaNeedsUpdate() || textList
315: .getVerticalTextListAreaNeedsUpdate());
316: }
317:
318: /**
319: * Updates this parent's variables, and this' variables.
320: * @param g2D The graphics context to use for calculations.
321: */
322: final void updateYAxisArea(Graphics2D g2D) {
323:
324: if (getYAxisAreaNeedsUpdate()) {
325: updateTitledArea(g2D);
326: update(g2D);
327: textList.updateVerticalTextListArea(g2D);
328: }
329: needsUpdate = false;
330: }
331:
332: /**
333: * Resets the model for this class. The model is used for shrinking and
334: * growing of its components based on the maximum size of this class. If this
335: * method is called, then the next time the maximum size is set, this classes
336: * model maximum size will be made equal to the new maximum size. Effectively
337: * what this does is ensure that whenever this objects maximum size is equal
338: * to the one given, then all of the components will take on their default
339: * model sizes. Note: This is only useful when auto model max sizing is
340: * disabled.
341: * @param reset True causes the max model size to be set upon the next max
342: * sizing.
343: */
344: final void resetYAxisModel(boolean reset) {
345:
346: needsUpdate = true;
347: resetTitledAreaModel(reset);
348: textList.resetVerticalTextListAreaModel(reset);
349: }
350:
351: /**
352: * Paints all the components of this class. First all variables are updated.
353: * @param g2D The graphics context for calculations and painting.
354: */
355: final void paintComponent(Graphics2D g2D) {
356:
357: updateYAxisArea(g2D);
358: super .paintComponent(g2D);
359: textList.paintComponent(g2D);
360: }
361:
362: private void update(Graphics2D g2D) {
363: textList.setCustomRatio(WIDTH, true, getRatio(WIDTH));
364: textList.setCustomRatio(HEIGHT, true, getRatio(HEIGHT));
365: updateTickColors();
366: updateMaxTextList(g2D);
367: textList.updateVerticalTextListArea(g2D);
368: updateMinSizes(g2D);
369: updateMinTextList(g2D);
370: }
371:
372: private void updateTickColors() {
373:
374: Color[] tickColors = new Color[numTicks];
375: for (int i = 0; i < numTicks; ++i) {
376:
377: tickColors[i] = ticksColor;
378: }
379:
380: textList.setBulletColors(tickColors);
381: }
382:
383: private void updateMaxTextList(Graphics2D g2D) {
384:
385: textList.setAllowSelfSize(true);
386: textList.setAutoSizes(getAutoSize(MAXMODEL), false);
387: Rectangle maxBounds = getMaxEntitledSpaceBounds(g2D);
388: textList.setSize(MAX, maxBounds.getSize());
389: textList.setSizeLocation(MAX, maxBounds.getLocation());
390: }
391:
392: private void updateMinSizes(Graphics2D g2D) {
393:
394: if (!getAutoSize(MIN)) {
395: Dimension titleSize = getTitleSize(MIN, g2D);
396: Dimension textListSize = textList.getSize(MIN);
397: int minWidth;
398: if (titleSize.width > 0) {
399: minWidth = titleSize.width
400: + getBetweenTitleAndSpaceGapThickness(g2D)
401: + textListSize.width;
402: } else
403: minWidth = titleSize.width + textListSize.width;
404: int minHeight = titleSize.height > textListSize.height ? titleSize.height
405: : textListSize.height;
406: setSpaceSize(MIN, new Dimension(minWidth, minHeight));
407: }
408: }
409:
410: private void updateMinTextList(Graphics2D g2D) {
411:
412: int spaceHeight = textList.getSize(MIN).height;
413: textList.setAllowSelfSize(false);
414: spaceHeight = spaceHeight < getSpaceSize(MIN).height ? getSpaceSize(MIN).height
415: : spaceHeight;
416: int betweenHeight = textList.getSize(MIN).height
417: - textList.getSpaceSize(MIN).height;
418: spaceHeight = spaceHeight - betweenHeight;
419: textList.setSpaceSize(MIN, new Dimension(textList
420: .getSpaceSize(MIN).width, spaceHeight));
421:
422: int spaceY = getSpaceSizeLocation(MIN).y;
423: int spaceX;
424: int betweenWidth = textList.getSize(MIN).width
425: - textList.getSpaceSize(MIN).width;
426: if (textList.getJustifications(HORIZONTAL) == LEFT)
427: spaceX = getSpaceSizeLocation(MIN).x
428: + getTitleSize(MIN, g2D).width
429: + getBetweenTitleAndSpaceGapThickness(g2D)
430: + textList.getSpaceSize(MIN).width + betweenWidth
431: / 2;
432: else
433: spaceX = getSpaceSizeLocation(MIN).x
434: + getSpaceSize(MIN).width
435: - textList.getSize(MIN).width + betweenWidth / 2;
436:
437: textList.setSpaceSizeLocation(MIN, new Point(spaceX, spaceY));
438: }
439: }
|