/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.plugin.jfreereport.reportcharts;
import org.jfree.chart.axis.LogarithmicAxis;
import org.jfree.chart.axis.NumberTick;
import org.jfree.chart.plot.ValueAxisPlot;
import org.jfree.data.Range;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.TextAnchor;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
public class ScalingLogarithmicAxis extends LogarithmicAxis {
private static final long serialVersionUID = 1L;
private int ticksVertical = -1;
public ScalingLogarithmicAxis( final String label ) {
super( label );
}
public void autoAdjustRange() {
super.autoAdjustRange();
if ( getPlot() instanceof ValueAxisPlot ) {
final Range range = this.getRange();
setRange( new Range( range.getLowerBound() * 10.0, range.getUpperBound() * 10.0 ), false, false );
setupSmallLogFlag();
}
}
protected List refreshTicksVertical( final Graphics2D g2,
final Rectangle2D dataArea,
final RectangleEdge edge ) {
final ArrayList ticks = new ArrayList();
// get lower bound value:
double lowerBoundVal = getRange().getLowerBound();
// if small log values and lower bound value too small
// then set to a small value (don't allow <= 0):
if ( this.smallLogFlag && lowerBoundVal < SMALL_LOG_VALUE ) {
lowerBoundVal = SMALL_LOG_VALUE;
}
// get upper bound value
final double upperBoundVal = getRange().getUpperBound();
// get log10 version of lower bound and round to integer:
int iBegCount = (int) Math.rint( switchedLog10( lowerBoundVal ) );
// get log10 version of upper bound and round to integer:
final int iEndCount = (int) Math.rint( switchedLog10( upperBoundVal ) );
if ( iBegCount == iEndCount && iBegCount > 0
&& Math.pow( 10, iBegCount ) > lowerBoundVal ) {
// only 1 power of 10 value, it's > 0 and its resulting
// tick value will be larger than lower bound of data
--iBegCount; // decrement to generate more ticks
}
double tickVal;
String tickLabel;
boolean zeroTickFlag = false;
final int[] intervals = { 10, 10, 10, 10, 10, 5, 5, 5, 3, 3 };
for ( int i = iBegCount; i <= iEndCount; i++ ) {
// for each tick with a label to be displayed
int jEndCount = getTicksVertical();
if ( jEndCount == -1 ) {
jEndCount = Math.abs( iEndCount - iBegCount ) < 10 ? intervals[ iEndCount - iBegCount ] : 1;
}
if ( i == iEndCount ) {
jEndCount = 1;
}
for ( int j = 0; j < jEndCount; j++ ) {
// for each tick to be displayed
if ( this.smallLogFlag ) {
// small log values in use
tickVal = Math.pow( 10, i ) + ( Math.pow( 10, i ) * j );
if ( j == 0 ) {
// first tick of group; create label text
if ( this.log10TickLabelsFlag ) {
// if flag then
tickLabel = "10^" + i; // create "log10"-type label
} else { // not "log10"-type label
if ( this.expTickLabelsFlag ) {
// if flag then
tickLabel = "1e" + i; // create "1e#"-type label
} else { // not "1e#"-type label
if ( i >= 0 ) { // if positive exponent then
// make integer
final NumberFormat format
= getNumberFormatOverride();
if ( format != null ) {
tickLabel = format.format( tickVal );
} else {
tickLabel = LogCategoryItemLabelGenerator.formatValue( new Double( tickVal ) );
/*tickLabel = Long.toString((long) Math.rint(tickVal));*/
}
} else {
// negative exponent; create fractional value
// set exact number of fractional digits to
// be shown:
this.numberFormatterObj
.setMaximumFractionDigits( -i );
// create tick label:
tickLabel = this.numberFormatterObj.format(
tickVal
);
}
}
}
} else { // not first tick to be displayed
tickLabel = ""; // no tick label
}
} else { // not small log values in use; allow for values <= 0
if ( zeroTickFlag ) { // if did zero tick last iter then
--j;
} // decrement to do 1.0 tick now
tickVal = ( i >= 0 ) ? Math.pow( 10, i ) + ( Math.pow( 10, i ) * j )
: j == 0 ? -Math.pow( 10, -i ) : -( Math.pow( 10, -i ) - ( Math.pow( 10, -i - 1 ) * ( 9 - j ) ) );
if ( j == 0 ) { // first tick of group
if ( !zeroTickFlag ) { // did not do zero tick last
// iteration
if ( i > iBegCount && i < iEndCount
&& Math.abs( tickVal - 1.0 ) < 0.0001 ) {
// not first or last tick on graph and value
// is 1.0
tickVal = 0.0; // change value to 0.0
zeroTickFlag = true; // indicate zero tick
tickLabel = "0"; // create label for tick
} else {
// first or last tick on graph or value is 1.0
// create label for tick:
if ( this.log10TickLabelsFlag ) {
// create "log10"-type label
tickLabel = ( ( ( i < 0 ) ? "-" : "" )
+ "10^" + Math.abs( i ) );
} else {
if ( this.expTickLabelsFlag ) {
// create "1e#"-type label
tickLabel = ( ( ( i < 0 ) ? "-" : "" )
+ "1e" + Math.abs( i ) );
} else {
final NumberFormat format
= getNumberFormatOverride();
if ( format != null ) {
tickLabel = format.format( tickVal );
} else {
tickLabel = LogCategoryItemLabelGenerator.formatValue( new Double( tickVal ) );/*
tickLabel = Long.toString((long) Math.rint(tickVal));*/
}
}
}
}
} else { // did zero tick last iteration
tickLabel = ""; // no label
zeroTickFlag = false; // clear flag
}
} else { // not first tick of group
tickLabel = ""; // no label
zeroTickFlag = false; // make sure flag cleared
}
}
if ( tickVal > upperBoundVal ) {
return ticks; // if past highest data value then exit method
}
if ( tickVal >= lowerBoundVal - SMALL_LOG_VALUE ) {
// tick value not below lowest data value
final TextAnchor anchor;
final TextAnchor rotationAnchor;
double angle = 0.0;
if ( isVerticalTickLabels() ) {
if ( edge == RectangleEdge.LEFT ) {
anchor = TextAnchor.BOTTOM_CENTER;
rotationAnchor = TextAnchor.BOTTOM_CENTER;
angle = -Math.PI / 2.0;
} else {
anchor = TextAnchor.BOTTOM_CENTER;
rotationAnchor = TextAnchor.BOTTOM_CENTER;
angle = Math.PI / 2.0;
}
} else {
if ( edge == RectangleEdge.LEFT ) {
anchor = TextAnchor.CENTER_RIGHT;
rotationAnchor = TextAnchor.CENTER_RIGHT;
} else {
anchor = TextAnchor.CENTER_LEFT;
rotationAnchor = TextAnchor.CENTER_LEFT;
}
}
ticks.add( new NumberTick( new Double( tickVal ), tickLabel, anchor, rotationAnchor, angle ) );
}
}
}
return ticks;
}
public void setTicksVertical( final int ticksVertical ) {
this.ticksVertical = ticksVertical;
}
public int getTicksVertical() {
return ticksVertical;
}
}