Skip to content
Snippets Groups Projects
Commit c8b70b29 authored by Tim Molter's avatar Tim Molter
Browse files

Merge branch 'develop'

parents 6d1661c6 93c4ed8e
Branches
No related tags found
No related merge requests found
Showing
with 575 additions and 145 deletions
## [![XChart](http://www.xeiam.com/images/XChart_64_64.png)](http://www.xeiam.com/xchart) XChart
## [![XChart](http://xeiam.com/wp-content/uploads/xchartlogo.png)](http://xeiam.com/xchart) XChart
A Simple Charting Library for Java
## Description
......@@ -20,12 +20,12 @@ Usage is very simple: Create a Chart instance, add a series of data to it, and e
new SwingWrapper(chart).displayChart();
// Save it
BitmapEncoder.savePNG(chart, "./Sample_Chart.png");
BitmapEncoder.saveBitmap(chart, "./Sample_Chart", BitmapFormat.PNG);
// or save it in high-res
BitmapEncoder.savePNGWithDPI(chart, "./Sample_Chart_300_DPI.png", 300);
BitmapEncoder.saveBitmapWithDPI(chart, "./Sample_Chart_300_DPI", BitmapFormat.PNG, 300);
Now go ahead and [study some more examples](http://www.xeiam.com/xchart_examplecode.jsp), [download the thing](http://www.xeiam.com/xchart_changelog.jsp) and [provide feedback](https://github.com/timmolter/XChart/issues).
Now go ahead and [study some more examples](http://xeiam.com/xchart-example-code/), [download the thing](http://xeiam.com/xchart-change-log) and [provide feedback](https://github.com/timmolter/XChart/issues).
## Features
* No additional dependencies
......@@ -52,7 +52,7 @@ Now go ahead and [study some more examples](http://www.xeiam.com/xchart_examplec
### Non-Maven
Download Jar: http://www.xeiam.com/xchart_changelog.jsp
Download Jar: http://xeiam.com/xchart-change-log
### Maven
......@@ -63,7 +63,7 @@ Add the XChart library as a dependency to your pom.xml file:
<dependency>
<groupId>com.xeiam.xchart</groupId>
<artifactId>xchart</artifactId>
<version>2.4.0</version>
<version>2.4.1</version>
</dependency>
For snapshots, add the following to your pom.xml file:
......@@ -77,7 +77,7 @@ For snapshots, add the following to your pom.xml file:
<dependency>
<groupId>com.xeiam</groupId>
<artifactId>xchart</artifactId>
<version>2.4.1-SNAPSHOT</version>
<version>2.4.2-SNAPSHOT</version>
</dependency>
## Building
......@@ -95,7 +95,7 @@ For snapshots, add the following to your pom.xml file:
## Running Demo
cd /path/to/xchart-demo/jar/
java -cp xchart-demo-2.4.0.jar:xchart-2.4.0.jar com.xeiam.xchart.demo.XChartDemo
java -cp xchart-demo-2.4.1.jar:xchart-2.4.1.jar com.xeiam.xchart.demo.XChartDemo
## Bugs
Please report any bugs or submit feature requests to [XChart's Github issue tracker](https://github.com/timmolter/XChart/issues).
......
......
......@@ -4,7 +4,7 @@
<groupId>com.xeiam.xchart</groupId>
<artifactId>xchart-parent</artifactId>
<version>2.4.1-SNAPSHOT</version>
<version>2.4.2-SNAPSHOT</version>
<packaging>pom</packaging>
<name>XChart Parent</name>
<description>Basic Charts for Java Applications</description>
......
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>com.xeiam.xchart</groupId>
<artifactId>xchart-parent</artifactId>
<version>2.4.1-SNAPSHOT</version>
<version>2.4.2-SNAPSHOT</version>
</parent>
<artifactId>xchart-demo</artifactId>
......@@ -17,7 +17,7 @@
<dependency>
<groupId>com.xeiam.xchart</groupId>
<artifactId>xchart</artifactId>
<version>2.4.1-SNAPSHOT</version>
<version>2.4.2-SNAPSHOT</version>
</dependency>
</dependencies>
......
......
......@@ -33,6 +33,7 @@ import javax.swing.tree.TreeSelectionModel;
import com.xeiam.xchart.XChartPanel;
import com.xeiam.xchart.demo.charts.area.AreaChart01;
import com.xeiam.xchart.demo.charts.area.AreaChart02;
import com.xeiam.xchart.demo.charts.area.AreaLineChart03;
import com.xeiam.xchart.demo.charts.bar.BarChart01;
import com.xeiam.xchart.demo.charts.bar.BarChart02;
import com.xeiam.xchart.demo.charts.bar.BarChart03;
......@@ -194,6 +195,9 @@ public class XChartDemo extends JPanel implements TreeSelectionListener {
defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("AreaChart02 - Null Y-Axis Data Points", new AreaChart02().getChart()));
category.add(defaultMutableTreeNode);
defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("AreaLineChart03 - Combination Are & Line Chart", new AreaLineChart03().getChart()));
category.add(defaultMutableTreeNode);
// Line category
category = new DefaultMutableTreeNode("Line Charts");
top.add(category);
......
......
......@@ -44,7 +44,7 @@ public class AreaChart01 implements ExampleChart {
public Chart getChart() {
// Create Chart
Chart chart = new ChartBuilder().chartType(ChartType.Area).width(800).height(600).title("AreaChart01").xAxisTitle("X").yAxisTitle("Y").build();
Chart chart = new ChartBuilder().chartType(ChartType.Area).width(800).height(600).title(getClass().getSimpleName()).xAxisTitle("X").yAxisTitle("Y").build();
chart.addSeries("a", new double[] { 0, 3, 5, 7, 9 }, new double[] { -3, 5, 9, 6, 5 });
chart.addSeries("b", new double[] { 0, 2, 4, 6, 9 }, new double[] { -1, 6, 4, 0, 4 });
chart.addSeries("c", new double[] { 0, 1, 3, 8, 9 }, new double[] { -2, -1, 1, 0, 1 });
......
......
......@@ -47,7 +47,7 @@ public class AreaChart02 implements ExampleChart {
public Chart getChart() {
// Create Chart
Chart chart = new ChartBuilder().chartType(ChartType.Area).width(800).height(600).title("AreaChart02").xAxisTitle("X").yAxisTitle("Y").build();
Chart chart = new ChartBuilder().chartType(ChartType.Area).width(800).height(600).title(getClass().getSimpleName()).xAxisTitle("X").yAxisTitle("Y").build();
List<Integer> xData = new ArrayList<Integer>();
List<Integer> yData = new ArrayList<Integer>();
......
......
/**
* Copyright 2011 - 2014 Xeiam LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xeiam.xchart.demo.charts.area;
import com.xeiam.xchart.Chart;
import com.xeiam.xchart.Series;
import com.xeiam.xchart.SeriesMarker;
import com.xeiam.xchart.StyleManager;
import com.xeiam.xchart.StyleManager.ChartType;
import com.xeiam.xchart.StyleManager.LegendPosition;
import com.xeiam.xchart.SwingWrapper;
import com.xeiam.xchart.demo.charts.ExampleChart;
/**
* Combination Line & Area Chart
* <p/>
* Demonstrates the following:
* <ul>
* <li>Combination of Line and Area series
* <li>Axis Label Alignment
* <li>Ensuring a chart axis on a tick
*/
public class AreaLineChart03 implements ExampleChart {
public static void main(String[] args) {
ExampleChart exampleChart = new AreaLineChart03();
Chart chart = exampleChart.getChart();
new SwingWrapper(chart).displayChart();
}
@Override
public Chart getChart() {
// Create Chart
Chart chart = new Chart(800, 600);
// Customize Chart
chart.setChartTitle(getClass().getSimpleName());
chart.setXAxisTitle("Age");
chart.setYAxisTitle("Amount");
chart.getStyleManager().setLegendPosition(LegendPosition.InsideNW);
chart.getStyleManager().setChartType(ChartType.Line);
// @formatter:off
double[] xAges = new double[]{
60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100};
double[] yLiability = new double[]{
672234,
691729,
711789,
732431,
753671,
775528,
798018,
821160,
844974,
869478,
907735,
887139,
865486,
843023,
819621,
795398,
770426,
744749,
719011,
693176,
667342,
641609,
616078,
590846,
565385,
540002,
514620,
489380,
465149,
441817,
419513,
398465,
377991,
358784,
340920,
323724,
308114,
293097,
279356,
267008,
254873
};
double[] yPercentile75th = new double[]{
800000,
878736,
945583,
1004209,
1083964,
1156332,
1248041,
1340801,
1440138,
1550005,
1647728,
1705046,
1705032,
1710672,
1700847,
1683418,
1686522,
1674901,
1680456,
1679164,
1668514,
1672860,
1673988,
1646597,
1641842,
1653758,
1636317,
1620725,
1589985,
1586451,
1559507,
1544234,
1529700,
1507496,
1474907,
1422169,
1415079,
1346929,
1311689,
1256114,
1221034
};
double[] yPercentile50th = new double[]{
800000,
835286,
873456,
927048,
969305,
1030749,
1101102,
1171396,
1246486,
1329076,
1424666,
1424173,
1421853,
1397093,
1381882,
1364562,
1360050,
1336885,
1340431,
1312217,
1288274,
1271615,
1262682,
1237287,
1211335,
1191953,
1159689,
1117412,
1078875,
1021020,
974933,
910189,
869154,
798476,
744934,
674501,
609237,
524516,
442234,
343960,
257025
};
double[] yPercentile25th = new double[]{
800000,
791439,
809744,
837020,
871166,
914836,
958257,
1002955,
1054094,
1118934,
1194071,
1185041,
1175401,
1156578,
1132121,
1094879,
1066202,
1054411,
1028619,
987730,
944977,
914929,
880687,
809330,
783318,
739751,
696201,
638242,
565197,
496959,
421280,
358113,
276518,
195571,
109514,
13876,
29,
0,
0,
0,
0};
// @formatter:on
Series seriesLiability = chart.addSeries("Liability", xAges, yLiability);
seriesLiability.setMarker(SeriesMarker.NONE);
seriesLiability.setSeriesType(Series.SeriesType.Area);
Series seriesPercentile75th = chart.addSeries("75th Percentile", xAges, yPercentile75th);
seriesPercentile75th.setMarker(SeriesMarker.NONE);
Series seriesPercentile50th = chart.addSeries("50th Percentile", xAges, yPercentile50th);
seriesPercentile50th.setMarker(SeriesMarker.NONE);
Series seriesPercentile25th = chart.addSeries("25th Percentile", xAges, yPercentile25th);
seriesPercentile25th.setMarker(SeriesMarker.NONE);
chart.getStyleManager().setYAxisLabelAlignment(StyleManager.TextAlignment.Right);
chart.getStyleManager().setYAxisDecimalPattern("$ #,###.##");
chart.getStyleManager().setPlotPadding(0);
chart.getStyleManager().setAxisTickSpacePercentage(.95);
// chart.getStyleManager().setYAxisMax(1620725 * 1.15); // We want to ensure there is a % of padding on the top of the chart
return chart;
}
}
......@@ -78,6 +78,7 @@ public class BarChart02 implements ExampleChart {
Series series = chart.addSeries("Model 77", xData, yData);
series.setLineColor(SeriesColor.RED);
chart.getStyleManager().setPlotGridLinesVisible(false);
chart.getStyleManager().setBarFilled(false);
return chart;
}
......
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>com.xeiam.xchart</groupId>
<artifactId>xchart-parent</artifactId>
<version>2.4.1-SNAPSHOT</version>
<version>2.4.2-SNAPSHOT</version>
</parent>
<artifactId>xchart</artifactId>
......
......
......@@ -32,6 +32,10 @@ import com.xeiam.xchart.internal.style.SeriesColorMarkerLineStyle;
*/
public class Series {
public enum SeriesType {
Line, Area
}
private String name = "";
private Collection<?> xData;
......@@ -40,6 +44,8 @@ public class Series {
private Collection<? extends Number> yData;
private AxisType yAxisType;
private SeriesType seriesType;
private Collection<? extends Number> errorBars;
/** the minimum value of axis range */
......@@ -60,6 +66,9 @@ public class Series {
/** Line Color */
private Color strokeColor;
/** Fill Colour */
private Color fillColor;
/** Marker Style */
private Marker marker;
......@@ -91,6 +100,7 @@ public class Series {
this.errorBars = errorBars;
strokeColor = seriesColorMarkerLineStyle.getColor();
fillColor = seriesColorMarkerLineStyle.getColor();
markerColor = seriesColorMarkerLineStyle.getColor();
marker = seriesColorMarkerLineStyle.getMarker();
stroke = seriesColorMarkerLineStyle.getStroke();
......@@ -241,6 +251,16 @@ public class Series {
return this;
}
public SeriesType getSeriesType() {
return seriesType;
}
public void setSeriesType(SeriesType seriesType) {
this.seriesType = seriesType;
}
public Collection<?> getXData() {
return xData;
......@@ -296,6 +316,16 @@ public class Series {
return markerColor;
}
public Color getFillColor() {
return fillColor;
}
public void setFillColor(Color fillColor) {
this.fillColor = fillColor;
}
public String getName() {
return name;
......
......
......@@ -66,6 +66,10 @@ public class StyleManager {
}
}
public enum TextAlignment {
Left, Centre, Right;
}
/** the default Theme */
private Theme theme = new XChartTheme();
......@@ -116,7 +120,9 @@ public class StyleManager {
private Double xAxisMax;
private Double yAxisMin;
private Double yAxisMax;
private double axisTickSpaceRatio;
private double axisTickSpacePercentage;
private TextAlignment xAxisLabelAlignment = TextAlignment.Centre;
private TextAlignment yAxisLabelAlignment = TextAlignment.Left;
// Chart Plot Area ///////////////////////////////
private boolean isPlotGridLinesVisible;
......@@ -130,6 +136,7 @@ public class StyleManager {
// Bar Charts ///////////////////////////////
private double barWidthPercentage;
private boolean isBarsOverlapped;
private boolean isBarFilled;
// Line, Scatter, Area Charts ///////////////////////////////
private int markerSize;
......@@ -142,6 +149,8 @@ public class StyleManager {
private TimeZone timezone;
private String datePattern;
private String decimalPattern;
private String xAxisDecimalPattern;
private String yAxisDecimalPattern;
/**
* Constructor
......@@ -200,7 +209,7 @@ public class StyleManager {
xAxisMax = null;
yAxisMin = null;
yAxisMax = null;
axisTickSpaceRatio = .95;
axisTickSpacePercentage = .95;
// Chart Plot Area ///////////////////////////////
isPlotGridLinesVisible = theme.isPlotGridLinesVisible();
......@@ -214,6 +223,7 @@ public class StyleManager {
// Bar Charts ///////////////////////////////
barWidthPercentage = theme.getBarWidthPercentage();
isBarsOverlapped = theme.isBarsOverlapped();
isBarFilled = theme.isBarFilled();
// Line, Scatter, Area Charts ///////////////////////////////
......@@ -227,6 +237,8 @@ public class StyleManager {
timezone = TimeZone.getDefault();
datePattern = null; // if not null, this override pattern will be used
decimalPattern = null;
xAxisDecimalPattern = null;
yAxisDecimalPattern = null;
}
/**
......@@ -862,14 +874,34 @@ public class StyleManager {
return yAxisMax;
}
public void setAxisTickSpaceRatio(double axisTickSpaceRatio) {
public void setAxisTickSpacePercentage(double axisTickSpacePercentage) {
this.axisTickSpacePercentage = axisTickSpacePercentage;
}
public double getAxisTickSpacePercentage() {
return axisTickSpacePercentage;
}
public TextAlignment getXAxisLabelAlignment() {
return xAxisLabelAlignment;
}
public void setXAxisLabelAlignment(TextAlignment xAxisLabelAlignment) {
this.axisTickSpaceRatio = axisTickSpaceRatio;
this.xAxisLabelAlignment = xAxisLabelAlignment;
}
public double getAxisTickSpaceRatio() {
public TextAlignment getYAxisLabelAlignment() {
return axisTickSpaceRatio;
return yAxisLabelAlignment;
}
public void setYAxisLabelAlignment(TextAlignment yAxisLabelAlignment) {
this.yAxisLabelAlignment = yAxisLabelAlignment;
}
// Chart Plot Area ///////////////////////////////
......@@ -1011,6 +1043,21 @@ public class StyleManager {
return isBarsOverlapped;
}
/**
* set whether or no bars are filled with a solid color or empty.
*
* @param isBarFilled
*/
public void setBarFilled(boolean isBarFilled) {
this.isBarFilled = isBarFilled;
}
public boolean isBarFilled() {
return isBarFilled;
}
// Line, Scatter, Area Charts ///////////////////////////////
/**
......@@ -1107,4 +1154,34 @@ public class StyleManager {
return decimalPattern;
}
public String getXAxisDecimalPattern() {
return xAxisDecimalPattern;
}
/**
* Set the decimal formatting pattern for the X-Axis
*
* @param xAxisDecimalPattern
*/
public void setXAxisDecimalPattern(String xAxisDecimalPattern) {
this.xAxisDecimalPattern = xAxisDecimalPattern;
}
public String getYAxisDecimalPattern() {
return yAxisDecimalPattern;
}
/**
* Set the decimal formatting pattern for the Y-Axis
*
* @param yAxisDecimalPattern
*/
public void setYAxisDecimalPattern(String yAxisDecimalPattern) {
this.yAxisDecimalPattern = yAxisDecimalPattern;
}
}
......@@ -50,7 +50,7 @@ import com.xeiam.xchart.BitmapEncoder.BitmapFormat;
public class XChartPanel extends JPanel {
private final Chart chart;
private final Dimension preferredSize;
private String saveAsString = "Save As...";
/**
......@@ -61,6 +61,7 @@ public class XChartPanel extends JPanel {
public XChartPanel(final Chart chart) {
this.chart = chart;
preferredSize = new Dimension(chart.getWidth(), chart.getHeight());
// Right-click listener for saving chart
this.addMouseListener(new PopUpMenuClickListener());
......@@ -92,7 +93,7 @@ public class XChartPanel extends JPanel {
@Override
public Dimension getPreferredSize() {
return new Dimension(chart.getWidth(), chart.getHeight());
return this.preferredSize;
}
private class SaveAction extends AbstractAction {
......
......
......@@ -115,6 +115,14 @@ public class AxisPair implements ChartPart {
series = new Series(seriesName, generatedXData, xAxis.getAxisType(), yData, yAxis.getAxisType(), errorBars, seriesColorMarkerLineStyleCycler.getNextSeriesColorMarkerLineStyle());
}
switch (chartPainter.getStyleManager().getChartType()) {
case Area:
series.setSeriesType(Series.SeriesType.Area);
break;
case Line:
series.setSeriesType(Series.SeriesType.Line);
}
// Sanity check
if (xData != null && xData.size() != yData.size()) {
throw new IllegalArgumentException("X and Y-Axis sizes are not the same!!!");
......
......
......@@ -51,7 +51,7 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator {
private void calculate(ChartPainter chartPainter) {
// tick space - a percentage of the working space available for ticks
int tickSpace = (int) (styleManager.getAxisTickSpaceRatio() * workingSpace); // in plot space
int tickSpace = (int) (styleManager.getAxisTickSpacePercentage() * workingSpace); // in plot space
// where the tick should begin in the working space in pixels
double margin = Utils.getTickStartOffset(workingSpace, tickSpace); // in plot space double gridStep = getGridStepForDecimal(tickSpace);
......@@ -119,48 +119,36 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator {
for (Object category : categories) {
if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Number) {
tickLabels.add(numberFormatter.formatNumber(BigDecimal.valueOf((Double) category), minValue, maxValue));
tickLabels.add(numberFormatter.formatNumber(new BigDecimal(category.toString()), minValue, maxValue, axisDirection));
}
else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) {
long span = (long) Math.abs(maxValue - minValue); // in data space
long gridStepHint = (long) (span / (double) tickSpace * styleManager.getXAxisTickMarkSpacingHint());
long timeUnit = dateFormatter.getTimeUnit(gridStepHint);
tickLabels.add(dateFormatter.formatDate((Double) category, timeUnit));
tickLabels.add(dateFormatter.formatDate(((Number) category).doubleValue(), timeUnit));
}
double tickLabelPosition = (int) (margin + firstPosition + gridStep * counter++);
tickLocations.add(tickLabelPosition);
}
}
else { // Number or Date and more than 12 categories. divide up the axis tick space according to normal number axis layout
double gridStep = getNumericalGridStep(tickSpace);
double firstPosition = getFirstPosition(gridStep);
else { // Number or Date and more than 12 categories. divide up the axis tick space according to normal date oor number axis layout
// generate all tickLabels and tickLocations from the first to last position
NumberFormatter numberFormatter = null;
DateFormatter dateFormatter = null;
if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Number) {
numberFormatter = new NumberFormatter(styleManager);
}
else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) {
dateFormatter = new DateFormatter(chartPainter.getStyleManager());
}
for (double tickPosition = firstPosition; tickPosition <= maxValue + 2 * gridStep; tickPosition = tickPosition + gridStep) {
AxisTickNumericalCalculator axisTickNumericalCalculator = new AxisTickNumericalCalculator(axisDirection, workingSpace, minValue, maxValue, styleManager);
tickLabels = axisTickNumericalCalculator.getTickLabels();
tickLocations = axisTickNumericalCalculator.getTickLocations();
if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Number) {
tickLabels.add(numberFormatter.formatNumber(BigDecimal.valueOf(tickPosition), minValue, maxValue));
}
else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) {
long span = (long) Math.abs(maxValue - minValue); // in data space
long gridStepHint = (long) (span / (double) tickSpace * styleManager.getXAxisTickMarkSpacingHint());
long timeUnit = dateFormatter.getTimeUnit(gridStepHint);
tickLabels.add(dateFormatter.formatDate(tickPosition, timeUnit));
}
double tickLabelPosition = margin + ((tickPosition - minValue) / (maxValue - minValue) * tickSpace);
tickLocations.add(tickLabelPosition);
AxisTickDateCalculator axisTickDateCalculator = new AxisTickDateCalculator(axisDirection, workingSpace, minValue, maxValue, styleManager);
tickLabels = axisTickDateCalculator.getTickLabels();
tickLocations = axisTickDateCalculator.getTickLocations();
}
}
}
......
......
......@@ -73,13 +73,13 @@ public abstract class AxisTickCalculator {
}
// override min and maxValue if specified
if (axisDirection == Direction.X && styleManager.getXAxisMin() != null) {
if (axisDirection == Direction.X && styleManager.getXAxisMin() != null && styleManager.getChartType() != ChartType.Bar) {
overrideMinValue = styleManager.getXAxisMin();
}
if (axisDirection == Direction.Y && styleManager.getYAxisMin() != null) {
overrideMinValue = styleManager.getYAxisMin();
}
if (axisDirection == Direction.X && styleManager.getXAxisMax() != null) {
if (axisDirection == Direction.X && styleManager.getXAxisMax() != null && styleManager.getChartType() != ChartType.Bar) {
overrideMaxValue = styleManager.getXAxisMax();
}
if (axisDirection == Direction.Y && styleManager.getYAxisMax() != null) {
......
......
......@@ -47,7 +47,7 @@ public class AxisTickDateCalculator extends AxisTickCalculator {
private void calculate() {
// tick space - a percentage of the working space available for ticks
double tickSpace = styleManager.getAxisTickSpaceRatio() * workingSpace; // in plot space
double tickSpace = styleManager.getAxisTickSpacePercentage() * workingSpace; // in plot space
// where the tick should begin in the working space in pixels
double margin = Utils.getTickStartOffset(workingSpace, tickSpace); // in plot space double gridStep = getGridStepForDecimal(tickSpace);
......
......
......@@ -21,6 +21,8 @@ import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;
/**
* Axis tick labels
......@@ -58,38 +60,59 @@ public class AxisTickLabels implements ChartPart {
if (axisTick.getAxis().getDirection() == Axis.Direction.Y && getChartPainter().getStyleManager().isYAxisTicksVisible()) { // Y-Axis
double xOffset = axisTick.getAxis().getAxisTitle().getBounds().getX() + axisTick.getAxis().getAxisTitle().getBounds().getWidth();
double xWidth = axisTick.getAxis().getAxisTitle().getBounds().getWidth();
double xOffset = axisTick.getAxis().getAxisTitle().getBounds().getX() + xWidth;
double yOffset = axisTick.getAxis().getPaintZone().getY();
double height = axisTick.getAxis().getPaintZone().getHeight();
double maxTickLabelWidth = 0;
Map<Double, TextLayout> axisLabelTextLayouts = new HashMap<Double, TextLayout>();
for (int i = 0; i < axisTick.getTickLabels().size(); i++) {
String tickLabel = axisTick.getTickLabels().get(i);
// System.out.println(tickLabel);
// System.out.println("** " + tickLabel);
double tickLocation = axisTick.getTickLocations().get(i);
double flippedTickLocation = yOffset + height - tickLocation;
if (tickLabel != null && flippedTickLocation > yOffset && flippedTickLocation < yOffset + height) { // some are null for logarithmic axes
FontRenderContext frc = g.getFontRenderContext();
TextLayout layout = new TextLayout(tickLabel, getChartPainter().getStyleManager().getAxisTickLabelsFont(), frc);
Rectangle2D tickLabelBounds = layout.getBounds();
TextLayout axisLabelTextLayout = new TextLayout(tickLabel, getChartPainter().getStyleManager().getAxisTickLabelsFont(), frc);
Rectangle2D tickLabelBounds = axisLabelTextLayout.getBounds();
double boundWidth = tickLabelBounds.getWidth();
if (boundWidth > maxTickLabelWidth) {
maxTickLabelWidth = boundWidth;
}
axisLabelTextLayouts.put(tickLocation, axisLabelTextLayout);
}
}
for (Double tickLocation : axisLabelTextLayouts.keySet()) {
Shape shape = layout.getOutline(null);
TextLayout axisLabelTextLayout = axisLabelTextLayouts.get(tickLocation);
Rectangle2D tickLabelBounds = axisLabelTextLayout.getBounds();
Shape shape = axisLabelTextLayout.getOutline(null);
double flippedTickLocation = yOffset + height - tickLocation;
AffineTransform orig = g.getTransform();
AffineTransform at = new AffineTransform();
at.translate(xOffset, flippedTickLocation + tickLabelBounds.getHeight() / 2.0);
double boundWidth = tickLabelBounds.getWidth();
double xPos;
switch (getChartPainter().getStyleManager().getYAxisLabelAlignment()) {
case Right:
xPos = xOffset + maxTickLabelWidth - boundWidth;
break;
case Centre:
xPos = xOffset + (maxTickLabelWidth - boundWidth) / 2;
break;
case Left:
default:
xPos = xOffset;
}
at.translate(xPos, flippedTickLocation + tickLabelBounds.getHeight() / 2.0);
g.transform(at);
g.fill(shape);
g.setTransform(orig);
if (tickLabelBounds.getWidth() > maxTickLabelWidth) {
maxTickLabelWidth = tickLabelBounds.getWidth();
}
}
}
// bounds
......@@ -124,7 +147,19 @@ public class AxisTickLabels implements ChartPart {
AffineTransform orig = g.getTransform();
AffineTransform at = new AffineTransform();
at.translate(shiftedTickLocation - tickLabelBounds.getWidth() / 2.0, yOffset);
double xPos;
switch (getChartPainter().getStyleManager().getXAxisLabelAlignment()) {
case Left:
xPos = shiftedTickLocation;
break;
case Right:
xPos = shiftedTickLocation - tickLabelBounds.getWidth();
break;
case Centre:
default:
xPos = shiftedTickLocation - tickLabelBounds.getWidth() / 2.0;
}
at.translate(xPos, yOffset);
g.transform(at);
g.fill(shape);
g.setTransform(orig);
......
......
......@@ -50,13 +50,13 @@ public class AxisTickLogarithmicCalculator extends AxisTickCalculator {
// a check if all axis data are the exact same values
if (minValue == maxValue) {
tickLabels.add(numberFormatter.formatNumber(BigDecimal.valueOf(maxValue), minValue, maxValue));
tickLabels.add(numberFormatter.formatNumber(BigDecimal.valueOf(maxValue), minValue, maxValue, axisDirection));
tickLocations.add(workingSpace / 2.0);
return;
}
// tick space - a percentage of the working space available for ticks
double tickSpace = styleManager.getAxisTickSpaceRatio() * workingSpace; // in plot space
double tickSpace = styleManager.getAxisTickSpacePercentage() * workingSpace; // in plot space
// where the tick should begin in the working space in pixels
double margin = Utils.getTickStartOffset(workingSpace, tickSpace); // in plot space double gridStep = getGridStepForDecimal(tickSpace);
......@@ -113,7 +113,7 @@ public class AxisTickLogarithmicCalculator extends AxisTickCalculator {
// only add labels for the decades
if (Math.abs(Math.log10(j) % 1) < 0.00000001) {
tickLabels.add(numberFormatter.formatLogNumber(j));
tickLabels.add(numberFormatter.formatLogNumber(j, axisDirection));
}
else {
tickLabels.add(null);
......
......
......@@ -51,13 +51,13 @@ public class AxisTickNumericalCalculator extends AxisTickCalculator {
// a check if all axis data are the exact same values
if (minValue == maxValue) {
tickLabels.add(numberFormatter.formatNumber(BigDecimal.valueOf(maxValue), minValue, maxValue));
tickLabels.add(numberFormatter.formatNumber(BigDecimal.valueOf(maxValue), minValue, maxValue, axisDirection));
tickLocations.add(workingSpace / 2.0);
return;
}
// tick space - a percentage of the working space available for ticks
double tickSpace = styleManager.getAxisTickSpaceRatio() * workingSpace; // in plot space
double tickSpace = styleManager.getAxisTickSpacePercentage() * workingSpace; // in plot space
// where the tick should begin in the working space in pixels
double margin = Utils.getTickStartOffset(workingSpace, tickSpace); // in plot space double gridStep = getGridStepForDecimal(tickSpace);
......@@ -74,7 +74,11 @@ public class AxisTickNumericalCalculator extends AxisTickCalculator {
// generate all tickLabels and tickLocations from the first to last position
for (BigDecimal tickPosition = cleanedFirstPosition; tickPosition.compareTo(BigDecimal.valueOf(maxValue + 2 * cleanedGridStep.doubleValue())) < 0; tickPosition = tickPosition.add(cleanedGridStep)) {
tickLabels.add(numberFormatter.formatNumber(tickPosition, minValue, maxValue));
// System.out.println(tickPosition);
String tickLabel = numberFormatter.formatNumber(tickPosition, minValue, maxValue, axisDirection);
// System.out.println(tickLabel);
tickLabels.add(tickLabel);
// here we convert tickPosition finally to plot space, i.e. pixels
double tickLabelPosition = margin + ((tickPosition.doubleValue() - minValue) / (maxValue - minValue) * tickSpace);
tickLocations.add(tickLabelPosition);
......
......
......@@ -20,6 +20,7 @@ import java.text.DecimalFormat;
import java.text.NumberFormat;
import com.xeiam.xchart.StyleManager;
import com.xeiam.xchart.internal.chartpart.Axis.Direction;
/**
* @author timmolter
......@@ -107,21 +108,32 @@ public class NumberFormatter {
* Format a number value, if the override patterns are null, it uses defaults
*
* @param value
* @param min
* @param max
* @param axisDirection
* @return
*/
public String formatNumber(BigDecimal value, double min, double max) {
public String formatNumber(BigDecimal value, double min, double max, Direction axisDirection) {
NumberFormat numberFormat = NumberFormat.getNumberInstance(styleManager.getLocale());
String decimalPattern;
if (styleManager.getDecimalPattern() == null) {
if (axisDirection == Direction.X && styleManager.getXAxisDecimalPattern() != null) {
decimalPattern = getFormatPattern(value, min, max);
decimalPattern = styleManager.getXAxisDecimalPattern();
}
else {
else if (axisDirection == Direction.Y && styleManager.getYAxisDecimalPattern() != null) {
decimalPattern = styleManager.getYAxisDecimalPattern();
}
else if (styleManager.getDecimalPattern() != null) {
decimalPattern = styleManager.getDecimalPattern();
}
else {
decimalPattern = getFormatPattern(value, min, max);
}
// System.out.println(decimalPattern);
DecimalFormat normalFormat = (DecimalFormat) numberFormat;
normalFormat.applyPattern(decimalPattern);
......@@ -135,19 +147,26 @@ public class NumberFormatter {
* @param value
* @return
*/
public String formatLogNumber(double value) {
public String formatLogNumber(double value, Direction axisDirection) {
NumberFormat numberFormat = NumberFormat.getNumberInstance(styleManager.getLocale());
String decimalPattern;
if (styleManager.getDecimalPattern() == null) {
if (axisDirection == Direction.X && styleManager.getXAxisDecimalPattern() != null) {
decimalPattern = "0E0";
decimalPattern = styleManager.getXAxisDecimalPattern();
}
else {
else if (axisDirection == Direction.Y && styleManager.getYAxisDecimalPattern() != null) {
decimalPattern = styleManager.getYAxisDecimalPattern();
}
else if (styleManager.getDecimalPattern() != null) {
decimalPattern = styleManager.getDecimalPattern();
}
else {
decimalPattern = "0E0";
}
DecimalFormat normalFormat = (DecimalFormat) numberFormat;
normalFormat.applyPattern(decimalPattern);
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment