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.Chart;
036: import org.krysalis.jcharts.axisChart.axis.Axis;
037: import org.krysalis.jcharts.axisChart.axis.XAxis;
038: import org.krysalis.jcharts.axisChart.axis.YAxis;
039: import org.krysalis.jcharts.axisChart.axis.scale.AutomaticScaleCalculator;
040: import org.krysalis.jcharts.axisChart.axis.scale.ScaleCalculator;
041: import org.krysalis.jcharts.axisChart.axis.scale.UserDefinedScaleCalculator;
042: import org.krysalis.jcharts.chartData.ChartDataException;
043: import org.krysalis.jcharts.chartData.interfaces.IAxisChartDataSet;
044: import org.krysalis.jcharts.chartData.interfaces.IAxisDataSeries;
045: import org.krysalis.jcharts.chartData.interfaces.IAxisPlotDataSet;
046: import org.krysalis.jcharts.chartData.interfaces.IDataSeries;
047: import org.krysalis.jcharts.chartData.interfaces.IStockChartDataSet;
048: import org.krysalis.jcharts.chartData.processors.AxisChartDataProcessor;
049: import org.krysalis.jcharts.chartText.NumericTagGroup;
050: import org.krysalis.jcharts.chartText.TextTagGroup;
051: import org.krysalis.jcharts.imageMap.ImageMap;
052: import org.krysalis.jcharts.properties.AxisProperties;
053: import org.krysalis.jcharts.properties.AxisTypeProperties;
054: import org.krysalis.jcharts.properties.ChartProperties;
055: import org.krysalis.jcharts.properties.DataAxisProperties;
056: import org.krysalis.jcharts.properties.LegendAreaProperties;
057: import org.krysalis.jcharts.properties.LegendProperties;
058: import org.krysalis.jcharts.properties.PropertyException;
059: import org.krysalis.jcharts.test.HTMLChartTestable;
060: import org.krysalis.jcharts.test.HTMLGenerator;
061: import org.krysalis.jcharts.test.HTMLTestable;
062: import org.krysalis.jcharts.types.ChartType;
063:
064: import java.awt.*;
065: import java.awt.font.FontRenderContext;
066: import java.awt.geom.Rectangle2D;
067:
068: // Dual Y axis changes integrated CMC 25Aug03
069: //import java.lang.Math.*;
070: //import java.lang.Float.*;
071:
072: /*************************************************************************************
073: * This Class is used to create all axis chart types. This class knows how to render
074: * charts based on the ChartType specified in on the iAxisChartDataSet.
075: *
076: * @author Nathaniel Auvil
077: * @version $Id: AxisChart.java,v 1.7 2004/05/31 16:23:46 nathaniel_auvil Exp $
078: ************************************************************************************/
079: public class AxisChart extends Chart implements HTMLChartTestable {
080: protected XAxis xAxis;
081: protected YAxis yAxis;
082: protected AxisProperties axisProperties;
083:
084: private IAxisDataSeries iAxisDataSeries;
085:
086: /**************************************************************************************************
087: * Constructor
088: *
089: * @param iAxisDataSeries
090: * @param chartProperties
091: * @param axisProperties
092: * @param legendProperties if no legend is desired, pass NULL
093: * @param pixelWidth
094: * @param pixelHeight
095: ***************************************************************************************************/
096: public AxisChart(IAxisDataSeries iAxisDataSeries,
097: ChartProperties chartProperties,
098: AxisProperties axisProperties,
099: LegendProperties legendProperties, int pixelWidth,
100: int pixelHeight) {
101: super (legendProperties, chartProperties, pixelWidth,
102: pixelHeight);
103: this .axisProperties = axisProperties;
104: this .iAxisDataSeries = iAxisDataSeries;
105: }
106:
107: /*************************************************************************************************
108: *
109: * @return IAxisDataSeries
110: *************************************************************************************************/
111: public IAxisDataSeries getIAxisDataSeries() {
112: return this .iAxisDataSeries;
113: }
114:
115: /********************************************************************************************
116: * ScatterPlots create a subclass of AxisChartDataProcessor so we need this method so we can
117: * overload it.
118: *
119: * @return AxisChartDataProcessor
120: ********************************************************************************************/
121: public AxisChartDataProcessor createAxisChartDataProcessor() {
122: return new AxisChartDataProcessor();
123: }
124:
125: /************************************************************************************************
126: * Once we determine which axis is the data axis, the logic to set it up is the same whether it
127: * is a horizontal or vertical plot.
128: *
129: * @param dataAxisProperties
130: * @param axisChartDataProcessor
131: * @param fontRenderContext
132: * @return NumericTagGroup need to set this on the right axis
133: ************************************************************************************************/
134: protected NumericTagGroup setupDataAxisProperties(Axis axis,
135: DataAxisProperties dataAxisProperties,
136: AxisChartDataProcessor axisChartDataProcessor,
137: FontRenderContext fontRenderContext) {
138: if (dataAxisProperties.getScaleCalculator() == null) {
139: ScaleCalculator s;
140:
141: if (dataAxisProperties.hasUserDefinedScale()) {
142: s = new UserDefinedScaleCalculator(dataAxisProperties
143: .getUserDefinedMinimumValue(),
144: dataAxisProperties.getUserDefinedIncrement());
145: } else {
146: s = new AutomaticScaleCalculator();
147: // Dual Y axis changes integrated CMC 25Aug03
148: // s.setMaxValue( axisChartDataProcessor.getMaxValue() );
149: // s.setMinValue( axisChartDataProcessor.getMinValue() );
150: if (this .axisProperties.getYAxisProperties()
151: .getMaxRightAxis() > 0) {
152: s.setMaxValue(this .axisProperties
153: .getYAxisProperties().getMaxRightAxis());
154: } else {
155: s.setMaxValue(axisChartDataProcessor.getMaxValue());
156: }
157:
158: if (this .axisProperties.getYAxisProperties()
159: .getMinRightAxis() < 0) {
160: s.setMinValue(this .axisProperties
161: .getYAxisProperties().getMinRightAxis());
162: } else {
163: s.setMinValue(axisChartDataProcessor.getMinValue());
164: }
165: }
166: axis.setScaleCalculator(s);
167: } else {
168: axis.setScaleCalculator(dataAxisProperties
169: .getScaleCalculator());
170: // Dual Y axis changes integrated CMC 25Aug03
171: // axis.getScaleCalculator().setMaxValue( axisChartDataProcessor.getMaxValue() );
172: // axis.getScaleCalculator().setMinValue( axisChartDataProcessor.getMinValue() );
173:
174: if (this .axisProperties.getYAxisProperties()
175: .getMaxRightAxis() > 0) {
176: axis.getScaleCalculator().setMaxValue(
177: this .axisProperties.getYAxisProperties()
178: .getMaxRightAxis());
179: } else {
180: axis.getScaleCalculator().setMaxValue(
181: axisChartDataProcessor.getMaxValue());
182: }
183:
184: if (this .axisProperties.getYAxisProperties()
185: .getMinRightAxis() < 0) {
186: axis.getScaleCalculator().setMinValue(
187: this .axisProperties.getYAxisProperties()
188: .getMinRightAxis());
189: } else {
190: axis.getScaleCalculator().setMinValue(
191: axisChartDataProcessor.getMinValue());
192: }
193: }
194:
195: axis.getScaleCalculator().setRoundingPowerOfTen(
196: dataAxisProperties.getRoundToNearest());
197: axis.getScaleCalculator().setNumberOfScaleItems(
198: dataAxisProperties.getNumItems());
199: axis.getScaleCalculator().computeScaleValues();
200:
201: // if( dataAxisProperties.showAxisLabels() )
202: {
203: //TODO what if they do not want to display axis labels?
204: //todo we still need to know how to size the axis
205: NumericTagGroup numericTagGroup = new NumericTagGroup(
206: dataAxisProperties.getScaleChartFont(),
207: fontRenderContext, dataAxisProperties
208: .useDollarSigns(), dataAxisProperties
209: .usePercentSigns(), dataAxisProperties
210: .useCommas(), dataAxisProperties
211: .getRoundToNearest());
212:
213: numericTagGroup.createAxisScaleLabels(axis
214: .getScaleCalculator());
215: return numericTagGroup;
216: }
217: /*
218: else
219: {
220: return null;
221: }
222: */
223: }
224:
225: /***************************************************************************************
226: *
227: *
228: * @param axisChartDataProcessor
229: * @param fontRenderContext
230: **************************************************************************************/
231: protected void setupAxis(
232: AxisChartDataProcessor axisChartDataProcessor,
233: FontRenderContext fontRenderContext)
234: throws ChartDataException {
235: IDataSeries iDataSeries = (IDataSeries) this
236: .getIAxisDataSeries();
237:
238: if (this .axisProperties.isPlotHorizontal()) {
239: //---X AXIS---------------------------------------------------------------------------
240: DataAxisProperties dataAxisProperties = (DataAxisProperties) this
241: .getAxisProperties().getXAxisProperties();
242: this .xAxis = new XAxis(this , dataAxisProperties
243: .getNumItems());
244:
245: NumericTagGroup numericTagGroup = setupDataAxisProperties(
246: this .xAxis, dataAxisProperties,
247: axisChartDataProcessor, fontRenderContext);
248: this .xAxis.setAxisLabelsGroup(numericTagGroup);
249:
250: //---Y AXIS---------------------------------------------------------------------------
251: AxisTypeProperties axisTypeProperties = this
252: .getAxisProperties().getYAxisProperties();
253: this .yAxis = new YAxis(this , axisChartDataProcessor
254: .getNumberOfElementsInADataSet());
255: if (axisTypeProperties.showAxisLabels()) {
256: TextTagGroup textTagGroup = new TextTagGroup(
257: axisTypeProperties.getScaleChartFont(),
258: fontRenderContext);
259:
260: //LOOP
261: for (int i = 0; i < iDataSeries.getNumberOfAxisLabels(); i++) {
262: if (iDataSeries.getAxisLabel(i) == null) {
263: throw new ChartDataException(
264: "None of the axis labels can be NULL.");
265: }
266: textTagGroup.addLabel(iDataSeries.getAxisLabel(i));
267: }
268:
269: this .yAxis.setAxisLabelsGroup(textTagGroup);
270: }
271: } else {
272: //---X AXIS---------------------------------------------------------------------------
273: AxisTypeProperties axisTypeProperties = this
274: .getAxisProperties().getXAxisProperties();
275: this .xAxis = new XAxis(this , axisChartDataProcessor
276: .getNumberOfElementsInADataSet());
277: if (axisTypeProperties.showAxisLabels()) {
278: TextTagGroup textTagGroup = new TextTagGroup(
279: axisTypeProperties.getScaleChartFont(),
280: fontRenderContext);
281:
282: //LOOP
283: for (int i = 0; i < iDataSeries.getNumberOfAxisLabels(); i++) {
284: if (iDataSeries.getAxisLabel(i) == null) {
285: throw new ChartDataException(
286: "None of the axis labels can be NULL.");
287: }
288: textTagGroup.addLabel(iDataSeries.getAxisLabel(i));
289: }
290:
291: this .xAxis.setAxisLabelsGroup(textTagGroup);
292: }
293:
294: //---Y AXIS---------------------------------------------------------------------------
295: DataAxisProperties dataAxisProperties = (DataAxisProperties) this
296: .getAxisProperties().getYAxisProperties();
297: this .yAxis = new YAxis(this , dataAxisProperties
298: .getNumItems());
299: NumericTagGroup numericTagGroup = setupDataAxisProperties(
300: this .yAxis, dataAxisProperties,
301: axisChartDataProcessor, fontRenderContext);
302: this .yAxis.setAxisLabelsGroup(numericTagGroup);
303: // Dual Y axis changes integrated CMC 25Aug03
304: // compute the labels of the right axis if necessary
305: if (this .axisProperties.getYAxisProperties()
306: .getSecondScaleRight() != 1) {
307: NumericTagGroup numericTagGroup2 = new NumericTagGroup(
308: dataAxisProperties.getScaleChartFontRight(),
309: fontRenderContext, dataAxisProperties
310: .useDollarSigns(), dataAxisProperties
311: .usePercentSigns(), dataAxisProperties
312: .useCommas(), dataAxisProperties
313: .getRoundToNearest());
314: int j = 0;
315: while (j < this .getYAxis().getNumberOfScaleItems()) {
316: Float myFloat = new Float(this .yAxis
317: .getAxisLabelsGroup().getTextTag(j)
318: .getText());
319: float temp = myFloat.floatValue();
320: // Rounding problems were causing errors
321: //Integer myInteger = new Integer ( Math.round(Math.round((float)(temp / this.axisProperties.getYAxisProperties().getSecondScaleRight()))/10)*10 );
322: //String myString = new String ("");
323: //myString = myInteger.toString();
324: String myString = new String(String.valueOf(Math
325: .round(temp
326: / this .axisProperties
327: .getYAxisProperties()
328: .getSecondScaleRight())));
329: numericTagGroup2.addLabel(myString);
330: j++;
331: }
332: this .yAxis.setAxisLabelsGroupRight(numericTagGroup2);
333: }
334: }
335:
336: //---if yAxisTitle is null, do not show title
337: this .yAxis.computeMinimumWidthNeeded(iDataSeries
338: .getYAxisTitle());
339: this .xAxis.computeMinimumHeightNeeded(iDataSeries
340: .getXAxisTitle());
341: }
342:
343: /***********************************************************************************************
344: * Finalizes the size of both Axis and sets the origin position
345: *
346: * @param xAxisWidth
347: * @param yAxisHeight
348: * @param chartTitleHeight
349: **********************************************************************************************/
350: private void sizeAndPositionAxis(float xAxisWidth,
351: float yAxisHeight, float chartTitleHeight) {
352: //---SUBTRACT space for axis titles, labels, ticks...
353: // Dual Y axis changes integrated CMC 25Aug03
354: // if there is a right axis to render we subtract twice the minimum width needed
355: if (this .axisProperties.getYAxisProperties().getShowRightAxis())
356: xAxisWidth -= 2 * this .yAxis.getMinimumWidthNeeded();
357: else
358: xAxisWidth -= this .yAxis.getMinimumWidthNeeded();
359:
360: yAxisHeight -= this .xAxis.getMinimumHeightNeeded();
361:
362: //---SET THE PIXEL LENGTH OF THE AXIS
363: this .xAxis.setPixelLength(xAxisWidth);
364:
365: if (axisProperties.getYAxisProperties().showAxisLabels()) {
366: this .yAxis.setPixelLength(yAxisHeight
367: - this .yAxis.getAxisLabelsGroup().getTallestLabel()
368: / 2);
369: } else {
370: this .yAxis.setPixelLength(yAxisHeight);
371: }
372:
373: if (this .getLegend() != null) {
374: //---SET THE ORIGIN COORDINATES
375: if ((this .getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.RIGHT)
376: || (this .getLegend().getLegendProperties()
377: .getPlacement() == LegendAreaProperties.BOTTOM)) {
378: this .xAxis.setOrigin(this .yAxis.getMinimumWidthNeeded()
379: + super .getChartProperties().getEdgePadding());
380: this .yAxis.setOrigin(yAxisHeight
381: + super .getChartProperties().getEdgePadding()
382: + chartTitleHeight);
383: } else if (this .getLegend().getLegendProperties()
384: .getPlacement() == LegendAreaProperties.LEFT)
385: //---else, LegendAreaProperties.LEFT, OR LegendAreaProperties.TOP
386: {
387: this .xAxis.setOrigin(super .getImageWidth() - xAxisWidth
388: - super .getChartProperties().getEdgePadding());
389: this .yAxis.setOrigin(yAxisHeight
390: + super .getChartProperties().getEdgePadding()
391: + chartTitleHeight);
392: } else if (this .getLegend().getLegendProperties()
393: .getPlacement() == LegendAreaProperties.TOP) {
394: this .xAxis.setOrigin(this .yAxis.getMinimumWidthNeeded()
395: + super .getChartProperties().getEdgePadding());
396: this .yAxis.setOrigin(super .getImageHeight()
397: - super .getChartProperties().getEdgePadding()
398: - this .xAxis.getMinimumHeightNeeded());
399: }
400: } else {
401: this .xAxis.setOrigin(this .yAxis.getMinimumWidthNeeded()
402: + super .getChartProperties().getEdgePadding());
403: this .yAxis.setOrigin(yAxisHeight
404: + super .getChartProperties().getEdgePadding()
405: + chartTitleHeight);
406: }
407: }
408:
409: /******************************************************************************************
410: *
411: *****************************************************************************************/
412: protected void deriveAxisValues() {
413: this .xAxis.computeLabelFilter();
414: this .xAxis.computeShouldTickStartAtYAxis(this .iAxisDataSeries,
415: this .axisProperties.getXAxisProperties());
416:
417: if (this .axisProperties.isPlotHorizontal()) {
418: //DataAxisProperties dataAxisProperties = (DataAxisProperties) this.axisProperties.getXAxisProperties();
419: //LabelAxisProperties labelAxisProperties= (LabelAxisProperties) this.axisProperties.getYAxisProperties();
420:
421: //---Determine how many labels will fit on the x-axis
422:
423: this .xAxis
424: .computeScalePixelWidthDataAxis(this .axisProperties
425: .getXAxisProperties());
426:
427: this .yAxis.computeScalePixelWidth(this .axisProperties
428: .getYAxisProperties());
429: this .xAxis.computeOneUnitPixelSize(this .xAxis
430: .getScalePixelWidth(), this .xAxis
431: .getScaleCalculator().getIncrement());
432:
433: //---we ADD to the origin position when doing x-axis
434: float zeroLineCoordinate = (float) (this .xAxis.getOrigin() + (this .xAxis
435: .getScalePixelWidth() * (-this .xAxis
436: .getScaleCalculator().getMinValue()))
437: / this .xAxis.getScaleCalculator().getIncrement());
438: this .xAxis.setZeroLineCoordinate(zeroLineCoordinate);
439: } else {
440: //DataAxisProperties dataAxisProperties = ( DataAxisProperties ) this.axisProperties.getYAxisProperties();
441:
442: this .xAxis.computeScalePixelWidth(this .axisProperties
443: .getXAxisProperties());
444: this .yAxis
445: .computeScalePixelWidthDataAxis(this .axisProperties
446: .getYAxisProperties());
447: this .yAxis.computeOneUnitPixelSize(this .yAxis
448: .getScalePixelWidth(), this .yAxis
449: .getScaleCalculator().getIncrement());
450:
451: //---we SUBTRACT to the origin position when doing y-axis
452: float zeroLineCoordinate = (float) (this .yAxis.getOrigin() - (this .yAxis
453: .getScalePixelWidth() * (-this .yAxis
454: .getScaleCalculator().getMinValue()))
455: / this .yAxis.getScaleCalculator().getIncrement());
456: this .yAxis.setZeroLineCoordinate(zeroLineCoordinate);
457: }
458:
459: this .xAxis.computeTickStart();
460: }
461:
462: /********************************************************************************************
463: * Implement the method to render the Axis based chart
464: *
465: * @throws ChartDataException
466: * @throws PropertyException there are several validations done to aid in development of the
467: * charts.
468: ********************************************************************************************/
469: protected void renderChart() throws ChartDataException,
470: PropertyException {
471: if (super .getChartProperties().validate()) {
472: this .iAxisDataSeries.validate();
473: }
474:
475: //---this is not an optional validation
476: this .validateHorizontalPlot();
477:
478: Graphics2D g2d = super .getGraphics2D();
479:
480: FontRenderContext fontRenderContext = g2d
481: .getFontRenderContext();
482:
483: //---cache calcs used more than once
484: float edgePaddingTimesTwo = super .getChartProperties()
485: .getEdgePadding() * 2;
486:
487: //---start off with total image width and we will subtract components from that.
488: float xAxisWidth = super .getImageWidth() - edgePaddingTimesTwo;
489: float yAxisHeight = super .getImageHeight()
490: - edgePaddingTimesTwo;
491:
492: //---render the TITLE. If no title, this will return zero.
493: float chartTitleHeight = super .renderChartTitle(this
494: .getIAxisDataSeries().getChartTitle(),
495: fontRenderContext);
496: yAxisHeight -= chartTitleHeight;
497:
498: //---if there is a legend...
499: if (super .getLegend() != null) {
500: //---PROCESS the size needed for drawing the legend.
501: super .getLegend().computeLegendXY(this .iAxisDataSeries,
502: chartTitleHeight);
503:
504: if ((super .getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.RIGHT)
505: || (super .getLegend().getLegendProperties()
506: .getPlacement() == LegendAreaProperties.LEFT)) {
507: xAxisWidth -= super .getLegend().getLegendProperties()
508: .getChartPadding();
509: xAxisWidth -= super .getLegend().getWidth();
510: } else //LegendAreaProperties.BOTTOM, OR LegendAreaProperties.TOP
511: {
512: yAxisHeight -= this .getLegend().getLegendProperties()
513: .getChartPadding();
514: yAxisHeight -= this .getLegend().getHeight();
515: }
516:
517: super .getLegend().render();
518: }
519:
520: AxisChartDataProcessor axisChartDataProcessor = this
521: .createAxisChartDataProcessor();
522: axisChartDataProcessor.processData(this , fontRenderContext);
523:
524: this .setupAxis(axisChartDataProcessor, fontRenderContext);
525: this .sizeAndPositionAxis(xAxisWidth, yAxisHeight,
526: chartTitleHeight);
527: this .deriveAxisValues();
528:
529: //---PAINT THE BACKGROUND OF AXIS
530: if (this .getAxisProperties().getBackgroundPaint() != null) {
531: Rectangle2D.Float rectangle = new Rectangle2D.Float(
532: this .xAxis.getOrigin() + 1, this .yAxis.getOrigin()
533: - this .yAxis.getPixelLength(), this .xAxis
534: .getPixelLength(), this .yAxis
535: .getPixelLength());
536: g2d.setPaint(this .axisProperties.getBackgroundPaint());
537: g2d.fill(rectangle);
538: }
539:
540: this .yAxis.render(g2d, this .getAxisProperties(),
541: iAxisDataSeries.getYAxisTitle());
542: this .xAxis.render(g2d, this .getAxisProperties(),
543: iAxisDataSeries.getXAxisTitle());
544:
545: //---SCALE CLIPPING REGION
546: //---if the user defined the scale, chart may be off the 'screen' so set a clipping region so only draw in the chart.
547: Rectangle2D.Float rectangle = new Rectangle2D.Float(this
548: .getXAxis().getOrigin(), this .getYAxis().getOrigin()
549: - this .getYAxis().getPixelLength() + 1, this .xAxis
550: .getPixelLength() + 1, this .yAxis.getPixelLength() - 2);
551: g2d.setClip(rectangle);
552:
553: //---IMAGE MAP setup
554: //---if we are saving all the coordinates for an ImageMap, create the ImageMap Object as we
555: //--- know how many area elements there are.
556: if (super .getGenerateImageMapFlag()) {
557: //---pass the size to try and avoid having the expense of resizing the ArrayList
558: ImageMap imageMap = new ImageMap(iAxisDataSeries.size()
559: * iAxisDataSeries.getTotalNumberOfDataSets());
560: super .setImageMap(imageMap);
561: }
562:
563: //---draw the charts over the axis...
564: overlayCharts();
565: }
566:
567: /********************************************************************************************
568: * Draws the charts over the axis. We have to render in a specific order so combo charts
569: * get drawn correctly
570: *
571: * @throws PropertyException
572: ******************************************************************************************/
573: protected void overlayCharts() throws PropertyException,
574: ChartDataException {
575: IAxisPlotDataSet iAxisPlotDataSet;
576:
577: iAxisPlotDataSet = this .iAxisDataSeries
578: .getIAxisPlotDataSet(ChartType.AREA_STACKED);
579: if (iAxisPlotDataSet != null) {
580: StackedAreaChart.render(this ,
581: (IAxisChartDataSet) iAxisPlotDataSet);
582: }
583: iAxisPlotDataSet = this .iAxisDataSeries
584: .getIAxisPlotDataSet(ChartType.AREA);
585: if (iAxisPlotDataSet != null) {
586: AreaChart
587: .render(this , (IAxisChartDataSet) iAxisPlotDataSet);
588: }
589:
590: iAxisPlotDataSet = this .iAxisDataSeries
591: .getIAxisPlotDataSet(ChartType.BAR);
592: if (iAxisPlotDataSet != null) {
593: BarChart.render(this , (IAxisChartDataSet) iAxisPlotDataSet);
594: }
595: iAxisPlotDataSet = this .iAxisDataSeries
596: .getIAxisPlotDataSet(ChartType.BAR_STACKED);
597: if (iAxisPlotDataSet != null) {
598: StackedBarChart.render(this ,
599: (IAxisChartDataSet) iAxisPlotDataSet);
600: }
601: iAxisPlotDataSet = this .iAxisDataSeries
602: .getIAxisPlotDataSet(ChartType.BAR_CLUSTERED);
603: if (iAxisPlotDataSet != null) {
604: ClusteredBarChart.render(this ,
605: (IAxisChartDataSet) iAxisPlotDataSet);
606: }
607:
608: iAxisPlotDataSet = this .iAxisDataSeries
609: .getIAxisPlotDataSet(ChartType.STOCK);
610: if (iAxisPlotDataSet != null) {
611: StockChart.render(this ,
612: (IStockChartDataSet) iAxisPlotDataSet);
613: }
614:
615: iAxisPlotDataSet = this .iAxisDataSeries
616: .getIAxisPlotDataSet(ChartType.LINE);
617: if (iAxisPlotDataSet != null) {
618: LineChart
619: .render(this , (IAxisChartDataSet) iAxisPlotDataSet);
620: }
621:
622: iAxisPlotDataSet = this .iAxisDataSeries
623: .getIAxisPlotDataSet(ChartType.POINT);
624: if (iAxisPlotDataSet != null) {
625: PointChart.render(this ,
626: (IAxisChartDataSet) iAxisPlotDataSet);
627: }
628: }
629:
630: /**********************************************************************************************
631: * Currently, we only support the bar chart types being horizontal, and you can not have a
632: * horizontally plotted bar chart in a combo chart.
633: *
634: * @throws PropertyException
635: **********************************************************************************************/
636: private void validateHorizontalPlot() throws PropertyException {
637: if (axisProperties.isPlotHorizontal()) {
638: //---if there is only one data set, there is no need to do any validations.
639: if (this .iAxisDataSeries.size() > 1) {
640: throw new PropertyException(
641: "You can not have a combo chart on a horizontal plot.");
642: }
643:
644: if (!this .allowHorizontalPlot()) {
645: throw new PropertyException(
646: "Horizontal plots are only supported in the Bar, Stacked Bar, and Clustered Bar Chart Types.");
647: }
648: }
649: }
650:
651: /******************************************************************************************
652: * We only allow horizontal plots for the Bar Chart types in this release.
653: *
654: * @return boolean
655: ******************************************************************************************/
656: private boolean allowHorizontalPlot() {
657: if (this .iAxisDataSeries.getIAxisPlotDataSet(ChartType.BAR) != null) {
658: return true;
659: }
660:
661: if (this .iAxisDataSeries
662: .getIAxisPlotDataSet(ChartType.BAR_STACKED) != null) {
663: return true;
664: }
665:
666: if (this .iAxisDataSeries
667: .getIAxisPlotDataSet(ChartType.BAR_CLUSTERED) != null) {
668: return true;
669: }
670:
671: return false;
672: }
673:
674: /**************************************************************************************************
675: *
676: ***************************************************************************************************/
677: public AxisProperties getAxisProperties() {
678: return this .axisProperties;
679: }
680:
681: /**************************************************************************************************
682: *
683: ***************************************************************************************************/
684: public XAxis getXAxis() {
685: return this .xAxis;
686: }
687:
688: /**************************************************************************************************
689: *
690: ***************************************************************************************************/
691: public YAxis getYAxis() {
692: return this .yAxis;
693: }
694:
695: /**********************************************************************************************
696: * Enables the testing routines to display the contents of this Object. Override Chart
697: * implementation as PieCharts use AreaProperties directly rather than a child.
698: *
699: * @param htmlGenerator
700: * @param imageFileName
701: * @param imageMap if this is NULL we are not creating image map data in html
702: **********************************************************************************************/
703: public void toHTML(HTMLGenerator htmlGenerator,
704: String imageFileName, ImageMap imageMap) {
705: htmlGenerator.chartTableStart(this .getClass().getName(),
706: imageFileName, imageMap);
707:
708: if (this .iAxisDataSeries instanceof HTMLTestable) {
709: ((HTMLTestable) this .iAxisDataSeries).toHTML(htmlGenerator);
710: }
711:
712: //---AxisProperties
713: htmlGenerator.chartTableRowStart();
714: this .axisProperties.toHTML(htmlGenerator);
715: htmlGenerator.chartTableRowEnd();
716:
717: //---XAxis
718: htmlGenerator.chartTableRowStart();
719: this .xAxis.toHTML(htmlGenerator);
720: htmlGenerator.chartTableRowEnd();
721:
722: //---YAxis
723: htmlGenerator.chartTableRowStart();
724: this .yAxis.toHTML(htmlGenerator);
725: htmlGenerator.chartTableRowEnd();
726:
727: //---ChartProperties
728: htmlGenerator.chartTableRowStart();
729: super.getChartProperties().toHTML(htmlGenerator);
730: htmlGenerator.chartTableRowEnd();
731:
732: if (super.getLegend() != null) {
733: htmlGenerator.chartTableRowStart();
734: this.getLegend().toHTML(htmlGenerator);
735: htmlGenerator.chartTableRowEnd();
736: }
737:
738: htmlGenerator.chartTableEnd();
739: }
740:
741: }
|