001: /***********************************************************************************************
002: * Copyright 2002 (C) Nathaniel G. Auvil. All Rights Reserved.
003: *
004: * Redistribution and use of this software and associated documentation ("Software"), with or
005: * without modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain copyright statements and notices.
008: * Redistributions must also contain a copy of this document.
009: *
010: * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
011: * conditions and the following disclaimer in the documentation and/or other materials
012: * provided with the distribution.
013: *
014: * 3. The name "jCharts" or "Nathaniel G. Auvil" must not be used to endorse or promote
015: * products derived from this Software without prior written permission of Nathaniel G.
016: * Auvil. For written permission, please contact nathaniel_auvil@users.sourceforge.net
017: *
018: * 4. Products derived from this Software may not be called "jCharts" nor may "jCharts" appear
019: * in their names without prior written permission of Nathaniel G. Auvil. jCharts is a
020: * registered trademark of Nathaniel G. Auvil.
021: *
022: * 5. Due credit should be given to the jCharts Project (http://jcharts.sourceforge.net/).
023: *
024: * THIS SOFTWARE IS PROVIDED BY Nathaniel G. Auvil AND CONTRIBUTORS ``AS IS'' AND ANY
025: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
026: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
027: * jCharts OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
028: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
029: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
030: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,STRICT LIABILITY, OR TORT
031: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
032: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
033: ************************************************************************************************/package org.krysalis.jcharts.axisChart;
034:
035: import org.krysalis.jcharts.chartData.interfaces.IAxisChartDataSet;
036: import org.krysalis.jcharts.imageMap.RectMapArea;
037: import org.krysalis.jcharts.properties.*;
038: import org.krysalis.jcharts.axisChart.customRenderers.axisValue.AxisValueRenderEvent;
039:
040: import java.awt.*;
041: import java.awt.geom.Rectangle2D;
042:
043: /*************************************************************************************
044: *
045: * @author Nathaniel Auvil
046: * @version $Id: ClusteredBarChart.java,v 1.2 2003/12/07 14:04:27 nathaniel_auvil Exp $
047: ************************************************************************************/
048: abstract class ClusteredBarChart {
049:
050: /********************************************************************************************
051: * Draws the chart
052: * uses Rectangle2D......keep having rounding problems.
053: *
054: * @param axisChart
055: * @param iAxisChartDataSet
056: *********************************************************************************************/
057: static void render(AxisChart axisChart,
058: IAxisChartDataSet iAxisChartDataSet) {
059: Graphics2D g2d = axisChart.getGraphics2D();
060: ClusteredBarChartProperties clusteredBarChartProperties = (ClusteredBarChartProperties) iAxisChartDataSet
061: .getChartTypeProperties();
062:
063: float barGroupWidth;
064: float barWidth;
065:
066: //---y axis position on screen to start drawing.
067: float startingY;
068: float startingX;
069: float width;
070: float height;
071:
072: DataAxisProperties dataAxisProperties;
073: if (axisChart.getAxisProperties().isPlotHorizontal()) {
074: dataAxisProperties = (DataAxisProperties) axisChart
075: .getAxisProperties().getXAxisProperties();
076:
077: barGroupWidth = axisChart.getYAxis().getScalePixelWidth()
078: * clusteredBarChartProperties.getPercentage();
079: barWidth = barGroupWidth
080: / iAxisChartDataSet.getNumberOfDataSets();
081:
082: //---where the group of bars starts
083: startingX = axisChart.getXAxis().getZeroLineCoordinate();
084: startingY = axisChart.getYAxis().getLastTickY()
085: - (barGroupWidth / 2);
086: width = 0;
087: height = barWidth;
088: Rectangle2D.Float rectangle = new Rectangle2D.Float(
089: startingX, startingY, width, height);
090:
091: horizontalPlot(axisChart, iAxisChartDataSet,
092: clusteredBarChartProperties, dataAxisProperties,
093: g2d, rectangle, startingX, startingY, barWidth);
094: } else {
095: dataAxisProperties = (DataAxisProperties) axisChart
096: .getAxisProperties().getYAxisProperties();
097:
098: barGroupWidth = axisChart.getXAxis().getScalePixelWidth()
099: * clusteredBarChartProperties.getPercentage();
100: barWidth = barGroupWidth
101: / iAxisChartDataSet.getNumberOfDataSets();
102:
103: //---where the group of bars starts
104: startingX = axisChart.getXAxis().getTickStart()
105: - (barGroupWidth / 2);
106: startingY = axisChart.getYAxis().getZeroLineCoordinate();
107: width = barWidth;
108: height = 0;
109: Rectangle2D.Float rectangle = new Rectangle2D.Float(
110: startingX, startingY, width, height);
111:
112: verticalPlot(axisChart, iAxisChartDataSet,
113: clusteredBarChartProperties, dataAxisProperties,
114: g2d, rectangle, startingX, startingY, barWidth);
115: }
116: }
117:
118: /*******************************************************************************************
119: *
120: *
121: * @param axisChart
122: * @param iAxisChartDataSet
123: * @param clusteredBarChartProperties
124: * @param dataAxisProperties
125: * @param g2d
126: * @param rectangle
127: * @param startingX
128: * @param startingY
129: * @param barWidth
130: ********************************************************************************************/
131: private static void horizontalPlot(AxisChart axisChart,
132: IAxisChartDataSet iAxisChartDataSet,
133: ClusteredBarChartProperties clusteredBarChartProperties,
134: DataAxisProperties dataAxisProperties, Graphics2D g2d,
135: Rectangle2D.Float rectangle, float startingX,
136: float startingY, float barWidth) {
137: int imageMapLabelIndex = axisChart.getYAxis()
138: .getNumberOfScaleItems() - 1;
139:
140: //---setup the total area rectangle
141: Rectangle2D.Float totalItemArea = new Rectangle2D.Float();
142: totalItemArea.y = axisChart.getYAxis().getOrigin()
143: - axisChart.getYAxis().getPixelLength() + 1;
144: totalItemArea.height = axisChart.getYAxis()
145: .getScalePixelWidth() - 1;
146: totalItemArea.x = axisChart.getXAxis().getOrigin() + 1;
147: totalItemArea.width = axisChart.getXAxis().getPixelLength() - 1;
148:
149: //---reuse the same Object for pre and post render events.
150: AxisValueRenderEvent axisValueRenderEvent = new AxisValueRenderEvent(
151: axisChart, iAxisChartDataSet, g2d, totalItemArea,
152: axisChart.getXAxis().getZeroLineCoordinate());
153:
154: //LOOP
155: for (int i = 0; i < iAxisChartDataSet.getNumberOfDataItems(); i++) {
156: for (int j = 0; j < iAxisChartDataSet.getNumberOfDataSets(); j++) {
157: g2d.setPaint(iAxisChartDataSet.getPaint(j));
158:
159: //---there is only ever one data set for a regular bar chart
160: axisValueRenderEvent.setDataSetIndex(j);
161:
162: //---set values for the preRender event
163: axisValueRenderEvent.setValueX(axisChart.getXAxis()
164: .getZeroLineCoordinate());
165: axisValueRenderEvent.setValueY((float) rectangle
166: .getCenterY());
167: axisValueRenderEvent.setValueIndex(i);
168:
169: //---we want to do this regardless if we render an item
170: clusteredBarChartProperties
171: .firePreRender(axisValueRenderEvent);
172:
173: //---if value == 0 do not plot anything.
174: if (iAxisChartDataSet.getValue(j, i) != 0.0d) {
175:
176: if (iAxisChartDataSet.getValue(j, i) < 0) {
177: rectangle.x = axisChart.getXAxis()
178: .computeAxisCoordinate(
179: axisChart.getXAxis()
180: .getOrigin(),
181: iAxisChartDataSet
182: .getValue(j, i),
183: axisChart.getXAxis()
184: .getScaleCalculator()
185: .getMinValue());
186: rectangle.width = startingX - rectangle.x;
187:
188: //---set values for the postRender event
189: axisValueRenderEvent.setValueX(rectangle.x);
190: } else {
191: rectangle.x = startingX;
192: rectangle.width = BarChart
193: .computeScaleHeightOfValue(
194: iAxisChartDataSet
195: .getValue(j, i),
196: axisChart.getXAxis()
197: .getOneUnitPixelSize());
198:
199: //---set values for the postRender event
200: axisValueRenderEvent.setValueX(rectangle.x
201: + rectangle.width);
202: }
203:
204: //---with a user defined scale, we could have non-zero data points with a height of zero.
205: if (rectangle.width != 0) {
206: g2d.fill(rectangle);
207:
208: if (clusteredBarChartProperties
209: .getShowOutlinesFlag()) {
210: clusteredBarChartProperties
211: .getBarOutlineStroke().draw(g2d,
212: rectangle);
213: }
214:
215: //---if we are generating an ImageMap, store the image coordinates
216: if (axisChart.getGenerateImageMapFlag()) {
217: String label;
218: if (axisChart.getYAxis()
219: .getAxisLabelsGroup() != null) {
220: label = axisChart.getYAxis()
221: .getAxisLabelsGroup()
222: .getTextTag(imageMapLabelIndex)
223: .getText();
224: } else {
225: label = null;
226: }
227:
228: axisChart
229: .getImageMap()
230: .addImageMapArea(
231: new RectMapArea(
232: rectangle,
233: iAxisChartDataSet
234: .getValue(
235: j,
236: i),
237: label,
238: iAxisChartDataSet
239: .getLegendLabel(j)));
240: }
241: }
242: }
243:
244: //---notify everyone we just rendered
245: clusteredBarChartProperties
246: .firePostRender(axisValueRenderEvent);
247:
248: rectangle.y += barWidth;
249: }
250:
251: imageMapLabelIndex--;
252:
253: startingY += axisChart.getYAxis().getScalePixelWidth();
254: rectangle.y = startingY;
255:
256: totalItemArea.y += axisChart.getYAxis()
257: .getScalePixelWidth();
258: }
259: }
260:
261: /**************************************************************************************
262: *
263: * @param axisChart
264: * @param iAxisChartDataSet
265: * @param barChartProperties
266: * @param dataAxisProperties
267: * @param g2d
268: * @param rectangle
269: * @param startingY
270: **************************************************************************************/
271: private static void verticalPlot(AxisChart axisChart,
272: IAxisChartDataSet iAxisChartDataSet,
273: BarChartProperties barChartProperties,
274: DataAxisProperties dataAxisProperties, Graphics2D g2d,
275: Rectangle2D.Float rectangle, float barGroupStartingX,
276: float startingY, float barWidth) {
277:
278: //---setup the total area rectangle
279: Rectangle2D.Float totalItemArea = new Rectangle2D.Float();
280: totalItemArea.x = axisChart.getXAxis().getOrigin() + 1;
281: totalItemArea.y = axisChart.getYAxis().getOrigin()
282: - axisChart.getYAxis().getPixelLength() + 1;
283: totalItemArea.width = axisChart.getXAxis().getScalePixelWidth() - 1;
284: totalItemArea.height = axisChart.getYAxis().getPixelLength() - 1;
285:
286: //---reuse the same Object for pre and post render events.
287: AxisValueRenderEvent axisValueRenderEvent = new AxisValueRenderEvent(
288: axisChart, iAxisChartDataSet, g2d, totalItemArea,
289: axisChart.getYAxis().getZeroLineCoordinate());
290:
291: //LOOP
292: for (int i = 0; i < iAxisChartDataSet.getNumberOfDataItems(); i++) {
293: for (int j = 0; j < iAxisChartDataSet.getNumberOfDataSets(); j++) {
294: g2d.setPaint(iAxisChartDataSet.getPaint(j));
295:
296: //---there is only ever one data set for a regular bar chart
297: axisValueRenderEvent.setDataSetIndex(j);
298:
299: //---if value == 0 do not plot anything.
300: if (iAxisChartDataSet.getValue(j, i) != 0.0d) {
301: //---set values for the preRender event
302: axisValueRenderEvent.setValueX((float) rectangle
303: .getCenterX());
304: axisValueRenderEvent.setValueY(axisChart.getYAxis()
305: .getZeroLineCoordinate());
306: axisValueRenderEvent.setValueIndex(i);
307:
308: //---we want to do this regardless if we render an item
309: barChartProperties
310: .firePreRender(axisValueRenderEvent);
311:
312: if (iAxisChartDataSet.getValue(j, i) < 0) {
313: rectangle.y = startingY;
314: rectangle.height = BarChart
315: .computeScaleHeightOfValue(
316: iAxisChartDataSet
317: .getValue(j, i),
318: axisChart.getYAxis()
319: .getOneUnitPixelSize());
320:
321: //---set values for the postRender event
322: axisValueRenderEvent.setValueY(rectangle.y
323: + rectangle.height);
324: } else {
325: rectangle.y = axisChart.getYAxis()
326: .computeAxisCoordinate(
327: axisChart.getYAxis()
328: .getOrigin(),
329: iAxisChartDataSet
330: .getValue(j, i),
331: axisChart.getYAxis()
332: .getScaleCalculator()
333: .getMinValue());
334: rectangle.height = startingY - rectangle.y;
335:
336: //---set values for the postRender event
337: axisValueRenderEvent.setValueY(rectangle.y);
338: }
339:
340: //---with a user defined scale, we could have non-zero data points with a height of zero.
341: if (rectangle.height != 0) {
342: g2d.fill(rectangle);
343:
344: if (barChartProperties.getShowOutlinesFlag()) {
345: barChartProperties.getBarOutlineStroke()
346: .draw(g2d, rectangle);
347: }
348:
349: //---if we are generating an ImageMap, store the image coordinates
350: if (axisChart.getGenerateImageMapFlag()) {
351: String label;
352: if (axisChart.getXAxis()
353: .getAxisLabelsGroup() != null) {
354: label = axisChart.getXAxis()
355: .getAxisLabelsGroup()
356: .getTextTag(i).getText();
357: } else {
358: label = null;
359: }
360:
361: axisChart
362: .getImageMap()
363: .addImageMapArea(
364: new RectMapArea(
365: rectangle,
366: iAxisChartDataSet
367: .getValue(
368: j,
369: i),
370: label,
371: iAxisChartDataSet
372: .getLegendLabel(j)));
373: }
374: }
375:
376: //---notify everyone we just rendered
377: barChartProperties
378: .firePostRender(axisValueRenderEvent);
379: }
380:
381: rectangle.x += barWidth;
382: }
383:
384: totalItemArea.x += axisChart.getXAxis()
385: .getScalePixelWidth();
386:
387: barGroupStartingX += axisChart.getXAxis()
388: .getScalePixelWidth();
389: rectangle.x = barGroupStartingX;
390: }
391: }
392:
393: }
|