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: PieChartRenderer.java
021: Created on 7. August 2001, 18:14
022: */
023:
024: package de.progra.charting.render;
025:
026: import java.awt.font.FontRenderContext;
027: import java.awt.font.TextLayout;
028: import java.awt.geom.Ellipse2D;
029: import java.awt.geom.Arc2D;
030: import java.awt.geom.GeneralPath;
031: import java.awt.geom.Line2D;
032:
033: import de.progra.charting.CoordSystem;
034: import java.awt.geom.AffineTransform;
035: import de.progra.charting.PointToPixelTranslator;
036:
037: import java.awt.Font;
038: import java.awt.Graphics2D;
039: import java.awt.Paint;
040: import java.awt.RenderingHints;
041: import java.awt.Color;
042: import de.progra.charting.model.ChartDataModel;
043:
044: /**
045: * This renderer creates a PieChart.
046: * @author tbee
047: * @version 1.0
048: */
049: public class RadarChartRenderer extends AbstractChartRenderer {
050:
051: /** Creates new PieChartRenderer
052: * @param model the DataModel that should be rendered
053: */
054: public RadarChartRenderer(ChartDataModel model) {
055: super (model);
056: }
057:
058: /** Creates new PieChartRenderer
059: * @param cs the CoordSystem used to translate values into points
060: * @param model the DataModel that should be rendered
061: */
062: public RadarChartRenderer(CoordSystem cs, ChartDataModel model) {
063: super (cs, model);
064: }
065:
066: /** Finally renders the Object in the Graphics object.
067: * @param g the Graphics2D object in which to render
068: */
069: public void renderChart(Graphics2D g) {
070: // remember current anti aliasing rendering hint
071: // then activate it
072: Object rh = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
073: g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
074: RenderingHints.VALUE_ANTIALIAS_ON);
075:
076: // get the models
077: ChartDataModel m = getChartDataModel();
078: RowColorModel rcm = getRowColorModel();
079:
080: // get the available drawing space
081: double height = this .getBounds().getHeight();
082: double width = this .getBounds().getWidth();
083:
084: // the number of dataset
085: int lNumberOfRows = m.getDataSetNumber();
086:
087: // determine shortest dataset length, this is the number of axis that we need to draw
088: int lNumberOfColumns = Integer.MAX_VALUE;
089: for (int i = 0; i < lNumberOfRows; i++)
090: lNumberOfColumns = Math.min(lNumberOfColumns, m
091: .getDataSetLength(i));
092:
093: double[] maxvalues = new double[lNumberOfColumns];
094:
095: // get center
096: double center_y = getBounds().getCenterY();
097: double center_x = getBounds().getCenterX();
098:
099: // determine the radius
100: double lRadius = Math.min(width * 0.9, height * 0.9) / 2;
101:
102: // scan through the datasets
103: for (int lRow = 0; lRow < lNumberOfRows; lRow++) {
104: // scan through the values in the dataset
105: GeneralPath filledPolygon = new GeneralPath(
106: GeneralPath.WIND_EVEN_ODD, lNumberOfColumns);
107: for (int lCol = 0; lCol < lNumberOfColumns; lCol++) {
108: // get the value
109: double lValue = m.getValueAt(lRow, lCol).doubleValue();
110:
111: // determine the scale
112: double lMaxValue = maxvalues[lCol];
113:
114: if (lMaxValue == 0.0) {
115: for (int row = 0; row < lNumberOfRows; row++)
116: lMaxValue = Math.max(lMaxValue, m.getValueAt(
117: row, lCol).doubleValue() * 1.1);
118:
119: maxvalues[lCol] = lMaxValue;
120: }
121:
122: double lScaledValue = lValue / lMaxValue;
123: double lLineValue = lRadius * lScaledValue;
124:
125: // determine rotation: there are 2PI/noOfCols vertexes, this is vertex no lCol
126: // -1 : we want to rotate clockwise
127: // + PI: rotate 180 degree to get the first column pointing up
128: double lRotation = (-1
129: * (2 * Math.PI / lNumberOfColumns) * lCol)
130: + Math.PI;
131:
132: // determine the end points
133: double lX = center_x
134: + (lLineValue * Math.sin(lRotation));
135: double lY = center_y
136: + (lLineValue * Math.cos(lRotation));
137:
138: // draw the line
139: Line2D lLine = new Line2D.Double(center_x, center_y,
140: lX, lY);
141: g.setColor(Color.black);
142: g.draw(lLine);
143:
144: // add to polygone
145: if (lCol == 0)
146: filledPolygon.moveTo((float) lX, (float) lY);
147: else
148: filledPolygon.lineTo((float) lX, (float) lY);
149: }
150:
151: // draw the polygone
152: filledPolygon.closePath();
153: g.setPaint(rcm.getColor(lRow));
154: g.draw(filledPolygon);
155: }
156:
157: double lRotation;
158: double lX;
159: double lY;
160: TextLayout lLabel;
161:
162: // draw the lines
163: for (int lCol = 0; lCol < lNumberOfColumns; lCol++) {
164: // determine rotation: there are 2PI/noOfCols vertexes, this is vertex no lCol
165: // -1 : we want to rotate clockwise
166: // + PI: rotate 180 degree to get the first column pointing up
167: // Math.PI ... - Math.PI
168: lRotation = (-1 * (2 * Math.PI / lNumberOfColumns) * lCol)
169: + Math.PI;
170:
171: // determine the end points
172: lX = center_x + (lRadius * Math.sin(lRotation));
173: lY = center_y + (lRadius * Math.cos(lRotation));
174:
175: // draw the line
176: Line2D lLine = new Line2D.Double(center_x, center_y, lX, lY);
177: g.setColor(Color.black);
178: g.draw(lLine);
179:
180: // draw the label
181: lLabel = new TextLayout("" + model.getColumnValueAt(lCol),
182: new Font("Courier", Font.BOLD, 9),
183: new FontRenderContext(null, true, false));
184: g.setColor(Color.black);
185:
186: // Move the labels in the lower half circle down a bit, so the upper left corner touches the axis
187: if ((lRotation <= Math.PI / 2)
188: && (lRotation >= -Math.PI / 2))
189: lY += lLabel.getBounds().getHeight();
190:
191: // Move the labels in the left half circle a bit left, so the upper right corner touches the axis
192: if (lRotation <= 0)
193: lX -= lLabel.getBounds().getWidth();
194:
195: lLabel.draw(g, (float) lX, (float) lY);
196: }
197:
198: // reset rendering hint
199: g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, rh);
200: }
201: }
|