Package org.krysalis.jcharts.axisChart.axis

Source Code of org.krysalis.jcharts.axisChart.axis.XAxis

/***********************************************************************************************
* Copyright 2002 (C) Nathaniel G. Auvil. All Rights Reserved.
*
* Redistribution and use of this software and associated documentation ("Software"), with or
* without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright statements and notices.
*   Redistributions must also contain a copy of this document.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
*   conditions and the following disclaimer in the documentation and/or other materials
*   provided with the distribution.
*
* 3. The name "jCharts" or "Nathaniel G. Auvil" must not be used to endorse or promote
*   products derived from this Software without prior written permission of Nathaniel G.
*   Auvil.  For written permission, please contact nathaniel_auvil@users.sourceforge.net
*
* 4. Products derived from this Software may not be called "jCharts" nor may "jCharts" appear
*   in their names without prior written permission of Nathaniel G. Auvil. jCharts is a
*   registered trademark of Nathaniel G. Auvil.
*
* 5. Due credit should be given to the jCharts Project (http://jcharts.sourceforge.net/).
*
* THIS SOFTWARE IS PROVIDED BY Nathaniel G. Auvil AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
* jCharts OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
************************************************************************************************/


package org.krysalis.jcharts.axisChart.axis;


import org.krysalis.jcharts.axisChart.AxisChart;
import org.krysalis.jcharts.properties.*;
import org.krysalis.jcharts.test.HTMLGenerator;
import org.krysalis.jcharts.test.HTMLTestable;
import org.krysalis.jcharts.chartData.interfaces.IAxisPlotDataSet;
import org.krysalis.jcharts.chartData.interfaces.IAxisDataSeries;
import org.krysalis.jcharts.types.ChartType;

import com.google.code.appengine.awt.*;
import com.google.code.appengine.awt.geom.Line2D;
import java.lang.reflect.Field;
import java.util.Iterator;


/*************************************************************************************
*
* @author Nathaniel Auvil, John Thomson
* @version $Id: XAxis.java,v 1.3 2003/06/29 14:14:28 nathaniel_auvil Exp $
************************************************************************************/
public class XAxis extends Axis implements HTMLTestable
{
  //---indicates which labels to display 1=every, 2=every other, 3=every third, etc...
  private int xLabelFilter = 1;

  //---for some charts such as line, point, area, etc... we want to start plot at y-axis
  private boolean startTicksAtAxis;


  /**************************************************************************************************
   *
   * @param axisChart
   * @param numberOfScaleItems
   ***************************************************************************************************/
  public XAxis( AxisChart axisChart, int numberOfScaleItems )
  {
    super( axisChart, numberOfScaleItems );
  }


  /*************************************************************************************************
   * Computes the minimum pixel height required for the X-Axis.
   *  Includes space, if needed, for: axis title + padding, axis values + tick padding, and tick marks.
   *
   * @param axisTitle
   **************************************************************************************************/
  public void computeMinimumHeightNeeded( String axisTitle )
  {
    float heightNeeded = 0;
    AxisProperties axisProperties = super.getAxisChart().getAxisProperties();
    AxisTypeProperties axisTypeProperties = axisProperties.getXAxisProperties();


    if( axisTypeProperties.showAxisLabels() )
    {
      if( axisProperties.xAxisLabelsAreVertical() )
      {
        //---widest label for vertical labels
        //heightNeeded = axisChartDataProcessor.getAxisLabelProcessor().getWidestLabel();
        heightNeeded = super.getAxisLabelsGroup().getWidestLabel();
      }
      else
      {
        //---tallest label for horizontal labels
        //heightNeeded = axisChartDataProcessor.getAxisLabelProcessor().getTallestLabel();
        heightNeeded = super.getAxisLabelsGroup().getTallestLabel();

        //---not sure why i need more padding
        heightNeeded += 3;
      }
    }


    if( axisTypeProperties.getShowTicks() != AxisTypeProperties.TICKS_NONE )
    {
      if( axisTypeProperties.showAxisLabels() )
      {
        //---add the padding between scale labels and tick marks
        heightNeeded += axisTypeProperties.getPaddingBetweenLabelsAndTicks();
      }

      //---add width of tick marks
      heightNeeded += axisTypeProperties.getAxisTickMarkPixelLength();
    }
    else
    {
      //---use specified distance between labels and axis
      heightNeeded += axisTypeProperties.getPaddingBetweenAxisAndLabels();
    }


    //---include axis title height if needed. Remember it is vertical for y-axis
    if( axisTitle != null )
    {
      super.computeAxisTitleDimensions( axisTitle, axisTypeProperties.getTitleChartFont() );
      heightNeeded += super.getTitleHeight();
      heightNeeded += axisTypeProperties.getPaddingBetweenAxisTitleAndLabels();
    }

    super.setMinimumHeightNeeded( heightNeeded );
  }


  /*************************************************************************************************
   * Computes the number of pixels between each value on the axis.
   *
   **************************************************************************************************
   public void computeScalePixelWidth( int numberOfValuesOnXAxis )
   {
   super.setScalePixelWidth( super.getPixelLength() / numberOfValuesOnXAxis );
   }


   /****************************************************************************************************
   *
   * @param axisTitle
   * @param graphics2D
   * @param axisTypeProperties
   ***************************************************************************************************/
  private void renderAxisTitle( String axisTitle, Graphics2D graphics2D, AxisTypeProperties axisTypeProperties )
  {
    if( axisTitle != null )
    {
      float titleX;
      float titleY = super.getAxisChart().getYAxis().getOrigin() + this.getMinimumHeightNeeded() - super.getTitleHeight();

      //---if title is larger than the axis itself, place at top.
      if( super.getTitleWidth() > super.getPixelLength() )
      {
        titleX = ((super.getAxisChart().getImageWidth() - super.getTitleWidth()) / 2);
      }
      //---else, center on XAxis.
      else
      {
        titleX = super.getOrigin() + ((super.getPixelLength() - super.getTitleWidth()) / 2);
      }


      axisTypeProperties.getAxisTitleChartFont().setupGraphics2D( graphics2D );
      graphics2D.drawString( axisTitle, titleX, titleY );
    }
  }


  /***************************************************************************************
   * Determines if we should start x-axis ticks at the y-axis or space it out a half
   *   a scale item width.
   *
   * @param iAxisDataSeries
   * @param axisTypeProperties
   **************************************************************************************/
  public void computeShouldTickStartAtYAxis( IAxisDataSeries iAxisDataSeries,
                               AxisTypeProperties axisTypeProperties )
  {
    //---if horizontal plot, x-axis is the data axis, so always start data points at y-axis
    if( axisTypeProperties instanceof DataAxisProperties )
    {
      this.startTicksAtAxis= true;
    }
    else
    {
      this.startTicksAtAxis= true;

      //---else, there are a couple of plots we do not start x-axis values at the y-axis
      IAxisPlotDataSet iAxisPlotDataSet;
      Iterator iterator= iAxisDataSeries.getIAxisPlotDataSetIterator();
//todo what about combo charts?
      while( iterator.hasNext() )
      {
        iAxisPlotDataSet= (IAxisPlotDataSet) iterator.next();
        if( iAxisPlotDataSet.getChartType().equals( ChartType.BAR )
          || iAxisPlotDataSet.getChartType().equals( ChartType.BAR_CLUSTERED )
          || iAxisPlotDataSet.getChartType().equals( ChartType.BAR_STACKED )
          || iAxisPlotDataSet.getChartType().equals( ChartType.LINE )
          || iAxisPlotDataSet.getChartType().equals( ChartType.POINT )
          || iAxisPlotDataSet.getChartType().equals( ChartType.STOCK ) )
        {
          this.startTicksAtAxis= false;
          break;
        }
      }
    }
  }


  /***************************************************************************************
   * Computes the screen pixel location of the first tick mark
   *
   **************************************************************************************/
  public void computeTickStart()
  {
    float tickStart= super.getOrigin();

    if( ! this.startTicksAtAxis )
    {
      tickStart+= (super.getScalePixelWidth() / 2);
    }

      super.setTickStart( tickStart );
  }


  /*************************************************************************************************
   * Computes the number of pixels between each value on the axis.
   *
   * @param axisTypeProperties
   *************************************************************************************************/
  public void computeScalePixelWidth( AxisTypeProperties axisTypeProperties )
  {
    if( this.startTicksAtAxis )
    {
      super.computeScalePixelWidthDataAxis( axisTypeProperties );
    }
    else
    {
      super.setScalePixelWidth( getPixelLength() / this.getNumberOfScaleItems() );
    }
  }


  /*********************************************************************************************
   * Renders the YAxis on the passes Graphics2D object
   *
   * @param graphics2D
   * @param axisProperties
   * @param axisTitle
   **********************************************************************************************/
  public void render( Graphics2D graphics2D,
                AxisProperties axisProperties,
                String axisTitle )
  {
    AxisTypeProperties axisTypeProperties = axisProperties.getXAxisProperties();


    //---AXIS TITLE
    this.renderAxisTitle( axisTitle, graphics2D, axisTypeProperties );

    Line2D.Float line2D = new Line2D.Float( super.getTickStart(), 0.0f, super.getTickStart(), 0.0f );
    float tickY1 = super.getAxisChart().getYAxis().getOrigin();
    float tickY2 = super.getAxisChart().getYAxis().getOrigin() + axisTypeProperties.getAxisTickMarkPixelLength();
    float gridLineY1 = super.getAxisChart().getYAxis().getOrigin();
    float gridLineY2 = super.getAxisChart().getYAxis().getOrigin() - super.getAxisChart().getYAxis().getPixelLength();


    float stringX = super.getTickStart();
    float stringY = super.getAxisChart().getYAxis().getOrigin();
    if( axisTypeProperties.getShowTicks() != AxisTypeProperties.TICKS_NONE )
    {
      stringY += axisTypeProperties.getAxisTickMarkPixelLength() + axisTypeProperties.getPaddingBetweenLabelsAndTicks();
    }
    else
    {
      stringY += axisTypeProperties.getPaddingBetweenAxisAndLabels();
    }


    if( axisTypeProperties.showAxisLabels() )
    {
      //---if the scale labels are horizontal, simply add the tallest label height.
      //---Otherwise we will have to calculate it when we draw the label
      if( !axisProperties.xAxisLabelsAreVertical() )
      {
        stringY += super.getAxisLabelsGroup().getTallestLabel();
        graphics2D.setFont( axisTypeProperties.getScaleChartFont().getFont() );
      }
      else
      {
        stringX -= super.getAxisLabelsGroup().getTextTag( 0 ).getFontDescent();
        graphics2D.setFont( axisTypeProperties.getScaleChartFont().deriveFont() );
      }
    }


    //LOOP
    //for( int i = 0; i < super.getAxisLabelsGroup().size(); i++ )
    for( int i = 0; i < super.getNumberOfScaleItems(); i++ )
    {
      //---GRID LINES
      if( axisTypeProperties.getShowGridLines() != AxisTypeProperties.GRID_LINES_NONE )
      {
        if( ( i == 0 && !( axisTypeProperties instanceof DataAxisProperties ) )
          || ( i > 0 && ( (axisTypeProperties.getShowGridLines() == AxisTypeProperties.GRID_LINES_ALL|| (axisTypeProperties.getShowGridLines() == AxisTypeProperties.GRID_LINES_ONLY_WITH_LABELS && (i % this.xLabelFilter == 0)) ) ) )
        {
          line2D.y1 = gridLineY1;
          line2D.y2 = gridLineY2;

          if( i < super.getAxisLabelsGroup().size()
            || (i == super.getAxisLabelsGroup().size() && !axisTypeProperties.getShowEndBorder()) )
          {
            axisTypeProperties.getGridLineChartStroke().draw( graphics2D, line2D );
          }
        }
      }

      //---TICK MARKS
      //if( i != super.getAxisLabelsGroup().size() )
      if( i != super.getNumberOfScaleItems() )
      {
        if( (axisTypeProperties.getShowTicks() == AxisTypeProperties.TICKS_ALL)
          || (axisTypeProperties.getShowTicks() == AxisTypeProperties.TICKS_ONLY_WITH_LABELS
          && (i % this.xLabelFilter == 0)) )
        {
          line2D.y1 = tickY1;
          line2D.y2 = tickY2;

          axisTypeProperties.getTickChartStroke().setupGraphics2D( graphics2D );
          graphics2D.draw( line2D );
        }
      }

      line2D.x1 += super.getScalePixelWidth();
      line2D.x2 = line2D.x1;


      //---AXIS LABEL
      if( axisTypeProperties.showAxisLabels() && (i % this.xLabelFilter == 0) )
      {
        graphics2D.setPaint( axisTypeProperties.getScaleChartFont().getPaint() );

        if( !axisProperties.xAxisLabelsAreVertical() )
        {
          //graphics2D.drawString( iDataSeries.getXAxisLabel( i ), stringX - super.getAxisLabelsGroup().getTextTag( i ).getWidth() / 2, stringY );
          float x = stringX - super.getAxisLabelsGroup().getTextTag( i ).getWidth() / 2;

          //---we can not only look at the last label as there could be a filter and labels near the last might go off the edge of the screen.
          if( x + super.getAxisLabelsGroup().getTextTag( i ).getWidth() < super.getAxisChart().getImageWidth() )
          {
            super.getAxisLabelsGroup().getTextTag( i ).render( graphics2D, x, stringY );
          }
        }
        else
        {
          float x = stringX + super.getAxisLabelsGroup().getTextTag( i ).getHeight() / 2;

          //---we can not only look at the last label as there could be a filter and labels near the last might go off the edge of the screen.
          if( x + super.getAxisLabelsGroup().getTextTag( i ).getHeight() < super.getAxisChart().getImageWidth() )
          {
            graphics2D.drawString( super.getAxisLabelsGroup().getTextTag( i ).getText(), x, stringY + super.getAxisLabelsGroup().getTextTag( i ).getWidth() );
          }
        }
      }
      stringX += super.getScalePixelWidth();
    }


    //---RIGHT BORDER-----------------------------------------------------------
    if( axisTypeProperties.getShowEndBorder() )
    {
      //---make sure no rounding errors
      line2D.x1 = super.getOrigin() + super.getPixelLength();
      line2D.x2 = line2D.x1;
      line2D.y1 = gridLineY1;
      line2D.y2 = gridLineY2;
      axisProperties.getYAxisProperties().getAxisStroke().draw( graphics2D, line2D );
    }


    //---AXIS-------------------------------------------------------------------
    line2D.x1 = super.getOrigin();
    line2D.x2 = super.getOrigin() + super.getPixelLength();
    line2D.y1 = super.getAxisChart().getYAxis().getOrigin();
    line2D.y2 = line2D.y1;
    axisTypeProperties.getAxisStroke().setupGraphics2D( graphics2D );
    graphics2D.draw( line2D );


    //---ZERO LINE-----------------------------------------------------------------
    if( axisTypeProperties instanceof DataAxisProperties )
    {
      DataAxisProperties dataAxisProperties = (DataAxisProperties) axisTypeProperties;

      if( dataAxisProperties.showZeroLine()
        && super.getScaleCalculator().getMinValue() < 0.0d
        && super.getScaleCalculator().getMaxValue() > 0.0d )
      {
        line2D.x1 = super.getZeroLineCoordinate();
        line2D.x2 = line2D.x1;
        line2D.y1 = super.getAxisChart().getYAxis().getOrigin();
        line2D.y2 = super.getAxisChart().getYAxis().getOrigin() - super.getAxisChart().getYAxis().getPixelLength();
        dataAxisProperties.getZeroLineChartStroke().draw( graphics2D, line2D );
      }
    }
  }


  /************************************************************************************************
   * Method to compute the filter to use on the x-axis label display so labels do not overlap
   *
   *************************************************************************************************/
  public void computeLabelFilter()
  {
    if( super.getAxisChart().getAxisProperties().getXAxisProperties().showAxisLabels() )
    {
      float widestLabelSize;
      AxisTypeProperties axisTypeProperties = super.getAxisChart().getAxisProperties().getXAxisProperties();

      if( super.getAxisChart().getAxisProperties().xAxisLabelsAreVertical() )
      {
        widestLabelSize = super.getAxisLabelsGroup().getTallestLabel();
      }
      else
      {
        widestLabelSize = super.getAxisLabelsGroup().getWidestLabel();
      }

      double numberLabelsCanDisplay = this.getPixelLength() / (widestLabelSize + axisTypeProperties.getPaddingBetweenAxisLabels());
      this.xLabelFilter = (int) Math.ceil( super.getAxisLabelsGroup().size() / numberLabelsCanDisplay );
    }
    else
    {
      this.xLabelFilter= 1;
    }
  }


  /*********************************************************************************************
   * Enables the testing routines to display the contents of this Object.
   *
   * @param htmlGenerator
   **********************************************************************************************/
  public void toHTML( HTMLGenerator htmlGenerator )
  {
    htmlGenerator.propertiesTableStart( this.getClass().getName() );

    super.toHTML( htmlGenerator );

    Field[] fields = this.getClass().getDeclaredFields();
    for( int i = 0; i < fields.length; i++ )
    {
      try
      {
        htmlGenerator.addField( fields[ i ].getName(), fields[ i ].get( this ) );
      }
      catch( IllegalAccessException illegalAccessException )
      {
        illegalAccessException.printStackTrace();
      }
    }

    htmlGenerator.propertiesTableEnd();
  }


  /*************************************************************************************************
   * Takes a value and determines the screen coordinate it should be drawn at. THe only difference
   *   between this and the y-axis is we add to the origin versus subtract from it.
   *
   * @param origin
   * @param value
   * @param axisMinValue the minimum value on the axis
   * @return float the screen pixel coordinate
   **************************************************************************************************/
  public float computeAxisCoordinate( float origin, double value, double axisMinValue )
  {
    double returnValue = origin + (value - axisMinValue) * this.getOneUnitPixelSize();
//System.out.println( "computeAxisCoordinate( " + origin + ", " + value + ", " + axisMinValue + " ) = " + returnValue );
    return (float) returnValue;
  }

}
TOP

Related Classes of org.krysalis.jcharts.axisChart.axis.XAxis

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.