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 x 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 horizontal bar charts or between the labels as
029: * int vertical 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 withing the
033: * width of the axis, left, right or center.
034: * Supports all of bordered areas 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 xAxis must be
038: * butted up against a graph area, this is best done manually.
039: * This is its default.
040: */
041: final class XAxisArea extends AxisArea {
042:
043: private HorizontalTextListArea textList;
044: private Color ticksColor;
045: private int numTicks;
046: private boolean needsUpdate;
047:
048: /**
049: * Creates a new xAxis Area with the default settings.
050: */
051: XAxisArea() {
052:
053: textList = new HorizontalTextListArea();
054:
055: setAutoSizes(false, false);
056: setAutoJustifys(false, false);
057: setTitleJustifications(CENTER, BOTTOM);
058: setBackgroundExistence(false);
059: setBorderExistence(false);
060: setGapExistence(false);
061:
062: setTicksSizeModel(new Dimension(3, 3));
063: setType(LABELSBOTTOM);
064: setTicksColor(Color.black);
065: setNumTicks(0);
066:
067: textList.setBulletsRelation(TOP);
068: textList.setAutoJustifys(false, false);
069: textList.setBorderExistence(false);
070: textList.setGapExistence(false);
071: textList.setBackgroundExistence(false);
072: textList.setBulletsOutline(false);
073:
074: resetXAxisModel(true);
075: needsUpdate = true;
076: }
077:
078: /**
079: * Specifies the type of the x Axis. The type refers to what type of chart
080: * it supports. In any chart the objects are plotted against one side,
081: * the values side, the values side has raw numbers like 0, 100, 200, etc.
082: * The other side, the labels side, has the labels for the data being plotted,
083: * like September, November, etc. If the labels side is along the bottom
084: * of the graph, then set the type to LABELSBOTTOM. If the labels side is
085: * along the left/right side of the graph then set the type to LABELSLEFT.
086: * @param type Whether this axis is used for labels bottom or labels left
087: * applications.
088: */
089: final void setType(int type) {
090:
091: needsUpdate = true;
092: if (type == LABELSBOTTOM)
093: textList.setBulletsAlignment(BETWEEN);
094: else
095: textList.setBulletsAlignment(CENTERED);
096: }
097:
098: /**
099: * The color for the ticks.
100: * @param color The x Axis tick color.
101: */
102: final void setTicksColor(Color color) {
103:
104: needsUpdate = true;
105: ticksColor = color;
106: }
107:
108: /**
109: * The horizontal alignment of the ticks respective to the labels. The
110: * bullets can either be place in line with each label, or in in line with
111: * the middle of the space between each label. That is, bullets can be
112: * centered in the middle of the label, or placed between each label.
113: * @param alignment With values of either Area.CENTERED or Area.BETWEEN
114: */
115: final void setTicksAlignment(int alignment) {
116:
117: textList.setBulletsAlignment(alignment);
118: }
119:
120: /**
121: * The number of ticks should be equal to the number of x axis labels at all
122: * times, EXCEPT with a type of chart with a (LABELSBOTTOM x axis and a
123: * graph components alignment is true).
124: * @param num The number of x axis ticks.
125: */
126: final void setNumTicks(int num) {
127:
128: needsUpdate = true;
129: numTicks = num;
130: }
131:
132: /**
133: * The model size for the ticks. If auto maximum sizing is enabled,
134: * then the actual tick size can grow and shrink; in this case a ratio based
135: * on the maximum area size / model area size is computed and applied to the
136: * model size in order to find the actual size. With maximum sizing
137: * disabled, the actual size is the model size.
138: * @param size The model size for the ticks. [Do not pass null]
139: */
140: final void setTicksSizeModel(Dimension size) {
141:
142: needsUpdate = true;
143: textList.setBulletsSizeModel(size);
144: }
145:
146: /**
147: * The model size for the ticks. If auto maximum sizing is enabled,
148: * then the actual tick size can grow and shrink; in this case a ratio based
149: * on the maximum area size / model area size is computed and applied to the
150: * model size in order to find the actual size. With maximum sizing
151: * disabled, the actual size is the model size.
152: * @return The model size for the ticks. [Do not pass null]
153: */
154: final Dimension getTicksSizeModel() {
155: return textList.getBulletsSizeModel();
156: }
157:
158: /**
159: * The existence of a gap between each tick and the next. If the gap does
160: * not exist, then it will not be used in calculations.
161: * @param existence The existence of a gap between each tick and the next. If
162: * true, then they do.
163: */
164: final void setBetweenTicksGapExistence(boolean existence) {
165:
166: needsUpdate = true;
167: textList.setBetweenBulletsGapExistence(existence);
168: }
169:
170: /**
171: * The model thickness for the gap between each tick. If auto maximum sizing
172: * is enabled,
173: * then the actual thickness size can grow and shrink; in this case a ratio
174: * based
175: * on the maximum area size / model area size is computed and applied to the
176: * model thickness in order to find the actual thickness. With maximum sizing
177: * disabled, the actual thickness is the model thickness.
178: * @param gap The model thickness for the gap between each tick.
179: */
180: final void setBetweenTicksGapThicknessModel(int gap) {
181:
182: needsUpdate = true;
183: textList.setBetweenBulletsGapThicknessModel(gap);
184: }
185:
186: /**
187: * The existence of a gap between the row of labels and the row of ticks. If
188: * the gap does
189: * not exist, then it will not be used in calculations.
190: * @param existence The existence of a gap between the labels and ticks. If
191: * true, then they do.
192: */
193: final void setBetweenTicksAndLabelsGapExistence(boolean existence) {
194:
195: needsUpdate = true;
196: textList.setBetweenBulletsAndLabelsGapExistence(existence);
197: }
198:
199: /**
200: * The model thickness for the gap between the row of labels and the row of
201: * ticks. If auto maximum sizing
202: * is enabled,
203: * then the actual thickness size can grow and shrink; in this case a ratio
204: * based
205: * on the maximum area size / model area size is computed and applied to the
206: * model thickness in order to find the actual thickness. With maximum sizing
207: * disabled, the actual thickness is the model thickness. This thickness
208: * is not used in calculations if either the ticks or labels do not exist.
209: * @param gap The model thickness for the gap between the labels and ticks.
210: */
211: final void setBetweenTicksAndLabelsGapThicknessModel(int gap) {
212:
213: needsUpdate = true;
214: textList.setBetweenBulletsAndLabelsGapThicknessModel(gap);
215: }
216:
217: /**
218: * Returns the HorizontalTextListArea for this X Axis.
219: * Get for standard configuration of the x axis.
220: * @return This x axis component.
221: */
222: final HorizontalTextListArea getTextList() {
223:
224: return textList;
225: }
226:
227: /**
228: * The labels of the axis. The lowest order array label is the top
229: * most label.
230: * @param g2D The graphics context to use for calculations.
231: * @return The text labels; this will never be null.
232: */
233: final TextArea[] getLabels(Graphics2D g2D) {
234:
235: updateXAxisArea(g2D);
236: return textList.getLabels(g2D);
237: }
238:
239: /**
240: * The bounds of the ticks. The bounds of the ticks specify the locations
241: * and sizes of each actual tick. The lowest order array tick is the left
242: * most tick.
243: * @param g2D The graphics context to use for calculations.
244: * @return The bounds of the ticks. This will never be null.
245: */
246: final Rectangle[] getTicks(Graphics2D g2D) {
247:
248: updateXAxisArea(g2D);
249: return textList.getBullets(g2D);
250: }
251:
252: /**
253: * Returns the model thickness of the gap between the ticks.
254: * @return The thickness.
255: */
256: final int getBetweenTicksGapThicknessModel() {
257:
258: return textList.getBetweenBulletsGapThicknessModel();
259: }
260:
261: /**
262: * Returns the color of the ticks.
263: * @return The color.
264: */
265: final Color getTicksColor() {
266:
267: return ticksColor;
268: }
269:
270: /**
271: * Returns how the ticks are aligned with respect to the labels.
272: * @return int With values of either Area.CENTERED or Area.BETWEEN
273: */
274: final int getTicksAlignment() {
275:
276: return textList.getBulletsAlignment();
277: }
278:
279: /**
280: * Indicates whether some property of this class has changed.
281: * @return True if some property has changed.
282: */
283: final boolean getXAxisAreaNeedsUpdate() {
284:
285: return (needsUpdate || getTitledAreaNeedsUpdate() || textList
286: .getHorizontalTextListAreaNeedsUpdate());
287: }
288:
289: /**
290: * Updates this parent's variables, and this' variables.
291: * @param g2D The graphics context to use for calculations.
292: */
293: final void updateXAxisArea(Graphics2D g2D) {
294:
295: if (getXAxisAreaNeedsUpdate()) {
296: updateTitledArea(g2D);
297: update(g2D);
298: textList.updateHorizontalTextListArea(g2D);
299: }
300: needsUpdate = false;
301: }
302:
303: /**
304: * Resets the model for this class. The model is used for shrinking and
305: * growing of its components based on the maximum size of this class. If this
306: * method is called, then the next time the maximum size is set, this classes
307: * model maximum size will be made equal to the new maximum size. Effectively
308: * what this does is ensure that whenever this objects maximum size is equal
309: * to the one given, then all of the components will take on their default
310: * model sizes. Note: This is only useful when auto model max sizing is
311: * disabled.
312: * @param reset True causes the max model size to be set upon the next max
313: * sizing.
314: */
315: final void resetXAxisModel(boolean reset) {
316:
317: needsUpdate = true;
318: resetTitledAreaModel(reset);
319: textList.resetHorizontalTextListAreaModel(reset);
320: }
321:
322: /**
323: * Paints all the components of this class. First all variables are updated.
324: * @param g2D The graphics context for calculations and painting.
325: */
326: final void paintComponent(Graphics2D g2D) {
327:
328: updateXAxisArea(g2D);
329: super .paintComponent(g2D);
330: textList.paintComponent(g2D);
331: }
332:
333: private void update(Graphics2D g2D) {
334: textList.setCustomRatio(WIDTH, true, getRatio(WIDTH));
335: textList.setCustomRatio(HEIGHT, true, getRatio(HEIGHT));
336: updateTickColors();
337: updateMaxTextList(g2D);
338: textList.updateHorizontalTextListArea(g2D);
339: updateMinSizes(g2D);
340: updateMinTextList(g2D);
341: }
342:
343: private void updateTickColors() {
344:
345: Color[] tickColors = new Color[numTicks];
346: for (int i = 0; i < numTicks; ++i) {
347:
348: tickColors[i] = ticksColor;
349: }
350:
351: textList.setBulletColors(tickColors);
352: }
353:
354: private void updateMaxTextList(Graphics2D g2D) {
355:
356: textList.setAllowSelfSize(true);
357: textList.setAutoSizes(getAutoSize(MAXMODEL), false);
358: Rectangle maxBounds = getMaxEntitledSpaceBounds(g2D);
359: textList.setSize(MAX, maxBounds.getSize());
360: textList.setSizeLocation(MAX, maxBounds.getLocation());
361: }
362:
363: private void updateMinSizes(Graphics2D g2D) {
364:
365: if (!getAutoSize(MIN)) {
366: Dimension titleSize = getTitleSize(MIN, g2D);
367: Dimension textListSize = textList.getSize(MIN);
368: int minWidth = titleSize.width > textListSize.width ? titleSize.width
369: : textListSize.width;
370: int minHeight;
371: if (titleSize.height > 0) {
372: minHeight = titleSize.height
373: + getBetweenTitleAndSpaceGapThickness(g2D)
374: + textListSize.height;
375: } else
376: minHeight = titleSize.height + textListSize.height;
377: setSpaceSize(MIN, new Dimension(minWidth, minHeight));
378: }
379: }
380:
381: private void updateMinTextList(Graphics2D g2D) {
382:
383: int spaceWidth = textList.getSize(MIN).width;
384: textList.setAllowSelfSize(false);
385: spaceWidth = spaceWidth < getSpaceSize(MIN).width ? getSpaceSize(MIN).width
386: : spaceWidth;
387: int betweenWidth = textList.getSize(MIN).width
388: - textList.getSpaceSize(MIN).width;
389: spaceWidth = spaceWidth - betweenWidth;
390: textList.setSpaceSize(MIN, new Dimension(spaceWidth, textList
391: .getSpaceSize(MIN).height));
392:
393: int spaceX = getSpaceSizeLocation(MIN).x;
394: int spaceY;
395: int betweenHeight = textList.getSize(MIN).height
396: - textList.getSpaceSize(MIN).height;
397: if (textList.getJustifications(VERTICAL) == TOP)
398: spaceY = getSpaceSizeLocation(MIN).y + betweenHeight / 2;
399: else
400: spaceY = getSpaceSizeLocation(MIN).y
401: + getSpaceSize(MIN).height
402: - getTitleSize(MIN, g2D).height
403: - getBetweenTitleAndSpaceGapThickness(g2D)
404: - textList.getSize(MIN).height + betweenHeight / 2;
405:
406: textList.setSpaceSizeLocation(MIN, new Point(spaceX, spaceY));
407: }
408: }
|