001: /*
002: JOpenChart Java Charting Library and Toolkit
003: Copyright (C) 2001 Sebastian Müller
004: http://jopenchart.sourceforge.net
005:
006: This library is free software; you can redistribute it and/or
007: modify it under the terms of the GNU Lesser General Public
008: License as published by the Free Software Foundation; either
009: version 2.1 of the License, or (at your option) any later version.
010:
011: This library is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public
017: License along with this library; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019:
020: StackedBarChartRenderer.java
021: Created on 26. September 2002
022: */
023:
024: package de.progra.charting.render;
025:
026: import java.awt.Color;
027: import java.awt.Font;
028: import java.awt.Graphics2D;
029: import java.awt.geom.AffineTransform;
030: import java.awt.geom.Point2D;
031: import java.awt.geom.Rectangle2D;
032: import java.awt.font.LineMetrics;
033: import java.awt.font.FontRenderContext;
034: import java.text.DecimalFormat;
035: import de.progra.charting.PointToPixelTranslator;
036: import de.progra.charting.CoordSystem;
037: import de.progra.charting.model.AbstractChartDataModel;
038: import de.progra.charting.model.ChartDataModel;
039: import de.progra.charting.model.ChartDataModelConstraints;
040: import de.progra.charting.model.StackedChartDataModelConstraints;
041:
042: /**
043: * This renderer creates a stacked BarChart. This will only work on a ChartDataModel
044: * with non-numeric x-axis values, because I couldn't make any sense out of
045: * a bar chart with a numeric x-axis like in a line chart.
046: * @author mueller
047: * @version 1.0
048: */
049: public class StackedBarChartRenderer extends AbstractChartRenderer {
050:
051: protected float boxWidth = 1.0f;
052:
053: /** Creates new StackedBarChartRenderer
054: * @param cs the CoordSystem used to translate into pixel space
055: * @param model the DataModel that should be rendered
056: */
057: public StackedBarChartRenderer(CoordSystem cs,
058: AbstractChartDataModel model) {
059: super (cs, model);
060: }
061:
062: /** Creates new StackedBarChartRenderer
063: * @param cs the CoordSystem used to translate into pixel space
064: * @param model the DataModel that should be rendered
065: * @param boxWidth a value between 0.0 and 1.0 representing how much of the
066: * alloted space each box should consume. If 1.0 is passed, then each box will
067: * completely fill it's allotted space, alternately I suggest you don't pass 0.0
068: */
069: public StackedBarChartRenderer(CoordSystem cs,
070: AbstractChartDataModel model, float boxWidth) {
071: this (cs, model);
072: this .boxWidth = boxWidth;
073: }
074:
075: /** Finally renders the Object in the Graphics object.
076: * @param g the Graphics2D object in which to render
077: */
078: public void renderChart(Graphics2D g) {
079: ChartDataModel m = getChartDataModel();
080: ChartDataModelConstraints con = m
081: .getChartDataModelConstraints(CoordSystem.FIRST_YAXIS);
082:
083: System.out.println("** Maximum: " + con.getMaximumValue()
084: + " Minimum: " + con.getMinimumValue());
085:
086: if (m.isColumnNumeric())
087: return;
088:
089: RowColorModel rcm = getRowColorModel();
090: AffineTransform yaxis1 = getTransform(CoordSystem.FIRST_YAXIS);
091:
092: int datasetcount = m.getDataSetNumber();
093:
094: int maximumDataSetLength = Integer.MIN_VALUE;
095:
096: for (int i = 0; i < model.getDataSetNumber(); i++) {
097: maximumDataSetLength = Math.max(maximumDataSetLength, model
098: .getDataSetLength(i));
099: }
100:
101: Point2D pointzero;
102: if (con.getMinimumValue().floatValue() > 0)
103: pointzero = yaxis1.transform(new Point2D.Float((float) con
104: .getMinimumColumnValue(), con.getMinimumValue()
105: .floatValue()), null);
106: else if (con.getMaximumValue().floatValue() < 0)
107: pointzero = yaxis1.transform(new Point2D.Float((float) con
108: .getMinimumColumnValue(), con.getMaximumValue()
109: .floatValue()), null);
110: else
111: pointzero = yaxis1.transform(new Point2D.Float((float) con
112: .getMinimumColumnValue(), 0f), null);
113:
114: Point2D point1 = yaxis1.transform(new Point2D.Float((float) con
115: .getMinimumColumnValue(), con.getMaximumValue()
116: .floatValue()), null);
117: Point2D point2 = yaxis1.transform(new Point2D.Float((float) con
118: .getMaximumColumnValue(), con.getMaximumValue()
119: .floatValue()), null);
120: Point2D value = point1;
121:
122: int dataunitwidth = (int) ((point2.getX() - point1.getX()) / con
123: .getMaximumColumnValue());
124: int boxwidth = (int) (dataunitwidth * boxWidth);
125: float margin = (float) (dataunitwidth * ((1.0 - boxWidth) / 2f));
126:
127: /* We paint the values starting at x-value "0".
128: * As we only render BarCharts for ChartDataModels with
129: * non-numeric x-axis values we don't have to read those
130: * values from the data model. You can look in
131: * ObjectChartDataModel to see, how the x-axis bounds
132: * are defined: the minimum value is always 0, the maximum
133: * value is the amount of non-numeric x-axis values.
134: */
135: double currentvalue = 0.0;
136: Rectangle2D box = null;
137: Point2D oldmaxvalue;
138: Point2D oldminvalue;
139:
140: for (int j = 0; j < maximumDataSetLength; j++) {
141: double minvalue = 0.0;
142: double maxvalue = 0.0;
143:
144: oldmaxvalue = pointzero;
145: oldminvalue = pointzero;
146:
147: for (int i = 0; i < m.getDataSetNumber(); i++) {
148:
149: if (j < m.getDataSetLength(i))
150: currentvalue = m.getValueAt(i, j).doubleValue();
151: else
152: currentvalue = 0.0;
153:
154: if (currentvalue < 0.0) {
155: minvalue += currentvalue;
156: yaxis1.transform(new Point2D.Float((float) j,
157: (float) minvalue), value);
158:
159: box = new Rectangle2D.Float((float) (value.getX()),
160: (float) Math.min(value.getY(), oldminvalue
161: .getY()), (float) boxwidth,
162: (float) Math.abs(oldminvalue.getY()
163: - value.getY()));
164: oldminvalue = (Point2D) value.clone();
165: } else {
166: maxvalue += currentvalue;
167: yaxis1.transform(new Point2D.Float((float) j,
168: (float) maxvalue), value);
169:
170: box = new Rectangle2D.Float((float) (value.getX()),
171: (float) Math.min(value.getY(), oldmaxvalue
172: .getY()), (float) boxwidth,
173: (float) Math.abs(oldmaxvalue.getY()
174: - value.getY()));
175:
176: oldmaxvalue = (Point2D) value.clone();
177: }
178:
179: g.setColor(rcm.getColor(i));
180: g.fill(box);
181: g.setColor(Color.black);
182: g.draw(box);
183: }
184: }
185: }//end render method
186:
187: }
|