From 992e71aa71927dbb797d4ffa89e93b7927162b52 Mon Sep 17 00:00:00 2001 From: Tim Molter <tim.molter@gmail.com> Date: Sat, 16 Feb 2013 20:16:26 +0100 Subject: [PATCH] more cleanup --- .../xchart/internal/chartpart/AxisTick.java | 18 +- .../AxisTickCalculator.java} | 4 +- .../DateAxisTickCalculator.java} | 13 +- .../DateFormatter.java | 2 +- .../DecimalAxisTickCalculator.java} | 13 +- .../DecimalFormatter.java | 2 +- .../LogarithmicAxisTickCalculator.java | 208 ++++++++++++++++++ .../com/xeiam/xchart/style/StyleManager.java | 4 +- .../xeiam/xchart/unit/ValueFormatterTest.java | 4 +- 9 files changed, 239 insertions(+), 29 deletions(-) rename xchart/src/main/java/com/xeiam/xchart/internal/chartpart/{gridstep/GridStep.java => axistickcalculator/AxisTickCalculator.java} (92%) rename xchart/src/main/java/com/xeiam/xchart/internal/chartpart/{gridstep/DateGridStep.java => axistickcalculator/DateAxisTickCalculator.java} (93%) rename xchart/src/main/java/com/xeiam/xchart/internal/chartpart/{gridstep => axistickcalculator}/DateFormatter.java (98%) rename xchart/src/main/java/com/xeiam/xchart/internal/chartpart/{gridstep/DecimalGridStep.java => axistickcalculator/DecimalAxisTickCalculator.java} (94%) rename xchart/src/main/java/com/xeiam/xchart/internal/chartpart/{gridstep => axistickcalculator}/DecimalFormatter.java (98%) create mode 100644 xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/LogarithmicAxisTickCalculator.java diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java index 8e83c3c5..2fdc5157 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java @@ -21,9 +21,10 @@ import java.util.List; import com.xeiam.xchart.Chart; import com.xeiam.xchart.internal.chartpart.Axis.AxisType; -import com.xeiam.xchart.internal.chartpart.gridstep.DateGridStep; -import com.xeiam.xchart.internal.chartpart.gridstep.DecimalGridStep; -import com.xeiam.xchart.internal.chartpart.gridstep.GridStep; +import com.xeiam.xchart.internal.chartpart.axistickcalculator.AxisTickCalculator; +import com.xeiam.xchart.internal.chartpart.axistickcalculator.DateAxisTickCalculator; +import com.xeiam.xchart.internal.chartpart.axistickcalculator.DecimalAxisTickCalculator; +import com.xeiam.xchart.internal.chartpart.axistickcalculator.LogarithmicAxisTickCalculator; /** * An axis tick @@ -45,7 +46,7 @@ public class AxisTick implements ChartPart { /** the visibility state of axistick */ private boolean isVisible = true; // default to true - GridStep gridStep = null; + AxisTickCalculator gridStep = null; /** * Constructor @@ -81,22 +82,19 @@ public class AxisTick implements ChartPart { // System.out.println("workingspace= " + workingSpace); } - // //////////////////////// - if (axis.getAxisType() == AxisType.Number) { - gridStep = new DecimalGridStep(axis.getDirection(), workingSpace, axis.getMin(), axis.getMax(), getChart().getStyleManager()); + gridStep = new DecimalAxisTickCalculator(axis.getDirection(), workingSpace, axis.getMin(), axis.getMax(), getChart().getStyleManager()); } else if (axis.getAxisType() == AxisType.Date) { - gridStep = new DateGridStep(axis.getDirection(), workingSpace, axis.getMin(), axis.getMax(), getChart().getStyleManager()); + gridStep = new DateAxisTickCalculator(axis.getDirection(), workingSpace, axis.getMin(), axis.getMax(), getChart().getStyleManager()); } else if (axis.getAxisType() == AxisType.Logarithmic) { + gridStep = new LogarithmicAxisTickCalculator(axis.getDirection(), workingSpace, axis.getMin(), axis.getMax(), getChart().getStyleManager()); } - // ///////////////////////// - if (isVisible) { axisTickLabels.paint(g); diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/GridStep.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/AxisTickCalculator.java similarity index 92% rename from xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/GridStep.java rename to xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/AxisTickCalculator.java index f10ec2bf..8a924230 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/GridStep.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/AxisTickCalculator.java @@ -19,14 +19,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.xeiam.xchart.internal.chartpart.gridstep; +package com.xeiam.xchart.internal.chartpart.axistickcalculator; import java.util.List; /** * @author timmolter */ -public interface GridStep { +public interface AxisTickCalculator { public List<Integer> getTickLocations(); diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DateGridStep.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DateAxisTickCalculator.java similarity index 93% rename from xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DateGridStep.java rename to xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DateAxisTickCalculator.java index d27af6eb..fd93c28c 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DateGridStep.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DateAxisTickCalculator.java @@ -19,7 +19,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.xeiam.xchart.internal.chartpart.gridstep; +package com.xeiam.xchart.internal.chartpart.axistickcalculator; import java.math.BigDecimal; import java.util.LinkedList; @@ -30,9 +30,11 @@ import com.xeiam.xchart.internal.chartpart.AxisPair; import com.xeiam.xchart.style.StyleManager; /** + * This class encapsulates the logic to generate the axis tick mark and axis tick label data for rendering the axis ticks for date axes + * * @author timmolter */ -public class DateGridStep implements GridStep { +public class DateAxisTickCalculator implements AxisTickCalculator { /** the default tick mark step hint for x axis */ private static final int DEFAULT_TICK_MARK_STEP_HINT_X = 74; @@ -63,8 +65,9 @@ public class DateGridStep implements GridStep { * @param workingSpace * @param minValue * @param maxValue + * @param styleManager */ - public DateGridStep(Direction axisDirection, int workingSpace, BigDecimal minValue, BigDecimal maxValue, StyleManager styleManager) { + public DateAxisTickCalculator(Direction axisDirection, int workingSpace, BigDecimal minValue, BigDecimal maxValue, StyleManager styleManager) { this.axisDirection = axisDirection; this.workingSpace = workingSpace; @@ -72,10 +75,10 @@ public class DateGridStep implements GridStep { this.maxValue = maxValue; this.styleManager = styleManager; - go(); + calculate(); } - private void go() { + private void calculate() { // a check if all axis data are the exact same values if (minValue == maxValue) { diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DateFormatter.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DateFormatter.java similarity index 98% rename from xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DateFormatter.java rename to xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DateFormatter.java index 21fae0c6..448002e0 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DateFormatter.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DateFormatter.java @@ -19,7 +19,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.xeiam.xchart.internal.chartpart.gridstep; +package com.xeiam.xchart.internal.chartpart.axistickcalculator; import java.math.BigDecimal; import java.text.SimpleDateFormat; diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DecimalGridStep.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DecimalAxisTickCalculator.java similarity index 94% rename from xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DecimalGridStep.java rename to xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DecimalAxisTickCalculator.java index b1426418..f22f06ed 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DecimalGridStep.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DecimalAxisTickCalculator.java @@ -19,7 +19,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.xeiam.xchart.internal.chartpart.gridstep; +package com.xeiam.xchart.internal.chartpart.axistickcalculator; import java.math.BigDecimal; import java.util.LinkedList; @@ -30,11 +30,11 @@ import com.xeiam.xchart.internal.chartpart.AxisPair; import com.xeiam.xchart.style.StyleManager; /** - * This class encapsulates the logic to generate the axis tick mark and axis tick label data for rendering the axis ticks for decimla axes + * This class encapsulates the logic to generate the axis tick mark and axis tick label data for rendering the axis ticks for decimal axes * * @author timmolter */ -public class DecimalGridStep implements GridStep { +public class DecimalAxisTickCalculator implements AxisTickCalculator { /** the default tick mark step hint for x axis */ private static final int DEFAULT_TICK_MARK_STEP_HINT_X = 74; @@ -65,8 +65,9 @@ public class DecimalGridStep implements GridStep { * @param workingSpace * @param minValue * @param maxValue + * @param styleManager */ - public DecimalGridStep(Direction axisDirection, int workingSpace, BigDecimal minValue, BigDecimal maxValue, StyleManager styleManager) { + public DecimalAxisTickCalculator(Direction axisDirection, int workingSpace, BigDecimal minValue, BigDecimal maxValue, StyleManager styleManager) { this.axisDirection = axisDirection; this.workingSpace = workingSpace; @@ -74,10 +75,10 @@ public class DecimalGridStep implements GridStep { this.maxValue = maxValue; this.styleManager = styleManager; - go(); + calculate(); } - private void go() { + private void calculate() { // a check if all axis data are the exact same values if (minValue == maxValue) { diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DecimalFormatter.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DecimalFormatter.java similarity index 98% rename from xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DecimalFormatter.java rename to xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DecimalFormatter.java index abf2d54d..27fb6d48 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/gridstep/DecimalFormatter.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/DecimalFormatter.java @@ -19,7 +19,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.xeiam.xchart.internal.chartpart.gridstep; +package com.xeiam.xchart.internal.chartpart.axistickcalculator; import java.math.BigDecimal; import java.text.DecimalFormat; diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/LogarithmicAxisTickCalculator.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/LogarithmicAxisTickCalculator.java new file mode 100644 index 00000000..7cd44ab0 --- /dev/null +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/axistickcalculator/LogarithmicAxisTickCalculator.java @@ -0,0 +1,208 @@ +/** + * Copyright (C) 2013 Xeiam LLC http://xeiam.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.xeiam.xchart.internal.chartpart.axistickcalculator; + +import java.math.BigDecimal; +import java.util.LinkedList; +import java.util.List; + +import com.xeiam.xchart.internal.chartpart.Axis.Direction; +import com.xeiam.xchart.internal.chartpart.AxisPair; +import com.xeiam.xchart.style.StyleManager; + +/** + * This class encapsulates the logic to generate the axis tick mark and axis tick label data for rendering the axis ticks for decimal axes + * + * @author timmolter + */ +public class LogarithmicAxisTickCalculator implements AxisTickCalculator { + + /** the default tick mark step hint for x axis */ + private static final int DEFAULT_TICK_MARK_STEP_HINT_X = 74; + + /** the default tick mark step hint for y axis */ + private static final int DEFAULT_TICK_MARK_STEP_HINT_Y = 44; + + /** the List of tick label position in pixels */ + private List<Integer> tickLocations = new LinkedList<Integer>();; + + /** the List of tick label values */ + private List<String> tickLabels = new LinkedList<String>(); + + private final Direction axisDirection; + + private final int workingSpace; + + private final BigDecimal minValue; + + private final BigDecimal maxValue; + + private final StyleManager styleManager; + + /** + * Constructor + * + * @param axisDirection + * @param workingSpace + * @param minValue + * @param maxValue + * @param styleManager + */ + public LogarithmicAxisTickCalculator(Direction axisDirection, int workingSpace, BigDecimal minValue, BigDecimal maxValue, StyleManager styleManager) { + + this.axisDirection = axisDirection; + this.workingSpace = workingSpace; + this.minValue = minValue; + this.maxValue = maxValue; + this.styleManager = styleManager; + + calculate(); + } + + private void calculate() { + + // a check if all axis data are the exact same values + if (minValue == maxValue) { + tickLabels.add(styleManager.getDecimalFormatter().formatNumber(maxValue)); + tickLocations.add((int) (workingSpace / 2.0)); + return; + } + + // tick space - a percentage of the working space available for ticks, i.e. 95% + int tickSpace = AxisPair.getTickSpace(workingSpace); // in plot space + System.out.println("tickSpace= " + tickSpace); + + // where the tick should begin in the working space in pixels + int margin = AxisPair.getTickStartOffset(workingSpace, tickSpace); // in plot space BigDecimal gridStep = getGridStepForDecimal(tickSpace); + + BigDecimal gridStep = getGridStepForDecimal(tickSpace); + + BigDecimal firstPosition = getFirstPosition(minValue, gridStep); + + // generate all tickLabels and tickLocations from the first to last position + for (BigDecimal tickPosition = firstPosition; tickPosition.compareTo(maxValue) <= 0; tickPosition = tickPosition.add(gridStep)) { + + tickLabels.add(styleManager.getDecimalFormatter().formatNumber(tickPosition)); + // here we convert tickPosition finally to plot space, i.e. pixels + int tickLabelPosition = (int) (margin + ((tickPosition.subtract(minValue)).doubleValue() / (maxValue.subtract(minValue)).doubleValue() * tickSpace)); + tickLocations.add(tickLabelPosition); + } + } + + /** + * Determine the grid step for the data set given the space in pixels allocated for the axis + * + * @param tickSpace in plot space + * @return + */ + private BigDecimal getGridStepForDecimal(int tickSpace) { + + // the span of the data + double span = Math.abs(maxValue.subtract(minValue).doubleValue()); // in data space + + int tickMarkSpaceHint = (axisDirection == Direction.X ? DEFAULT_TICK_MARK_STEP_HINT_X : DEFAULT_TICK_MARK_STEP_HINT_Y); + + // for very short plots, squeeze some more ticks in than normal + if (axisDirection == Direction.Y && tickSpace < 160) { + tickMarkSpaceHint = 25; + } + + double gridStepHint = span / tickSpace * tickMarkSpaceHint; + + // gridStepHint --> significand * 10 ** exponent + // e.g. 724.1 --> 7.241 * 10 ** 2 + double significand = gridStepHint; + int exponent = 0; + if (significand == 0) { + exponent = 1; + } else if (significand < 1) { + while (significand < 1) { + significand *= 10.0; + exponent--; + } + } else { + while (significand >= 10) { + significand /= 10.0; + exponent++; + } + } + + // calculate the grid step with hint. + BigDecimal gridStep; + if (significand > 7.5) { + // gridStep = 10.0 * 10 ** exponent + gridStep = BigDecimal.TEN.multiply(pow(10, exponent)); + } else if (significand > 3.5) { + // gridStep = 5.0 * 10 ** exponent + gridStep = new BigDecimal(new Double(5).toString()).multiply(pow(10, exponent)); + } else if (significand > 1.5) { + // gridStep = 2.0 * 10 ** exponent + gridStep = new BigDecimal(new Double(2).toString()).multiply(pow(10, exponent)); + } else { + // gridStep = 1.0 * 10 ** exponent + gridStep = pow(10, exponent); + } + return gridStep; + } + + /** + * Calculates the value of the first argument raised to the power of the second argument. + * + * @param base the base + * @param exponent the exponent + * @return the value <tt>a<sup>b</sup></tt> in <tt>BigDecimal</tt> + */ + private BigDecimal pow(double base, int exponent) { + + BigDecimal value; + if (exponent > 0) { + value = new BigDecimal(new Double(base).toString()).pow(exponent); + } else { + value = BigDecimal.ONE.divide(new BigDecimal(new Double(base).toString()).pow(-exponent)); + } + return value; + } + + private BigDecimal getFirstPosition(final BigDecimal min, BigDecimal gridStep) { + + BigDecimal firstPosition; + if (min.remainder(gridStep).doubleValue() <= 0.0) { + firstPosition = min.subtract(min.remainder(gridStep)); + } else { + firstPosition = min.subtract(min.remainder(gridStep)).add(gridStep); + } + return firstPosition; + } + + @Override + public List<Integer> getTickLocations() { + + return tickLocations; + } + + @Override + public List<String> getTickLabels() { + + return tickLabels; + } + +} diff --git a/xchart/src/main/java/com/xeiam/xchart/style/StyleManager.java b/xchart/src/main/java/com/xeiam/xchart/style/StyleManager.java index 32b9701b..37ad7c29 100644 --- a/xchart/src/main/java/com/xeiam/xchart/style/StyleManager.java +++ b/xchart/src/main/java/com/xeiam/xchart/style/StyleManager.java @@ -25,8 +25,8 @@ import java.awt.Color; import java.awt.Font; import java.awt.Stroke; -import com.xeiam.xchart.internal.chartpart.gridstep.DateFormatter; -import com.xeiam.xchart.internal.chartpart.gridstep.DecimalFormatter; +import com.xeiam.xchart.internal.chartpart.axistickcalculator.DateFormatter; +import com.xeiam.xchart.internal.chartpart.axistickcalculator.DecimalFormatter; import com.xeiam.xchart.style.theme.Theme; import com.xeiam.xchart.style.theme.XChartTheme; diff --git a/xchart/src/test/java/com/xeiam/xchart/unit/ValueFormatterTest.java b/xchart/src/test/java/com/xeiam/xchart/unit/ValueFormatterTest.java index 4edb9ce5..61321f15 100644 --- a/xchart/src/test/java/com/xeiam/xchart/unit/ValueFormatterTest.java +++ b/xchart/src/test/java/com/xeiam/xchart/unit/ValueFormatterTest.java @@ -30,8 +30,8 @@ import java.util.TimeZone; import org.junit.Test; -import com.xeiam.xchart.internal.chartpart.gridstep.DateFormatter; -import com.xeiam.xchart.internal.chartpart.gridstep.DecimalFormatter; +import com.xeiam.xchart.internal.chartpart.axistickcalculator.DateFormatter; +import com.xeiam.xchart.internal.chartpart.axistickcalculator.DecimalFormatter; /** * @author timmolter -- GitLab