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: import java.awt.image.*;
025:
026: /**
027: * A PieChart2D object is an enclosed are with a title, pie sectors, pie labels, and a legend.
028: * Changes through its set methods are updated upon next repaint() or getImage() calls.
029: */
030: public final class PieChart2D extends Chart2D {
031:
032: private boolean needsUpdate;
033: private PieChartArea chart;
034: private BufferedImage image;
035: private Dimension size;
036: private Dimension imageSize;
037: private Dimension prefSize;
038: private boolean customizePrefSize;
039: private Dimension customPrefSize;
040: private PieChart2DProperties pieChart2DProps;
041: private MultiColorsProperties multiColorsProps;
042: private Dataset dataset;
043:
044: /**
045: * Creates a PieChart2D object with its defaults.
046: */
047: public PieChart2D() {
048:
049: needsUpdate = true;
050: chart = new PieChartArea();
051: size = new Dimension();
052: imageSize = new Dimension();
053: prefSize = null;
054: customizePrefSize = false;
055: customPrefSize = null;
056: }
057:
058: /**
059: * Sets the PieChart2DProperties for this PieChart2D.
060: * @param props The PieChart2DProperties.
061: */
062: public final void setPieChart2DProperties(PieChart2DProperties props) {
063:
064: needsUpdate = true;
065: props.addPieChart2D(this );
066: if (pieChart2DProps != null)
067: pieChart2DProps.removePieChart2D(this );
068: pieChart2DProps = props;
069: }
070:
071: /**
072: * Sets the Dataset for this PieChart2D.
073: * @param d The Dataset.
074: */
075: public final void setDataset(Dataset d) {
076:
077: needsUpdate = true;
078: d.addChart2D(this );
079: if (dataset != null)
080: dataset.removeChart2D(this );
081: dataset = d;
082: }
083:
084: /**
085: * Sets the MultiColorsProperties for this PieChart2D.
086: * @param props The MultiColorsProperties.
087: */
088: public final void setMultiColorsProperties(
089: MultiColorsProperties props) {
090:
091: needsUpdate = true;
092: props.addObject2D(this );
093: if (multiColorsProps != null)
094: multiColorsProps.removeObject2D(this );
095: multiColorsProps = props;
096: }
097:
098: /**
099: * Sets the allocation of space to each component of a pie chart.
100: * There are three components: pieInfo and legend.
101: * The pieInfoW needs to be within 0f and 1f.
102: * The legendW will be 1f - pieInfoW.
103: * Both the pieInfoW and the legendH will be 1f.
104: * @param pieInfoW The ratio of pieInfo width to total.
105: */
106: public final void setLayoutRatios(float pieInfoW) {
107:
108: needsUpdate = true;
109:
110: chart.setPieLabelsToWidthRatio(pieInfoW);
111: chart.setPieLabelsToHeightRatio(1f);
112: chart.setLegendToWidthRatio(1f - pieInfoW);
113: chart.setLegendToHeightRatio(1f);
114:
115: chart.setAutoSetLayoutRatios(true);
116: }
117:
118: /**
119: * Sets a custom preferred size for the chart.
120: * This custom size will override the preferred size calculations that normally occurr.
121: * If null is passed, the preferred size calculations will be reinstated.
122: * @param size The custom preferred size for this chart.
123: */
124: public final void setPreferredSize(Dimension size) {
125:
126: needsUpdate = true;
127: customizePrefSize = size != null;
128: customPrefSize = size;
129: prefSize = null;
130: }
131:
132: /**
133: * Gets the PieChart2DProperties for this PieChart2D.
134: * @return The PieChart2DProperties.
135: */
136: public final PieChart2DProperties getPieChart2DProperties() {
137: return pieChart2DProps;
138: }
139:
140: /**
141: * Gets the Dataset for this PieChart2D.
142: * @return The Dataset.
143: */
144: public final Dataset getDataset() {
145: return dataset;
146: }
147:
148: /**
149: * Gets the MultiColorsProperties for this PieChart2D.
150: * @return The MultiColorsProperties.
151: */
152: public final MultiColorsProperties getMultiColorsProperties() {
153: return multiColorsProps;
154: }
155:
156: /**
157: * Gets a buffered image of the chart.
158: * @return An image of this chart
159: */
160: public final BufferedImage getImage() {
161:
162: if (getSize().width <= 0 || getSize().height <= 0)
163: pack();
164: else
165: updateImage(getSize());
166:
167: if (!chart.getBackgroundExistence()) {
168:
169: Graphics2D imageG2D = image.createGraphics();
170: imageG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
171: RenderingHints.VALUE_ANTIALIAS_ON);
172: chart.paintComponent(imageG2D);
173: Point location = chart.getSizeLocation(chart.MIN);
174: imageSize = chart.getSize(chart.MIN);
175: image = image.getSubimage(location.x, location.y,
176: imageSize.width, imageSize.height);
177: }
178:
179: return image;
180: }
181:
182: /**
183: * Gets the preferred size of the chart.
184: * The preferred size is within the maximum and minimum sizes of the chart.
185: * Much calculation is performed when calling this method.
186: * @return The preferred minimum size of the chart.
187: */
188: public final Dimension getPreferredSize() {
189:
190: updateChart2D();
191: updatePieChartArea();
192:
193: if (!customizePrefSize) {
194:
195: boolean autoModel = chart.getAutoSize(chart.MAXMODEL);
196: boolean autoMin = chart.getAutoSize(chart.MIN);
197: chart.setAutoSizes(true, false);
198: chart.resetPieChartAreaModel(true);
199: chart.setAutoSetLayoutRatios(true);
200: chart.setSize(chart.MAX, getMaximumSize());
201: BufferedImage image = new BufferedImage(
202: getMaximumSize().width, getMaximumSize().height,
203: BufferedImage.TYPE_INT_BGR);
204: Graphics2D imageG2D = image.createGraphics();
205: prefSize = chart.getPrefSize(imageG2D);
206: chart.setAutoSizes(autoModel, autoMin);
207: } else
208: prefSize = customPrefSize;
209:
210: int prefWidth = prefSize.width < getMinimumSize().width ? getMinimumSize().width
211: : prefSize.width;
212: int prefHeight = prefSize.height < getMinimumSize().height ? getMinimumSize().height
213: : prefSize.height;
214: prefSize.setSize(prefWidth, prefHeight);
215:
216: this .size = prefSize;
217: chart.resetPieChartAreaModel(true);
218: chart.setAutoSetLayoutRatios(true);
219: chart.setSize(chart.MAX, size);
220: if (!chart.getBackgroundExistence()) {
221:
222: image = new BufferedImage(getMaximumSize().width,
223: getMaximumSize().height, BufferedImage.TYPE_INT_BGR);
224: Graphics2D imageG2D = image.createGraphics();
225: imageG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
226: RenderingHints.VALUE_ANTIALIAS_ON);
227: chart.updatePieChartArea(imageG2D);
228: } else {
229:
230: image = new BufferedImage(size.width, size.height,
231: BufferedImage.TYPE_INT_BGR);
232: Graphics2D imageG2D = image.createGraphics();
233: imageG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
234: RenderingHints.VALUE_ANTIALIAS_ON);
235: chart.paintComponent(imageG2D);
236: Point location = chart.getSizeLocation(chart.MIN);
237: imageSize = chart.getSize(chart.MIN);
238: image = image.getSubimage(location.x, location.y,
239: imageSize.width, imageSize.height);
240: }
241:
242: needsUpdate = false;
243:
244: return prefSize;
245: }
246:
247: /**
248: * Causes the object to reinintialize to it's preferred size.
249: */
250: public final void pack() {
251:
252: needsUpdate = true;
253: setSize(getPreferredSize());
254: }
255:
256: /**
257: * Validates the properties of this object.
258: * If debug is true then prints a messages indicating whether each property is valid.
259: * Returns true if all the properties were valid and false otherwise.
260: * @param debug If true then will print status messages.
261: * @return If true then valid.
262: */
263: public final boolean validate(boolean debug) {
264:
265: if (debug)
266: System.out.println("Validating PieChart2D");
267:
268: boolean valid = true;
269:
270: if (!validateChart2D(debug))
271: valid = false;
272:
273: if (pieChart2DProps == null) {
274: valid = false;
275: if (debug)
276: System.out.println("PieChart2DProperties is null");
277: } else if (!pieChart2DProps.validate(debug))
278: valid = false;
279:
280: if (dataset == null) {
281: valid = false;
282: if (debug)
283: System.out.println("Dataset is null");
284: } else if (!dataset.validate(debug))
285: valid = false;
286:
287: if (multiColorsProps == null) {
288: valid = false;
289: if (debug)
290: System.out.println("MultiColorsProperties is null");
291: } else if (!multiColorsProps.validate(debug))
292: valid = false;
293:
294: //Restriction: If multi colors customize and num sets > 0, then custom colors > 0
295: if (valid) {
296: if (dataset.getNumSets() > 0
297: && multiColorsProps.getColorsCustomize()
298: && multiColorsProps.getColorsCustom().length < 1) {
299: valid = false;
300: if (debug)
301: System.out
302: .println("Not enough custom colors for MultiColorsProperties");
303: }
304: }
305:
306: if (debug) {
307: if (valid)
308: System.out.println("PieChart2D was valid");
309: else {
310: System.out
311: .println("Possibly unable to check for all invalidities because of early invalidity");
312: System.out.println("PieChart2D was invalid");
313: }
314: }
315:
316: return valid;
317: }
318:
319: /**
320: * Paints the chart.
321: * This is provided for the layout manager to call.
322: * @param g The graphics context for calculations and painting.
323: */
324: public final void paintComponent(Graphics g) {
325:
326: super .paintComponent(g);
327: Graphics2D g2D = (Graphics2D) g;
328:
329: updateImage(getSize());
330:
331: if (!chart.getBackgroundExistence()) {
332:
333: g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
334: RenderingHints.VALUE_ANTIALIAS_ON);
335: chart.paintComponent(g2D);
336: } else
337: g2D.drawImage(image, 0, 0, imageSize.width,
338: imageSize.height, this );
339: }
340:
341: /**
342: * Gets the PieChartArea of this PieChart2D.
343: * @return The PieChartArea of this PieChart2D.
344: */
345: final TitledArea getObjectArea() {
346: return chart;
347: }
348:
349: private boolean getNeedsUpdate() {
350:
351: return (needsUpdate || size.width != getSize().width
352: || size.height != getSize().height
353: || getNeedsUpdateChart2D()
354: || pieChart2DProps.getPieChart2DNeedsUpdate(this )
355: || dataset.getChart2DNeedsUpdate(this ) || multiColorsProps
356: .getObject2DNeedsUpdate(this ));
357: }
358:
359: private void updateImage(Dimension size) {
360:
361: if (prefSize == null)
362: getPreferredSize();
363:
364: if (getNeedsUpdate()) {
365:
366: updateChart2D();
367: updatePieChartArea();
368:
369: this .size = size;
370: chart.setSize(chart.MAX, size);
371:
372: if (!chart.getBackgroundExistence()) {
373:
374: image = new BufferedImage(getMaximumSize().width,
375: getMaximumSize().height,
376: BufferedImage.TYPE_INT_BGR);
377: Graphics2D imageG2D = image.createGraphics();
378: imageG2D.setRenderingHint(
379: RenderingHints.KEY_ANTIALIASING,
380: RenderingHints.VALUE_ANTIALIAS_ON);
381: chart.updatePieChartArea(imageG2D);
382: } else {
383:
384: image = new BufferedImage(size.width, size.height,
385: BufferedImage.TYPE_INT_BGR);
386: Graphics2D imageG2D = image.createGraphics();
387: imageG2D.setRenderingHint(
388: RenderingHints.KEY_ANTIALIASING,
389: RenderingHints.VALUE_ANTIALIAS_ON);
390: chart.paintComponent(imageG2D);
391: Point location = chart.getSizeLocation(chart.MIN);
392: imageSize = chart.getSize(chart.MIN);
393: image = image.getSubimage(location.x, location.y,
394: imageSize.width, imageSize.height);
395: }
396:
397: needsUpdate = false;
398: }
399: }
400:
401: private void updatePieChartArea() {
402:
403: if (pieChart2DProps.getPieChart2DNeedsUpdate(this )
404: || dataset.getChart2DNeedsUpdate(this )
405: || multiColorsProps.getObject2DNeedsUpdate(this )) {
406:
407: pieChart2DProps.updatePieChart2D(this );
408: dataset.updateChart2D(this );
409: multiColorsProps.updateObject2D(this );
410:
411: chart.setDataset(dataset.getOldPieStruct());
412: chart.setDatasetColors(multiColorsProps
413: .getColorsArray(dataset.getNumSets()));
414: chart.setLabelsLinesExistence(pieChart2DProps
415: .getPieLabelsLinesExistence());
416: chart.setLabelsLinesThicknessModel(pieChart2DProps
417: .getPieLabelsLinesThicknessModel());
418: chart.setLabelsLinesColor(pieChart2DProps
419: .getPieLabelsLinesColor());
420: chart.setLabelsLineDotsExistence(pieChart2DProps
421: .getPieLabelsLinesDotsExistence());
422: chart.setLabelsLineDotsThicknessModel(pieChart2DProps
423: .getPieLabelsLinesDotsThicknessModel());
424: chart.setLabelsLineDotsColor(pieChart2DProps
425: .getPieLabelsLinesDotsColor());
426:
427: PieInfoArea pieInfo = chart.getPieInfoArea();
428: pieInfo.setPieLabelsExistence(pieChart2DProps
429: .getPieLabelsExistence());
430: pieInfo.setLabelsType(pieChart2DProps.getPieLabelsType());
431: pieInfo.setBetweenLabelsGapExistence(pieChart2DProps
432: .getPieLabelsBetweenLabelsGapExistence());
433: pieInfo.setBetweenLabelsGapThicknessModel(pieChart2DProps
434: .getPieLabelsBetweenLabelsGapThicknessModel());
435: pieInfo.setLabelsPointsGapExistence(pieChart2DProps
436: .getPieLabelsPointsGapOffsetExistence());
437: pieInfo
438: .setLabelsPointsGapThicknessModel((int) (pieChart2DProps
439: .getPieLabelsPointsGapOffsetModelRatio() * pieChart2DProps
440: .getChartBetweenPieLabelsAndPieGapThicknessModel()));
441: pieInfo.setFontPointModel(pieChart2DProps
442: .getPieLabelsFontPointModel());
443: pieInfo.setFontName(pieChart2DProps.getPieLabelsFontName());
444: pieInfo.setFontColor(pieChart2DProps
445: .getPieLabelsFontColor());
446: pieInfo.setFontStyle(pieChart2DProps
447: .getPieLabelsFontStyle());
448:
449: PieArea pie = pieInfo.getPieArea();
450: pie.setGapExistence(pieChart2DProps
451: .getChartBetweenPieLabelsAndPieGapExistence());
452: pie.setGapThicknessModel(pieChart2DProps
453: .getChartBetweenPieLabelsAndPieGapThicknessModel());
454: pie.setPiePrefSizeModel(pieChart2DProps
455: .getPiePreferredSize());
456: pie.setOutlineSectors(pieChart2DProps
457: .getPieSectorsOutlineExistence());
458: pie.setOutlineSectorsColor(pieChart2DProps
459: .getPieSectorsOutlineColor());
460: pie.setSectorPointDepthRatio(pieChart2DProps
461: .getPieLabelsPointsPieSectorsDepthRatio());
462: pie
463: .setSectorGapPointRatio(pieChart2DProps
464: .getPieLabelsPointsBetweenPieAndLabelGapsDepthRatio());
465: pie.setLightSource(pieChart2DProps
466: .getPieSectorLightSource());
467: }
468: }
469: }
|