/*
* 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) 2009 Pentaho Corporation. All rights reserved.
*/
package org.pentaho.plugin.jfreereport.reportcharts;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;
import java.util.List;
import java.util.ArrayList;
import org.jfree.chart.axis.NumberTick;
import org.jfree.chart.axis.LogarithmicAxis;
import org.jfree.chart.plot.ValueAxisPlot;
import org.jfree.data.Range;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.TextAnchor;
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;
}
}