Repository: knowm/XChart (java)

Issue:
Line annotations out of chart area
Hi,
it would be great to have the line annotations just inside the chart area, not on the whole panel.

![annotation](https://user-images.githubusercontent.com/19358486/106374460-c7afe580-6327-11eb-82ef-9069d8690529.png)


Pull request description:
Constraining AnnotationLine to plot surface
Fixes #557.

Patch:
diff --git a/xchart/src/main/java/org/knowm/xchart/AnnotationImage.java b/xchart/src/main/java/org/knowm/xchart/AnnotationImage.java
index b5c8ff3b..4523ae55 100644
--- a/xchart/src/main/java/org/knowm/xchart/AnnotationImage.java
+++ b/xchart/src/main/java/org/knowm/xchart/AnnotationImage.java
@@ -48,8 +48,8 @@ public class AnnotationImage extends Annotation {
       xOffset = (int) x - image.getWidth() / 2;
       yOffset = chart.getHeight() - (int) y - image.getWidth() / 2;
     } else {
-      xOffset = (int) (getXAxisSreenValue(x) + 0.5) - image.getWidth() / 2;
-      yOffset = (int) (getYAxisSreenValue(y) + 0.5) - image.getHeight() / 2;
+      xOffset = (int) (getXAxisScreenValue(x) + 0.5) - image.getWidth() / 2;
+      yOffset = (int) (getYAxisScreenValue(y) + 0.5) - image.getHeight() / 2;
     }
     g.drawImage(image, xOffset, yOffset, null);
 
diff --git a/xchart/src/main/java/org/knowm/xchart/AnnotationLine.java b/xchart/src/main/java/org/knowm/xchart/AnnotationLine.java
index 39e1ef8e..283a4df5 100644
--- a/xchart/src/main/java/org/knowm/xchart/AnnotationLine.java
+++ b/xchart/src/main/java/org/knowm/xchart/AnnotationLine.java
@@ -30,14 +30,16 @@ public class AnnotationLine extends Annotation {
       return;
     }
 
+    int lineWidth = (int) styler.getAnnotationLineStroke().getLineWidth();
+
     int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
 
     if (isVertical) {
-      y1 = 0;
-      y2 = chart.getHeight();
+      y1 = getYAxisScreenValueForMax() + lineWidth / 2;
+      y2 = getYAxisScreenValueForMin() - lineWidth / 2;
     } else {
-      x1 = 0;
-      x2 = chart.getWidth();
+      x1 = getXAxisScreenValueForMin() + lineWidth / 2;
+      x2 = getXAxisScreenValueForMax() - lineWidth / 2;
     }
 
     if (isValueInScreenSpace) {
@@ -50,10 +52,10 @@ public class AnnotationLine extends Annotation {
       }
     } else {
       if (isVertical) {
-        x1 = (int) getXAxisSreenValue(value);
+        x1 = (int) getXAxisScreenValue(value);
         x2 = x1;
       } else {
-        y1 = (int) getYAxisSreenValue(value);
+        y1 = (int) getYAxisScreenValue(value);
         y2 = y1;
       }
     }
@@ -63,11 +65,7 @@ public class AnnotationLine extends Annotation {
     g.drawLine(x1, y1, x2, y2);
 
     bounds =
-        new Rectangle2D.Double(
-            x1,
-            y1,
-            Math.max(x2 - x1, styler.getAnnotationLineStroke().getLineWidth()),
-            Math.max(y2 - y1, styler.getAnnotationLineStroke().getLineWidth()));
+        new Rectangle2D.Double(x1, y1, Math.max(x2 - x1, lineWidth), Math.max(y2 - y1, lineWidth));
   }
 
   public void setValue(double value) {
diff --git a/xchart/src/main/java/org/knowm/xchart/AnnotationText.java b/xchart/src/main/java/org/knowm/xchart/AnnotationText.java
index 6bf810b8..d794c7c2 100644
--- a/xchart/src/main/java/org/knowm/xchart/AnnotationText.java
+++ b/xchart/src/main/java/org/knowm/xchart/AnnotationText.java
@@ -57,8 +57,8 @@ public class AnnotationText extends Annotation {
       xOffset = x - textBounds.getWidth() / 2;
       yOffset = chart.getHeight() - y + textBounds.getHeight() / 2;
     } else {
-      xOffset = getXAxisSreenValue(x) - textBounds.getWidth() / 2;
-      yOffset = getYAxisSreenValue(y) + textBounds.getHeight() / 2;
+      xOffset = getXAxisScreenValue(x) - textBounds.getWidth() / 2;
+      yOffset = getYAxisScreenValue(y) + textBounds.getHeight() / 2;
     }
 
     AffineTransform orig = g.getTransform();
diff --git a/xchart/src/main/java/org/knowm/xchart/AnnotationTextPanel.java b/xchart/src/main/java/org/knowm/xchart/AnnotationTextPanel.java
index 1fc28b18..c9891ea3 100644
--- a/xchart/src/main/java/org/knowm/xchart/AnnotationTextPanel.java
+++ b/xchart/src/main/java/org/knowm/xchart/AnnotationTextPanel.java
@@ -81,8 +81,8 @@ public class AnnotationTextPanel extends Annotation {
       xOffset = x;
       yOffset = chart.getHeight() - height - y - 1;
     } else {
-      xOffset = getXAxisSreenValue(x);
-      yOffset = getYAxisSreenValue(y) - height - 1;
+      xOffset = getXAxisScreenValue(x);
+      yOffset = getYAxisScreenValue(y) - height - 1;
     }
 
     xOffset = Math.min(xOffset, (chart.getWidth() - width - 1));
diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Annotation.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Annotation.java
index 2b08fb61..e6deea7b 100644
--- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Annotation.java
+++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Annotation.java
@@ -28,11 +28,27 @@ public abstract class Annotation implements ChartPart {
     isVisible = visible;
   }
 
-  protected double getXAxisSreenValue(double chartSpaceValue) {
-    return chart.getXAxis().getScreenValue(chartSpaceValue);
+  protected int getXAxisScreenValue(double chartSpaceValue) {
+    return (int) chart.getXAxis().getScreenValue(chartSpaceValue);
   }
 
-  protected double getYAxisSreenValue(double chartSpaceValue) {
-    return chart.getYAxis().getScreenValue(chartSpaceValue);
+  protected int getYAxisScreenValue(double chartSpaceValue) {
+    return (int) chart.getYAxis().getScreenValue(chartSpaceValue);
+  }
+
+  protected int getXAxisScreenValueForMax() {
+    return (int) chart.getPlot().plotSurface.getBounds().getMaxX();
+  }
+
+  protected int getXAxisScreenValueForMin() {
+    return (int) chart.getPlot().plotSurface.getBounds().getMinX();
+  }
+
+  protected int getYAxisScreenValueForMax() {
+    return (int) chart.getPlot().plotSurface.getBounds().getMaxY();
+  }
+
+  protected int getYAxisScreenValueForMin() {
+    return (int) chart.getPlot().plotSurface.getBounds().getMinY();
   }
 }
diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Axis.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Axis.java
index 78b3c3d9..a715665b 100644
--- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Axis.java
+++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Axis.java
@@ -683,6 +683,14 @@ public class Axis<ST extends AxesChartStyler, S extends AxesChartSeries> impleme
     return tickLabelPosition;
   }
 
+  public double getScreenValueForMin() {
+    return getScreenValue(min);
+  }
+
+  public double getScreenValueForMax() {
+    return getScreenValue(max);
+  }
+
   /**
    * Converts a screen coordinate to chart coordinate value. Reverses the AxisTickCalculators
    * calculation.


Test patch:
diff --git a/xchart/src/test/java/org/knowm/xchart/AnnotationLineTest.java b/xchart/src/test/java/org/knowm/xchart/AnnotationLineTest.java
new file mode 100644
index 00000000..025f9fbd
--- /dev/null
+++ b/xchart/src/test/java/org/knowm/xchart/AnnotationLineTest.java
@@ -0,0 +1,28 @@
+package org.knowm.xchart;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AnnotationLineTest {
+
+  @Test
+  public void annotationLineShouldNotSpanOverWholeWidth() throws IOException {
+    // given
+    double[] xData = new double[] {0.0, 1.0, 2.0};
+    double[] yData = new double[] {2.0, 1.0, 0.0};
+    XYChart chart = QuickChart.getChart("Sample Chart", "X", "Y", "y(x)", xData, yData);
+
+    // when
+    AnnotationLine annotation = new AnnotationLine(0.5d, false, false);
+    chart.addAnnotation(annotation);
+    OutputStream output = new ByteArrayOutputStream();
+    BitmapEncoder.saveBitmap(chart, output, BitmapEncoder.BitmapFormat.PNG);
+
+    // test
+    Assert.assertTrue(annotation.getBounds().getX() > 50);
+    Assert.assertTrue(annotation.getBounds().getWidth() < 500);
+  }
+}