package jyplot;

import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.jfree.chart.axis.AxisState;
import org.jfree.chart.axis.NumberTick;
import org.jfree.chart.axis.SymbolAxis;
import org.jfree.chart.axis.Tick;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.axis.ValueTick;
import org.jfree.text.TextUtilities;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.TextAnchor;

public class CustomSymbolAxis extends SymbolAxis
{
	/** The list of symbol locations */
	private HashMap locationToSymbolMap;
	private Double[] symbolLocations;
	
	
	
	/*
	 * From superclass
	 */
	/** The list of symbols to display instead of the numeric values. */
	private List symbols;
	
	/** The paint used to color the grid bands (if the bands are visible). */
	private transient Paint gridBandPaint;

	/** Flag that indicates whether or not grid bands are visible. */
	private boolean gridBandsVisible;

	public CustomSymbolAxis(String label, String[] sv, double[] symbolLocations)
	{
		super(label, sv);
		
		// if(sv != null)
		// {
			this.symbols = Arrays.asList(sv);
			this.gridBandsVisible = true;
			this.gridBandPaint = DEFAULT_GRID_BAND_PAINT;
			
			
			locationToSymbolMap = new HashMap();
			this.symbolLocations = new Double[symbolLocations.length];
			
			for (int i = 0; i < symbolLocations.length && i < sv.length; i++)
			{
				locationToSymbolMap.put(new Double(symbolLocations[i]), sv[i]);
				
			}
			Arrays.sort(symbolLocations);
			for (int i = 0; i < symbolLocations.length; i++)
			{
				this.symbolLocations[i] = new Double(symbolLocations[i]);
			}
		// }
		setAutoTickUnitSelection(false, false);
		setAutoRangeStickyZero(false);
	}
	
	/**
	 * Calculates the positions of the tick labels for the axis, storing the 
	 * results in the tick label list (ready for drawing).
	 *
	 * @param g2  the graphics device.
	 * @param state  the axis state.
	 * @param dataArea  the area in which the data should be drawn.
	 * @param edge  the location of the axis.
	 * 
	 * @return A list of ticks.
	 */
	public List refreshTicks(Graphics2D g2, AxisState state, Rectangle2D dataArea, RectangleEdge edge)
	{
		List ticks = null;
		if(RectangleEdge.isTopOrBottom(edge))
		{
			ticks = refreshTicksHorizontal(g2, dataArea, edge);
		}
		else if(RectangleEdge.isLeftOrRight(edge))
		{
			ticks = refreshTicksVertical(g2, dataArea, edge);
		}
		return ticks;
	}
	
	/**
	 * Calculates the positions of the tick labels for the axis, storing the 
	 * results in the tick label list (ready for drawing).
	 *
	 * @param g2  the graphics device.
	 * @param dataArea  the area in which the data should be drawn.
	 * @param edge  the location of the axis.
	 * 
	 * @return The ticks.
	 */
	protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge)
	{

		List ticks = new java.util.ArrayList();

		Font tickLabelFont = getTickLabelFont();
		g2.setFont(tickLabelFont);

		double size = getTickUnit().getSize();
		int count = calculateVisibleTickCount();
		double lowestTickValue = calculateLowestVisibleTickValue();

		double previousDrawnTickLabelPos = 0.0;
		double previousDrawnTickLabelLength = 0.0;

		if(count <= ValueAxis.MAXIMUM_TICK_COUNT)
		{
			//for (int i = 0; i < count; i++)
			for (int i = 0; i < this.symbolLocations.length; i++)
			{
//				this.symbolLocations locationToSymbolMap symbols
				double currentTickValue = this.symbolLocations[i];// lowestTickValue + (i * size);
				double xx = valueToJava2D(currentTickValue, dataArea, edge);
				String tickLabel;
				NumberFormat formatter = getNumberFormatOverride();
				
				if(this.locationToSymbolMap.containsKey(new Double(currentTickValue)))
				{
					tickLabel = this.locationToSymbolMap.get(new Double(currentTickValue));
				}
				else 
				if(formatter != null)
				{
					tickLabel = formatter.format(currentTickValue);
				}
				else
				{
					tickLabel = valueToString(currentTickValue);
				}

				// avoid to draw overlapping tick labels
				Rectangle2D bounds = TextUtilities.getTextBounds(tickLabel, g2, g2.getFontMetrics());
				double tickLabelLength = isVerticalTickLabels() ? bounds.getHeight() : bounds.getWidth();
				boolean tickLabelsOverlapping = false;
				if(i > 0)
				{
					double avgTickLabelLength = (previousDrawnTickLabelLength + tickLabelLength) / 2.0;
					if(Math.abs(xx - previousDrawnTickLabelPos) < avgTickLabelLength)
					{
						tickLabelsOverlapping = true;
					}
				}
				if(tickLabelsOverlapping)
				{
					tickLabel = ""; // don't draw this tick label
				}
				else
				{
					// remember these values for next comparison
					previousDrawnTickLabelPos = xx;
					previousDrawnTickLabelLength = tickLabelLength;
				}

				TextAnchor anchor = null;
				TextAnchor rotationAnchor = null;
				double angle = 0.0;
				if(isVerticalTickLabels())
				{
					anchor = TextAnchor.CENTER_RIGHT;
					rotationAnchor = TextAnchor.CENTER_RIGHT;
					if(edge == RectangleEdge.TOP)
					{
						angle = Math.PI / 2.0;
					}
					else
					{
						angle = -Math.PI / 2.0;
					}
				}
				else
				{
					if(edge == RectangleEdge.TOP)
					{
						anchor = TextAnchor.BOTTOM_CENTER;
						rotationAnchor = TextAnchor.BOTTOM_CENTER;
					}
					else
					{
						anchor = TextAnchor.TOP_CENTER;
						rotationAnchor = TextAnchor.TOP_CENTER;
					}
				}
				Tick tick = new NumberTick(new Double(currentTickValue), tickLabel, anchor, rotationAnchor, angle);
				ticks.add(tick);
			}
		}
		return ticks;

	}
	
    /**
     * Draws the axis line, tick marks and tick mark labels.
     * 
     * @param g2  the graphics device.
     * @param cursor  the cursor.
     * @param plotArea  the plot area.
     * @param dataArea  the data area.
     * @param edge  the edge that the axis is aligned with.
     * 
     * @return The width or height used to draw the axis.
     */
    protected AxisState drawTickMarksAndLabels(Graphics2D g2, 
                                               double cursor,
                                               Rectangle2D plotArea,
                                               Rectangle2D dataArea, 
                                               RectangleEdge edge) {
                                              
        AxisState state = new AxisState(cursor);

        if (isAxisLineVisible()) {
            drawAxisLine(g2, cursor, dataArea, edge);
        }

        double ol = getTickMarkOutsideLength();
        double il = getTickMarkInsideLength();

        List ticks = refreshTicks(g2, state, dataArea, edge);
        state.setTicks(ticks);
        g2.setFont(getTickLabelFont());
        Iterator iterator = ticks.iterator();
        while (iterator.hasNext()) {
            ValueTick tick = (ValueTick) iterator.next();
            if (isTickLabelsVisible()) {
                g2.setPaint(getTickLabelPaint());
                float[] anchorPoint = calculateAnchorPoint(
                    tick, cursor, dataArea, edge
                );
                TextUtilities.drawRotatedString(
                    tick.getText(), g2, 
                    anchorPoint[0], anchorPoint[1],
                    tick.getTextAnchor(), 
                    tick.getAngle(),
                    tick.getRotationAnchor()
                );
            }

            if (isTickMarksVisible()) {
                float xx = (float) valueToJava2D(
                    tick.getValue(), dataArea, edge
                );
                Line2D mark = null;
                g2.setStroke(getTickMarkStroke());
                g2.setPaint(getTickMarkPaint());
                if (edge == RectangleEdge.LEFT) {
                    mark = new Line2D.Double(cursor - ol, xx, cursor + il, xx);
                }
                else if (edge == RectangleEdge.RIGHT) {
                    mark = new Line2D.Double(cursor + ol, xx, cursor - il, xx);
                }
                else if (edge == RectangleEdge.TOP) {
                    mark = new Line2D.Double(xx, cursor - ol, xx, cursor + il);
                }
                else if (edge == RectangleEdge.BOTTOM) {
                    mark = new Line2D.Double(xx, cursor + ol, xx, cursor - il);
                }
                g2.draw(mark);
            }
        }
        
        // need to work out the space used by the tick labels...
        // so we can update the cursor...
        double used = 0.0;
        if (isTickLabelsVisible()) {
            if (edge == RectangleEdge.LEFT) {
                used += findMaximumTickLabelWidth(
                    ticks, g2, plotArea, isVerticalTickLabels()
                );  
                state.cursorLeft(used);      
            }
            else if (edge == RectangleEdge.RIGHT) {
                used = findMaximumTickLabelWidth(
                    ticks, g2, plotArea, isVerticalTickLabels()
                );
                state.cursorRight(used);      
            }
            else if (edge == RectangleEdge.TOP) {
                used = findMaximumTickLabelHeight(
                    ticks, g2, plotArea, isVerticalTickLabels()
                );
                state.cursorUp(used);
            }
            else if (edge == RectangleEdge.BOTTOM) {
                used = findMaximumTickLabelHeight(
                    ticks, g2, plotArea, isVerticalTickLabels()
                );
                state.cursorDown(used);
            }
        }
       
        return state;
    }
    
    /**
     * Calculates the value of the lowest visible tick on the axis.
     *
     * @return The value of the lowest visible tick on the axis.
     */
    protected double calculateLowestVisibleTickValue() {

//        double unit = getTickUnit().getSize();
//        double index = Math.ceil(getRange().getLowerBound() / unit);
//        return index * unit;

    	double lowerbound = getRange().getLowerBound();
    	for (int i = 0; i < this.symbolLocations.length; i++)
		{
			if(this.symbolLocations[i] > lowerbound)
				return this.symbolLocations[i];
		}
    	return 0;
    }

    /**
     * Calculates the value of the highest visible tick on the axis.
     *
     * @return The value of the highest visible tick on the axis.
     */
    protected double calculateHighestVisibleTickValue() {

//        double unit = getTickUnit().getSize();
//        double index = Math.floor(getRange().getUpperBound() / unit);
//        return index * unit;
    	
    	double upperbound = getRange().getUpperBound();
    	for (int i = this.symbolLocations.length - 1; i >= 0; i--)
		{
			if(this.symbolLocations[i] < upperbound)
				return this.symbolLocations[i];
		}
    	return 0;

    }

}

 

Ads help maintain this website.