Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.knowm.xchart.standalone.issues;

import java.util.Arrays;
import java.util.List;
import org.knowm.xchart.CategoryChart;
import org.knowm.xchart.CategoryChartBuilder;
import org.knowm.xchart.CategorySeries;
import org.knowm.xchart.CategorySeries.CategorySeriesRenderStyle;
import org.knowm.xchart.SwingWrapper;

/**
* Demonstrates smooth curved lines in a CategoryChart (string X-axis labels).
*
* @see <a href="https://github.com/knowm/XChart/issues/467">Issue #467</a>
*/
public class TestForIssue467 {

public static void main(String[] args) {
new SwingWrapper<>(getChart()).displayChart();
}

public static CategoryChart getChart() {
CategoryChart chart =
new CategoryChartBuilder()
.width(800)
.height(600)
.title("Issue 467 - Smooth Lines in CategoryChart")
.xAxisTitle("Month")
.yAxisTitle("Value")
.build();

chart.getStyler().setOverlapped(true);
chart.getStyler().setAvailableSpaceFill(0.4);

List<String> xData = Arrays.asList("Jan", "Feb", "Mar", "Apr", "May", "Jun");
List<Integer> yData1 = Arrays.asList(4, 7, 3, 8, 5, 9);
List<Integer> yData2 = Arrays.asList(2, 5, 6, 3, 7, 4);
List<Integer> yData3 = Arrays.asList(1, 3, 5, 2, 4, 6);

CategorySeries series1 = chart.addSeries("Smooth", xData, yData1);
series1.setChartCategorySeriesRenderStyle(CategorySeriesRenderStyle.Line);
series1.setSmooth(true);

CategorySeries series2 = chart.addSeries("Normal", xData, yData2);
series2.setChartCategorySeriesRenderStyle(CategorySeriesRenderStyle.Line);
series2.setSmooth(false);

CategorySeries series3 = chart.addSeries("Bar", xData, yData3);
series3.setChartCategorySeriesRenderStyle(CategorySeriesRenderStyle.Bar);

return chart;
}
}
19 changes: 19 additions & 0 deletions xchart/src/main/java/org/knowm/xchart/CategorySeries.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public class CategorySeries extends AxesChartSeriesCategory {

private CategorySeriesRenderStyle chartCategorySeriesRenderStyle = null;

// smooth curve
private boolean smooth;

/**
* Constructor
*
Expand Down Expand Up @@ -53,6 +56,22 @@ public CategorySeries setOverlapped(boolean overlapped) {
return this;
}

public boolean isSmooth() {

return smooth;
}

/**
* Sets whether the line/area series should be rendered with smooth cubic Bezier curves.
*
* @param smooth true for smooth curves, false for straight lines
*/
public CategorySeries setSmooth(boolean smooth) {

this.smooth = smooth;
return this;
}

@Override
public LegendRenderType getLegendRenderType() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ public void doPaint(Graphics2D g) {
double previousX = -Double.MAX_VALUE;
double previousY = -Double.MAX_VALUE;

// smooth curve path for Line render style
Path2D.Double smoothPath = null;

Iterator<?> xItr = series.getXData().iterator();
Iterator<? extends Number> yItr = series.getYData().iterator();
Iterator<? extends Number> ebItr = null;
Expand All @@ -113,6 +116,12 @@ public void doPaint(Graphics2D g) {
// skip when a value is null
if (next == null) {

if (smoothPath != null) {
g.setColor(series.getLineColor());
g.setStroke(series.getLineStyle());
g.draw(smoothPath);
smoothPath = null;
}
// // for area charts
// closePath(g, path, previousX, getBounds(), yTopMargin);
// path = null;
Expand Down Expand Up @@ -398,9 +407,23 @@ else if (series.getChartCategorySeriesRenderStyle() == CategorySeriesRenderStyle
if (previousX != -Double.MAX_VALUE && previousY != -Double.MAX_VALUE) {
g.setColor(series.getLineColor());
g.setStroke(series.getLineStyle());
Shape line =
new Line2D.Double(previousX, previousY, xOffset + barWidth / 2, yOffset);
g.draw(line);
if (series.isSmooth()) {
if (smoothPath == null) {
smoothPath = new Path2D.Double();
smoothPath.moveTo(previousX, previousY);
}
smoothPath.curveTo(
(previousX + xOffset + barWidth / 2) / 2,
previousY,
(previousX + xOffset + barWidth / 2) / 2,
yOffset,
xOffset + barWidth / 2,
yOffset);
} else {
Shape line =
new Line2D.Double(previousX, previousY, xOffset + barWidth / 2, yOffset);
g.draw(line);
}
}
}
}
Expand All @@ -418,7 +441,17 @@ else if (series.getChartCategorySeriesRenderStyle() == CategorySeriesRenderStyle
path.moveTo(previousX, yBottomOfArea);
path.lineTo(previousX, previousY);
}
path.lineTo(xOffset + barWidth / 2, yOffset);
if (series.isSmooth()) {
path.curveTo(
(previousX + xOffset + barWidth / 2) / 2,
previousY,
(previousX + xOffset + barWidth / 2) / 2,
yOffset,
xOffset + barWidth / 2,
yOffset);
} else {
path.lineTo(xOffset + barWidth / 2, yOffset);
}
}
if (xOffset < previousX) {
throw new RuntimeException("X-Data must be in ascending order for Area Charts!!!");
Expand Down Expand Up @@ -504,6 +537,14 @@ else if (series.getChartCategorySeriesRenderStyle() == CategorySeriesRenderStyle
}
}

// flush smooth path for line series
if (smoothPath != null) {
g.setColor(series.getLineColor());
g.setStroke(series.getLineStyle());
g.draw(smoothPath);
smoothPath = null;
}

// close any open path for area charts
g.setColor(series.getFillColor());
closePath(g, path, previousX, getBounds(), yTopMargin);
Expand Down
Loading