From 168aedd257c95a48658702e4117aec5ac124ef58 Mon Sep 17 00:00:00 2001
From: Tim Molter <tim.molter@gmail.com>
Date: Sun, 30 Mar 2014 21:28:56 +0200
Subject: [PATCH] roughed in vector export

---
 .gitignore                                    |   5 +-
 pom.xml                                       |  23 +++-
 .../xchart/standalone/VectorGraphicsTest.java |  41 ++++++
 xchart/pom.xml                                |  12 +-
 .../xeiam/xchart/VectorGraphicsEncoder.java   |  54 ++++++++
 .../internal/chartpart/AxisTickLabels.java    |  28 +++-
 .../xchart/internal/chartpart/AxisTitle.java  |  16 ++-
 .../xchart/internal/chartpart/ChartTitle.java |  11 +-
 .../xchart/internal/chartpart/Legend.java     | 123 +++++++++++++-----
 .../chartpart/PlotContentBarChart.java        |   2 +-
 10 files changed, 272 insertions(+), 43 deletions(-)
 create mode 100644 xchart-demo/src/main/java/com/xeiam/xchart/standalone/VectorGraphicsTest.java
 create mode 100644 xchart/src/main/java/com/xeiam/xchart/VectorGraphicsEncoder.java

diff --git a/.gitignore b/.gitignore
index fed9ea40..9a384e0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,7 @@ bin/
 *.png
 *.jpg
 *.bmp
-*.gif
\ No newline at end of file
+*.gif
+*.svg
+*.pdf
+*.eps
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 784fa47b..20d6c21b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,4 +1,5 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
 	<modelVersion>4.0.0</modelVersion>
 
@@ -66,6 +67,24 @@
 		<downloadUrl>https://oss.sonatype.org/content/groups/public/com/xeiam/xchart</downloadUrl>
 	</distributionManagement>
 
+	<repositories>
+		<repository>
+			<id>erichseifert.de</id>
+			<url>http://mvn.erichseifert.de/maven2</url>
+		</repository>
+	</repositories>
+
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>de.erichseifert.vectorgraphics2d</groupId>
+				<artifactId>VectorGraphics2D</artifactId>
+				<version>0.9.1</version>
+				<optional>true</optional>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
 	<dependencies>
 		<dependency>
 			<groupId>junit</groupId>
@@ -128,7 +147,7 @@
 					<autoversionsubmodules>true</autoversionsubmodules>
 				</configuration>
 			</plugin>
-			
+
 			<!-- for header in all .java files -->
 			<plugin>
 				<groupId>com.mycila.maven-license-plugin</groupId>
diff --git a/xchart-demo/src/main/java/com/xeiam/xchart/standalone/VectorGraphicsTest.java b/xchart-demo/src/main/java/com/xeiam/xchart/standalone/VectorGraphicsTest.java
new file mode 100644
index 00000000..33f2877e
--- /dev/null
+++ b/xchart-demo/src/main/java/com/xeiam/xchart/standalone/VectorGraphicsTest.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright 2013 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.standalone;
+
+import java.io.IOException;
+
+import com.xeiam.xchart.Chart;
+import com.xeiam.xchart.QuickChart;
+import com.xeiam.xchart.VectorGraphicsEncoder;
+import com.xeiam.xchart.VectorGraphicsEncoder.VectorGraphicsFormat;
+
+/**
+ * @author timmolter
+ */
+public class VectorGraphicsTest {
+
+  public static void main(String[] args) throws IOException {
+
+    double[] xData = new double[] { 0.0, 1.0, 2.0 };
+    double[] yData = new double[] { 2.0, 1.0, 0.0 };
+
+    // Create Chart
+    Chart chart = QuickChart.getChart("Sample Chart", "X", "Y", "y(x)", xData, yData);
+
+    VectorGraphicsEncoder.saveVectorGraphic(chart, "", VectorGraphicsFormat.PDF);
+  }
+
+}
diff --git a/xchart/pom.xml b/xchart/pom.xml
index 23fb06a1..6e2fdbd2 100644
--- a/xchart/pom.xml
+++ b/xchart/pom.xml
@@ -1,7 +1,8 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
 	<modelVersion>4.0.0</modelVersion>
-	
+
 	<parent>
 		<groupId>com.xeiam.xchart</groupId>
 		<artifactId>xchart-parent</artifactId>
@@ -13,4 +14,11 @@
 	<name>XChart</name>
 	<description>The core XChart library</description>
 
+	<dependencies>
+		<dependency>
+			<groupId>de.erichseifert.vectorgraphics2d</groupId>
+			<artifactId>VectorGraphics2D</artifactId>
+		</dependency>
+	</dependencies>
+
 </project>
diff --git a/xchart/src/main/java/com/xeiam/xchart/VectorGraphicsEncoder.java b/xchart/src/main/java/com/xeiam/xchart/VectorGraphicsEncoder.java
new file mode 100644
index 00000000..5eba3583
--- /dev/null
+++ b/xchart/src/main/java/com/xeiam/xchart/VectorGraphicsEncoder.java
@@ -0,0 +1,54 @@
+/**
+ * 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;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import de.erichseifert.vectorgraphics2d.SVGGraphics2D;
+
+/**
+ * A helper class with static methods for saving Charts as bitmaps
+ * 
+ * @author timmolter
+ */
+public final class VectorGraphicsEncoder {
+
+  /**
+   * Constructor - Private constructor to prevent instantiation
+   */
+  private VectorGraphicsEncoder() {
+
+  }
+
+  public enum VectorGraphicsFormat {
+    EPS, PDF, SVG;
+  }
+
+  public static void saveVectorGraphic(Chart chart, String fileName, VectorGraphicsFormat vectorGraphicsFormat) throws IOException {
+
+    SVGGraphics2D g = new SVGGraphics2D(0.0, 0.0, chart.getWidth(), chart.getHeight());
+    chart.paint(g, chart.getWidth(), chart.getHeight());
+    // Write the vector graphic output to a file
+    FileOutputStream file = new FileOutputStream("./ellipse.svg");
+    try {
+      file.write(g.getBytes());
+    } finally {
+      file.close();
+    }
+  }
+
+}
diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLabels.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLabels.java
index 5b851847..4f26213e 100644
--- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLabels.java
+++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLabels.java
@@ -16,8 +16,10 @@
 package com.xeiam.xchart.internal.chartpart;
 
 import java.awt.Graphics2D;
+import java.awt.Shape;
 import java.awt.font.FontRenderContext;
 import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
 
 /**
@@ -76,12 +78,20 @@ public class AxisTickLabels implements ChartPart {
           // TextLayout layout = new TextLayout(tickLabel, font, new FontRenderContext(null, true, false));
           TextLayout layout = new TextLayout(tickLabel, getChartPainter().getStyleManager().getAxisTickLabelsFont(), frc);
           Rectangle2D tickLabelBounds = layout.getBounds();
-          layout.draw(g, (float) xOffset, (float) (yOffset + axisTick.getAxis().getPaintZone().getHeight() - tickLocation + tickLabelBounds.getHeight() / 2.0));
+          // layout.draw(g, (float) xOffset, (float) (yOffset + axisTick.getAxis().getPaintZone().getHeight() - tickLocation + tickLabelBounds.getHeight() / 2.0));
+
+          Shape shape = layout.getOutline(null);
+
+          AffineTransform orig = g.getTransform();
+          AffineTransform at = new AffineTransform();
+          at.translate((float) xOffset, (float) (yOffset + axisTick.getAxis().getPaintZone().getHeight() - tickLocation + tickLabelBounds.getHeight() / 2.0));
+          g.transform(at);
+          g.fill(shape);
+          g.setTransform(orig);
 
           if (tickLabelBounds.getWidth() > maxTickLabelWidth) {
             maxTickLabelWidth = tickLabelBounds.getWidth();
           }
-          // g.setTransform(orig);
 
         }
       }
@@ -106,7 +116,19 @@ public class AxisTickLabels implements ChartPart {
           FontRenderContext frc = g.getFontRenderContext();
           TextLayout layout = new TextLayout(tickLabel, getChartPainter().getStyleManager().getAxisTickLabelsFont(), frc);
           Rectangle2D tickLabelBounds = layout.getBounds();
-          layout.draw(g, (float) (xOffset + tickLocation - tickLabelBounds.getWidth() / 2.0), (float) yOffset);
+          // layout.draw(g, (float) (xOffset + tickLocation - tickLabelBounds.getWidth() / 2.0), (float) yOffset);
+
+          Shape shape = layout.getOutline(null);
+
+          // Graphics2D gTemp = (Graphics2D) g.create();
+          // gTemp.setTransform(g.getTransform());
+          // gTemp.translate((float) (xOffset + tickLocation - tickLabelBounds.getWidth() / 2.0), (float) yOffset);
+          AffineTransform orig = g.getTransform();
+          AffineTransform at = new AffineTransform();
+          at.translate((float) (xOffset + tickLocation - tickLabelBounds.getWidth() / 2.0), (float) yOffset);
+          g.transform(at);
+          g.fill(shape);
+          g.setTransform(orig);
 
           if (tickLabelBounds.getHeight() > maxTickLabelHeight) {
             maxTickLabelHeight = tickLabelBounds.getHeight();
diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTitle.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTitle.java
index c3f2be21..e16c4a7d 100644
--- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTitle.java
+++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTitle.java
@@ -16,6 +16,7 @@
 package com.xeiam.xchart.internal.chartpart;
 
 import java.awt.Graphics2D;
+import java.awt.Shape;
 import java.awt.font.FontRenderContext;
 import java.awt.font.TextLayout;
 import java.awt.geom.AffineTransform;
@@ -72,11 +73,13 @@ public class AxisTitle implements ChartPart {
         int xOffset = (int) (axis.getPaintZone().getX() + nonRotatedRectangle.getHeight());
         int yOffset = (int) ((axis.getPaintZone().getHeight() + nonRotatedRectangle.getWidth()) / 2.0 + axis.getPaintZone().getY());
         AffineTransform orig = g.getTransform();
-        g.transform(AffineTransform.getRotateInstance(Math.PI / -2.0, xOffset, yOffset));
+        AffineTransform at = new AffineTransform();
+        at.rotate(Math.PI / -2.0, xOffset, yOffset);
+        g.transform(at);
         g.drawString(text, xOffset, yOffset);
+        g.setTransform(orig);
 
         // ///////////////////////////////////////////////
-        g.setTransform(orig);
         // System.out.println(nonRotatedRectangle.getHeight());
 
         // bounds
@@ -103,7 +106,14 @@ public class AxisTitle implements ChartPart {
         double xOffset = axis.getPaintZone().getX() + (axis.getPaintZone().getWidth() - rectangle.getWidth()) / 2.0;
         double yOffset = axis.getPaintZone().getY() + axis.getPaintZone().getHeight() - rectangle.getHeight();
 
-        textLayout.draw(g, (float) xOffset, (float) (yOffset - rectangle.getY()));
+        // textLayout.draw(g, (float) xOffset, (float) (yOffset - rectangle.getY()));
+        Shape shape = textLayout.getOutline(null);
+        AffineTransform orig = g.getTransform();
+        AffineTransform at = new AffineTransform();
+        at.translate((float) xOffset, (float) (yOffset - rectangle.getY()));
+        g.transform(at);
+        g.fill(shape);
+        g.setTransform(orig);
 
         bounds =
             new Rectangle2D.Double(xOffset, yOffset - getChartPainter().getStyleManager().getAxisTitlePadding(), rectangle.getWidth(), rectangle.getHeight()
diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/ChartTitle.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/ChartTitle.java
index f7126897..973ff52a 100644
--- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/ChartTitle.java
+++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/ChartTitle.java
@@ -20,6 +20,7 @@ import java.awt.Graphics2D;
 import java.awt.Shape;
 import java.awt.font.FontRenderContext;
 import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
 
 /**
@@ -120,7 +121,15 @@ public class ChartTitle implements ChartPart {
       // g.draw(bounds);
 
       g.setColor(chartPainter.getStyleManager().getChartFontColor());
-      textLayout.draw(g, xOffset, yOffset);
+      // textLayout.draw(g, xOffset, yOffset);
+
+      Shape shape = textLayout.getOutline(null);
+      AffineTransform orig = g.getTransform();
+      AffineTransform at = new AffineTransform();
+      at.translate(xOffset, yOffset);
+      g.transform(at);
+      g.fill(shape);
+      g.setTransform(orig);
     }
 
   }
diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/Legend.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/Legend.java
index 5e719299..3244fd8d 100644
--- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/Legend.java
+++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/Legend.java
@@ -16,9 +16,11 @@
 package com.xeiam.xchart.internal.chartpart;
 
 import java.awt.BasicStroke;
-import java.awt.FontMetrics;
 import java.awt.Graphics2D;
 import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
 import java.awt.geom.Line2D;
 import java.awt.geom.Rectangle2D;
 import java.util.AbstractMap;
@@ -37,6 +39,7 @@ public class Legend implements ChartPart {
 
   private static final int LEGEND_MARGIN = 6;
   private static final int BOX_SIZE = 20;
+  private static final int MULTI_LINE_SPACE = 3;
 
   /**
    * parent
@@ -71,26 +74,25 @@ public class Legend implements ChartPart {
     }
 
     StyleManager styleManager = getChartPainter().getStyleManager();
-    FontMetrics fontMetrics = g.getFontMetrics(chartPainter.getStyleManager().getLegendFont());
     boolean isBar = styleManager.getChartType() == ChartType.Bar;
 
     // determine legend text content max width
     double legendTextContentMaxWidth = 0;
-    // double legendTextContentMaxHeight = 0;
 
     // determine legend content height
     double legendContentHeight = 0;
 
     for (Series series : chartPainter.getAxisPair().getSeriesMap().values()) {
 
-      List<Map.Entry<String, Rectangle2D>> seriesBounds = getSeriesNameBounds(series, g);
+      List<Map.Entry<String, Rectangle2D>> seriesBounds = getSeriesTextBounds(series, g);
 
       double blockHeight = 0;
       for (Map.Entry<String, Rectangle2D> entry : seriesBounds) {
-        blockHeight += entry.getValue().getHeight();
+        blockHeight += entry.getValue().getHeight() + MULTI_LINE_SPACE;
         legendTextContentMaxWidth = Math.max(legendTextContentMaxWidth, entry.getValue().getWidth());
       }
 
+      blockHeight -= MULTI_LINE_SPACE;
       blockHeight = Math.max(blockHeight, isBar ? BOX_SIZE : getChartPainter().getStyleManager().getMarkerSize());
 
       legendContentHeight += blockHeight + styleManager.getLegendPadding();
@@ -104,28 +106,18 @@ public class Legend implements ChartPart {
     else {
       legendContentWidth = BOX_SIZE + styleManager.getLegendPadding() + legendTextContentMaxWidth;
     }
+
     // Legend Box
     double legendBoxWidth = legendContentWidth + 2 * styleManager.getLegendPadding();
     double legendBoxHeight = legendContentHeight + 1 * styleManager.getLegendPadding();
     return new double[] { legendBoxWidth, legendBoxHeight };
   }
 
-  private List<Map.Entry<String, Rectangle2D>> getSeriesNameBounds(Series series, Graphics2D g) {
-
-    String lines[] = series.getName().split("\\n");
-    List<Map.Entry<String, Rectangle2D>> stringBounds = new ArrayList<Map.Entry<String, Rectangle2D>>(lines.length);
-    for (String line : lines) {
-      Rectangle2D bounds = g.getFontMetrics().getStringBounds(line, g);
-      stringBounds.add(new AbstractMap.SimpleEntry<String, Rectangle2D>(line, bounds));
-    }
-    return stringBounds;
-  }
-
   @Override
   public void paint(Graphics2D g) {
 
     bounds = new Rectangle2D.Double();
-    g.setFont(chartPainter.getStyleManager().getLegendFont());
+    // g.setFont(chartPainter.getStyleManager().getLegendFont());
 
     StyleManager styleManager = getChartPainter().getStyleManager();
 
@@ -138,7 +130,7 @@ public class Legend implements ChartPart {
     double legendBoxWidth = sizeHint[0];
     double legendBoxHeight = sizeHint[1];
 
-    FontMetrics fontMetrics = g.getFontMetrics(styleManager.getLegendFont());
+    // FontMetrics fontMetrics = g.getFontMetrics(styleManager.getLegendFont());
 
     // legend draw position
     double xOffset = 0;
@@ -186,16 +178,20 @@ public class Legend implements ChartPart {
 
     for (Series series : chartPainter.getAxisPair().getSeriesMap().values()) {
 
-      List<Map.Entry<String, Rectangle2D>> seriesNameBounds = getSeriesNameBounds(series, g);
+      List<Map.Entry<String, Rectangle2D>> seriesTextBounds = getSeriesTextBounds(series, g);
 
       float blockHeight = 0;
-      for (Map.Entry<String, Rectangle2D> entry : seriesNameBounds) {
-        blockHeight += entry.getValue().getHeight();
+      double legendTextContentMaxWidth = 0;
+      for (Map.Entry<String, Rectangle2D> entry : seriesTextBounds) {
+        blockHeight += entry.getValue().getHeight() + MULTI_LINE_SPACE;
+        legendTextContentMaxWidth = Math.max(legendTextContentMaxWidth, entry.getValue().getWidth());
       }
+      blockHeight -= MULTI_LINE_SPACE;
 
       blockHeight = Math.max(blockHeight, styleManager.getChartType() == ChartType.Bar ? BOX_SIZE : getChartPainter().getStyleManager().getMarkerSize());
 
       if (styleManager.getChartType() != ChartType.Bar) {
+
         // paint line
         if (styleManager.getChartType() != ChartType.Scatter && series.getStroke() != null) {
           g.setColor(series.getStrokeColor());
@@ -204,10 +200,17 @@ public class Legend implements ChartPart {
           g.draw(line);
         }
 
+        // // debug box
+        // Rectangle2D boundsTemp = new Rectangle2D.Double(startx, starty, styleManager.getLegendSeriesLineLength(), blockHeight);
+        // g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+        // g.setColor(Color.red);
+        // g.draw(boundsTemp);
+
         // paint marker
         if (series.getMarker() != null) {
           g.setColor(series.getMarkerColor());
           series.getMarker().paint(g, startx + styleManager.getLegendSeriesLineLength() / 2.0, starty + blockHeight / 2.0, getChartPainter().getStyleManager().getMarkerSize());
+
         }
       }
       else {
@@ -217,27 +220,73 @@ public class Legend implements ChartPart {
           Shape rectSmall = new Rectangle2D.Double(startx, starty, BOX_SIZE, BOX_SIZE);
           g.fill(rectSmall);
         }
+        // // debug box
+        // Rectangle2D boundsTemp = new Rectangle2D.Double(startx, starty, BOX_SIZE, BOX_SIZE);
+        // g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+        // g.setColor(Color.red);
+        // g.draw(boundsTemp);
       }
 
       // paint series name
       g.setColor(chartPainter.getStyleManager().getChartFontColor());
 
-      float itemOffsetY = -fontMetrics.getDescent();
+      double multiLineOffset = 0.0;
+
       if (styleManager.getChartType() != ChartType.Bar) {
-        final float x = (float) (startx + styleManager.getLegendSeriesLineLength() + styleManager.getLegendPadding());
-        for (Map.Entry<String, Rectangle2D> entry : seriesNameBounds) {
-          g.drawString(entry.getKey(), x, (float) (starty + entry.getValue().getHeight()) + itemOffsetY);
-          itemOffsetY += entry.getValue().getHeight();
+
+        double x = startx + styleManager.getLegendSeriesLineLength() + styleManager.getLegendPadding();
+        for (Map.Entry<String, Rectangle2D> entry : seriesTextBounds) {
+
+          // float itemOffsetY = -fontMetrics.getDescent();
+          // System.out.println(itemOffsetY);
+
+          double height = entry.getValue().getHeight();
+          double centerOffsetY = (Math.max(getChartPainter().getStyleManager().getMarkerSize(), height) - height) / 2.0;
+
+          FontRenderContext frc = g.getFontRenderContext();
+          TextLayout tl = new TextLayout(entry.getKey(), styleManager.getLegendFont(), frc);
+          Shape shape = tl.getOutline(null);
+          AffineTransform orig = g.getTransform();
+          AffineTransform at = new AffineTransform();
+          at.translate(x, starty + height + centerOffsetY + multiLineOffset);
+          g.transform(at);
+          g.fill(shape);
+          g.setTransform(orig);
+
+          // // debug box
+          // Rectangle2D boundsTemp = new Rectangle2D.Double(x, starty + centerOffsetY + multiLineOffset, entry.getValue().getWidth(), height);
+          // g.setColor(Color.blue);
+          // g.draw(boundsTemp);
+
+          multiLineOffset += height + MULTI_LINE_SPACE;
         }
+
         starty += blockHeight + styleManager.getLegendPadding();
       }
       else {
-        final float x = (float) (startx + BOX_SIZE + styleManager.getLegendPadding());
-        for (Map.Entry<String, Rectangle2D> entry : seriesNameBounds) {
+
+        final double x = startx + BOX_SIZE + styleManager.getLegendPadding();
+        for (Map.Entry<String, Rectangle2D> entry : seriesTextBounds) {
+
           double height = entry.getValue().getHeight();
           double centerOffsetY = (Math.max(BOX_SIZE, height) - height) / 2.0;
-          g.drawString(entry.getKey(), x, (float) (starty + height + itemOffsetY + centerOffsetY));
-          itemOffsetY += height;
+
+          FontRenderContext frc = g.getFontRenderContext();
+          TextLayout tl = new TextLayout(entry.getKey(), styleManager.getLegendFont(), frc);
+          Shape shape = tl.getOutline(null);
+          AffineTransform orig = g.getTransform();
+          AffineTransform at = new AffineTransform();
+          at.translate(x, starty + height + centerOffsetY + multiLineOffset);
+          g.transform(at);
+          g.fill(shape);
+          g.setTransform(orig);
+
+          // // debug box
+          // Rectangle2D boundsTemp = new Rectangle2D.Double(x, starty + centerOffsetY, entry.getValue().getWidth(), height);
+          // g.setColor(Color.blue);
+          // g.draw(boundsTemp);
+          multiLineOffset += height + MULTI_LINE_SPACE;
+
         }
         starty += blockHeight + styleManager.getLegendPadding();
       }
@@ -252,6 +301,20 @@ public class Legend implements ChartPart {
 
   }
 
+  private List<Map.Entry<String, Rectangle2D>> getSeriesTextBounds(Series series, Graphics2D g) {
+
+    String lines[] = series.getName().split("\\n");
+    List<Map.Entry<String, Rectangle2D>> seriesTextBounds = new ArrayList<Map.Entry<String, Rectangle2D>>(lines.length);
+    for (String line : lines) {
+      FontRenderContext frc = g.getFontRenderContext();
+      TextLayout tl = new TextLayout(line, getChartPainter().getStyleManager().getLegendFont(), frc);
+      Shape shape = tl.getOutline(null);
+      Rectangle2D bounds = shape.getBounds2D();
+      seriesTextBounds.add(new AbstractMap.SimpleEntry<String, Rectangle2D>(line, bounds));
+    }
+    return seriesTextBounds;
+  }
+
   @Override
   public Rectangle2D getBounds() {
 
diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentBarChart.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentBarChart.java
index e6577354..a13983f8 100644
--- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentBarChart.java
+++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentBarChart.java
@@ -62,7 +62,7 @@ public class PlotContentBarChart extends PlotContent {
     for (Series series : getChartPainter().getAxisPair().getSeriesMap().values()) {
 
       // data points
-      Collection<?> xData = series.getXData();
+      // Collection<?> xData = series.getXData();
 
       Collection<? extends Number> yData = series.getYData();
       double yMin = getChartPainter().getAxisPair().getYAxis().getMin();
-- 
GitLab