Package org.krysalis.jcharts.nonAxisChart

Source Code of org.krysalis.jcharts.nonAxisChart.RadarChart

/***********************************************************************************************
* 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.nonAxisChart;


import com.google.code.appengine.awt.Color;
import com.google.code.appengine.awt.Graphics2D;
import com.google.code.appengine.awt.Paint;
import com.google.code.appengine.awt.Polygon;
import com.google.code.appengine.awt.Rectangle;
import com.google.code.appengine.awt.RenderingHints;
import com.google.code.appengine.awt.font.FontRenderContext;
import com.google.code.appengine.awt.geom.Point2D;
import com.google.code.appengine.awt.geom.Rectangle2D;

import org.krysalis.jcharts.Chart;
import org.krysalis.jcharts.chartData.interfaces.IRadarChartDataSet;
import org.krysalis.jcharts.chartData.processors.RadarChartDataProcessor;
import org.krysalis.jcharts.properties.ChartProperties;
import org.krysalis.jcharts.properties.LegendProperties;
import org.krysalis.jcharts.properties.RadarChartProperties;
import org.krysalis.jcharts.properties.util.ChartFont;


/*************************************************************************************
* Represents a radar chart a.k.a. spider chart
*
* @author Rami Hansenne
* @version $Id: RadarChart.java,v 1.3 2003/08/28 14:36:28 nicolaken Exp $
* @since 1.0.0
************************************************************************************/

public class RadarChart
  extends Chart
{

  private IRadarChartDataSet iRadarChartDataSet;
  private RadarChartDataProcessor radarChartDataProcessor;
  private RadarChartProperties props;
  private double radius, step;
  private Point2D center;

  // scale max value and increment
  private double scaleMax, scaleIncrement;

  // default number of scale increments if no user defined increment
  private static final int DEFAULT_NR_OF_INCREMENTS = 10;


  /************************************************************************************************
   * Constructor
   *
   * @param iRadarChartDataSet
   * @param legendProperties
   * @param chartProperties general chart properties
   * @param pixelWidth
   * @param pixelHeight
   ************************************************************************************************/
  public RadarChart( IRadarChartDataSet iRadarChartDataSet,
               LegendProperties legendProperties,
               ChartProperties chartProperties,
               int pixelWidth,
               int pixelHeight )
  {
    super( legendProperties, chartProperties, pixelWidth, pixelHeight );
    this.iRadarChartDataSet = iRadarChartDataSet;
    props = (RadarChartProperties) iRadarChartDataSet.getChartTypeProperties();
    if( props == null )
    {
      props = new RadarChartProperties();
    }
  }


  /************************************************************************************************
   * Draws the chart
   *
   ************************************************************************************************/
  protected void renderChart()
  {
    Graphics2D g2d = getGraphics2D();

    // turn anti-aliasing on
    g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );


//todo : render legend, use scale processor classes,...

    FontRenderContext fontRenderContext = super.getGraphics2D().
      getFontRenderContext();

    //---render the TITLE. If no title, this will return zero.
    float chartTitleHeight = super.renderChartTitle( this.iRadarChartDataSet.
                                     getChartTitle(), fontRenderContext );

    this.radarChartDataProcessor = new RadarChartDataProcessor( this.iRadarChartDataSet );
    this.radarChartDataProcessor.processData();

    // set scale max value
    if( Double.isNaN( props.getScaleMaxValue() ) )
      this.scaleMax = radarChartDataProcessor.getMaxValue();
    else
      scaleMax = props.getScaleMaxValue();

    // set scale increment
    if( Double.isNaN( props.getScaleIncrement() ) )
      this.scaleIncrement = scaleMax / DEFAULT_NR_OF_INCREMENTS;
    else
      scaleIncrement = props.getScaleIncrement();

    //todo : adjust chart space in order to correctly render title & legend
    Rectangle chartSpace = new Rectangle( getImageWidth(), getImageHeight() );

    center = new Point2D.Double(
      chartSpace.getWidth() / 2 - chartSpace.getX(),
      chartSpace.getHeight() / 2 - chartSpace.getY() );
    radius = Math.min( chartSpace.getWidth(), chartSpace.getHeight() );
    radius = ( radius - ( radius * 10 ) / 100 ) / 2;
    step = 2 * Math.PI / iRadarChartDataSet.getNumberOfDataItems();

    if( props.getShowGridLines() )
    {
      drawGridLines( g2d );
    }
    drawAxis( g2d );
    drawRadar( g2d );
  }


  private void drawRadar(
    Graphics2D g )
  {

    for( int dataset = 0; dataset < iRadarChartDataSet.getNumberOfDataSets();
        dataset++ )
    {

      double currentValue;
      double previousValue = scaleValue( iRadarChartDataSet.getValue( dataset,
                                                 iRadarChartDataSet.getNumberOfDataItems() -
                                                 1 ) );

      Paint paint = iRadarChartDataSet.getPaint( dataset );

      for( int di = 0; di < iRadarChartDataSet.getNumberOfDataItems(); di++ )
      {
        currentValue = previousValue;
        previousValue = scaleValue( iRadarChartDataSet.getValue( dataset, di ) );
        g.setPaint( paint );

        int c0 = (int) Math.round( center.getX() );
        int c1 = (int) Math.round( center.getY() );
        int x0 = getX( di + 1, previousValue );
        int y0 = getY( di + 1, previousValue );
        int x1 = getX( di, currentValue );
        int y1 = getY( di, currentValue );

        if( props.getFillRadar() )
        {
          Polygon p = new Polygon();
          p.addPoint( c0, c1 );
          p.addPoint( x0, y0 );
          p.addPoint( x1, y1 );
          // make color translucent
          if( paint instanceof Color )
          {
            Color color = (Color) paint;
            g.setPaint( new Color( color.getRed(), color.getGreen(),
                            color.getBlue(), 100 ) );
          }
          g.fillPolygon( p );
          g.setPaint( paint );
        }
        g.drawLine( x0, y0, x1, y1 );
      }
    }
  }


  private void drawGridLines( Graphics2D g )
  {
    g.setColor( Color.lightGray );
    for( int di = 0; di < iRadarChartDataSet.getNumberOfDataItems();
        di++ )
    {
      for( double i = scaleIncrement; i <= scaleMax; i += scaleIncrement )
      {
        double pos = scaleValue( i );
        g.drawLine(
          getX( di + 1, pos ),
          getY( di + 1, pos ),
          getX( di, pos ),
          getY( di, pos ) );
      }
    }
  }


  private void drawAxis( Graphics2D g )
  {
    g.setColor( Color.darkGray );
    for( int index = 0; index < iRadarChartDataSet.getNumberOfDataItems();
        index++ )
    {
      String label = iRadarChartDataSet.getAxisLabel( index );
      g.drawLine(
        (int) center.getX(),
        (int) center.getY(),
        getX( index, 1 ),
        getY( index, 1 ) );

      Rectangle2D bounds = g.getFontMetrics().getStringBounds( label, g );

      // draw axis label
      ChartFont cfont = props.getTitleChartFont();
      if( cfont != null )
      {
        g.setFont( cfont.getFont() );

      }
      g.drawString(
        label,
        (int) ( getX( index + 1, 1 ) - bounds.getWidth() / 2 ),
        getY( index + 1, 1 ) );
    }

    // draw gridline labels
    g.setColor( Color.darkGray );
    g.setFont( ChartFont.DEFAULT_AXIS_VALUE.getFont() );
    int selectedLine = (int) iRadarChartDataSet.getNumberOfDataItems() / 2;
    for( double i = scaleIncrement; i <= scaleMax; i += scaleIncrement )
    {
      double pos = scaleValue( i );
      Rectangle2D bounds = g.getFont().getStringBounds( "1",
                                        g.getFontRenderContext() );
      g.drawString( props.getGridLabelFormat().format( i ),
                getX( selectedLine, pos ),
                (int) Math.round( getY( selectedLine, pos ) + bounds.getHeight() ) );
    }

  }


  private int getX( int dataset, double factor )
  {
    return (int) Math.round( center.getX() + radius * factor * Math.sin( step * dataset ) );
  }


  private int getY( int dataset, double factor )
  {
    return (int) Math.round( center.getY() + radius * factor * Math.cos( step * dataset ) );
  }


  private double scaleValue( double value )
  {
    if( value > scaleMax )
      value = scaleMax;
    if( scaleMax == 0 )
      return 0;
    return value / scaleMax;
  }

}
TOP

Related Classes of org.krysalis.jcharts.nonAxisChart.RadarChart

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.