Add common nvd3 chart properties

The common properties allow a basic customization of nvd3 charts.

Change-Id: I14eba86e219b9290924e835e558710ab74f49a2f
Signed-off-by: Andreas Erlach <andreas.erlach@mic.co.at>
diff --git a/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-bar.js b/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-bar.js
index 3268982..5e2b9b0 100644
--- a/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-bar.js
+++ b/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-bar.js
@@ -17,5 +17,8 @@
   chart.discretebar.dispatch.on( "elementClick.rap", function( item ) {
     widget.notifySelection( item.index );
   });
+  chart.colorScale = function( value ) {
+    return chart.color( d3.scale.ordinal().range( value ).range() );
+  };
   return chart;
 });
diff --git a/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-line.js b/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-line.js
index 3d70516..f27f0fa 100644
--- a/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-line.js
+++ b/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-line.js
@@ -22,5 +22,8 @@
   chart.yAxisFormat = function( value ) {
     return chart.yAxis.tickFormat( d3.format( value ) );
   };
+  chart.colorScale = function( value ) {
+    return chart.color( d3.scale.ordinal().range( value ).range() );
+  };
   return chart;
 });
diff --git a/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-pie.js b/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-pie.js
index 204c1ff..896160e 100644
--- a/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-pie.js
+++ b/bundles/org.eclipse.rap.addons.chart/js/chart/nv/nv-pie.js
@@ -17,5 +17,8 @@
   chart.pie.dispatch.on( "elementClick.rap", function( item ) {
     widget.notifySelection( item.index );
   });
+  chart.colorScale = function( value ) {
+    return chart.color( d3.scale.ordinal().range( value ).range() );
+  };
   return chart;
 });
diff --git a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/Colors.java b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/Colors.java
new file mode 100644
index 0000000..cf8059b
--- /dev/null
+++ b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/Colors.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Ralf Sternberg - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.addons.chart;
+
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * Common D3 color definitions. Can be used to set the color scale of <code>NvChart</code>.
+ *
+ * @see "https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors"
+ */
+public class Colors {
+
+  public static final RGB[] CATEGORY_10 = {
+    new RGB( 0x1f, 0x77, 0xb4 ),
+    new RGB( 0xff, 0x7f, 0x0e ),
+    new RGB( 0x2c, 0xa0, 0x2c ),
+    new RGB( 0xd6, 0x27, 0x28 ),
+    new RGB( 0x94, 0x67, 0xbd ),
+    new RGB( 0x8c, 0x56, 0x4b ),
+    new RGB( 0xe3, 0x77, 0xc2 ),
+    new RGB( 0x7f, 0x7f, 0x7f ),
+    new RGB( 0xbc, 0xbd, 0x22 ),
+    new RGB( 0x17, 0xbe, 0xcf )
+  };
+
+  public static final RGB[] CATEGORY_20 = {
+    new RGB( 0x1f, 0x77, 0xb4 ),
+    new RGB( 0xae, 0xc7, 0xe8 ),
+    new RGB( 0xff, 0x7f, 0x0e ),
+    new RGB( 0xff, 0xbb, 0x78 ),
+    new RGB( 0x2c, 0xa0, 0x2c ),
+    new RGB( 0x98, 0xdf, 0x8a ),
+    new RGB( 0xd6, 0x27, 0x28 ),
+    new RGB( 0xff, 0x98, 0x96 ),
+    new RGB( 0x94, 0x67, 0xbd ),
+    new RGB( 0xc5, 0xb0, 0xd5 ),
+    new RGB( 0x8c, 0x56, 0x4b ),
+    new RGB( 0xc4, 0x9c, 0x94 ),
+    new RGB( 0xe3, 0x77, 0xc2 ),
+    new RGB( 0xf7, 0xb6, 0xd2 ),
+    new RGB( 0x7f, 0x7f, 0x7f ),
+    new RGB( 0xc7, 0xc7, 0xc7 ),
+    new RGB( 0xbc, 0xbd, 0x22 ),
+    new RGB( 0xdb, 0xdb, 0x8d ),
+    new RGB( 0x17, 0xbe, 0xcf ),
+    new RGB( 0x9e, 0xda, 0xe5 )
+  };
+
+  public static final RGB[] CATEGORY_20B = {
+    new RGB( 0x39, 0x3b, 0x79 ),
+    new RGB( 0x52, 0x54, 0xa3 ),
+    new RGB( 0x6b, 0x6e, 0xcf ),
+    new RGB( 0x9c, 0x9e, 0xde ),
+    new RGB( 0x63, 0x79, 0x39 ),
+    new RGB( 0x8c, 0xa2, 0x52 ),
+    new RGB( 0xb5, 0xcf, 0x6b ),
+    new RGB( 0xce, 0xdb, 0x9c ),
+    new RGB( 0x8c, 0x6d, 0x31 ),
+    new RGB( 0xbd, 0x9e, 0x39 ),
+    new RGB( 0xe7, 0xba, 0x52 ),
+    new RGB( 0xe7, 0xcb, 0x94 ),
+    new RGB( 0x84, 0x3c, 0x39 ),
+    new RGB( 0xad, 0x49, 0x4a ),
+    new RGB( 0xd6, 0x61, 0x6b ),
+    new RGB( 0xe7, 0x96, 0x9c ),
+    new RGB( 0x7b, 0x41, 0x73 ),
+    new RGB( 0xa5, 0x51, 0x94 ),
+    new RGB( 0xce, 0x6d, 0xbd ),
+    new RGB( 0xde, 0x9e, 0xd6 )
+  };
+
+  private Colors() {
+    // prevent instantiation
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/NvChart.java b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/NvChart.java
index 5bf5f67..0cb688c 100644
--- a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/NvChart.java
+++ b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/NvChart.java
@@ -10,6 +10,11 @@
  ******************************************************************************/
 package org.eclipse.rap.addons.chart;
 
+import static org.eclipse.rap.addons.chart.internal.ColorUtil.toJson;
+
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.rwt.theme.BoxDimensions;
+import org.eclipse.swt.graphics.RGB;
 import org.eclipse.swt.widgets.Composite;
 
 
@@ -37,6 +42,12 @@
   private static final String DEF_NVD3_CSS_URL
     = "https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.min.css";
 
+  private String noData;
+  private boolean showLegend = true;
+  private boolean tooltipsEnabled = true;
+  private RGB[] colors;
+  private BoxDimensions margin;
+
   /**
    * Create a chart instance that is implemented by the given <code>renderer</code>.
    */
@@ -47,4 +58,129 @@
     requireCss( registerResource( "resources/nv-chart.css" ) );
   }
 
+  /**
+   * Message to display if no data items are provided. Default text is
+   * <code>No Data Available.</code>.
+   *
+   * @param text the text to display when no data is available
+   */
+  public void setNoDataMessage( String text ) {
+    checkWidget();
+    if( text != null && !text.equals( noData ) ) {
+      noData = text;
+      setOption( "noData", text );
+    }
+  }
+
+  /**
+   * Returns the text to display when no data is available.
+   *
+   * @return the text to display when no data is available
+   */
+  public String getNoDataMessage() {
+    checkWidget();
+    return noData;
+  }
+
+  /**
+   * Whether to display the chart legend or not. Default is <code>true</code>.
+   *
+   * @param show <code>true</code> if legend should be shown
+   */
+  public void setShowLegend( boolean show ) {
+    checkWidget();
+    if( showLegend != show ) {
+      showLegend = show;
+      setOption( "showLegend", show );
+    }
+  }
+
+  /**
+   * Returns whether legend is shown for chart.
+   *
+   * @return <code>true</code> if legend is shown
+   */
+  public boolean getShowLegend() {
+    checkWidget();
+    return showLegend;
+  }
+
+  /**
+   * Whether tooltips are enabled or not. Default is <code>true</code>.
+   *
+   * @param enabled <code>true</code> if tooltips are enabled
+   */
+  public void setTooltipsEnabled( boolean enabled ) {
+    checkWidget();
+    if( tooltipsEnabled != enabled ) {
+      tooltipsEnabled = enabled;
+      setOption( "tooltip.enabled", enabled );
+    }
+  }
+
+  /**
+   * Returns whether tooltips are enabled for the chart.
+   *
+   * @return <code>true</code> if tooltips are enabled
+   */
+  public boolean isTooltipsEnabled() {
+    checkWidget();
+    return tooltipsEnabled;
+  }
+
+  /**
+   * Sets the colors to be used by the chart. This can be used alternatively to specifying the
+   * colors individually for every <code>DataItem</code>. Default colors used by nvd3 is
+   * category20.
+   *
+   * @param colors the colors as array of <code>RGB</code> values
+   *
+   * @see "https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors"
+   */
+  public void setColors( RGB[] colors ) {
+    checkWidget();
+    if( colors != null && !colors.equals( this.colors ) ) {
+      this.colors = colors;
+      setOption( "colorScale", toJson( colors ) );
+    }
+  }
+
+  /**
+   * Returns the colors used by the chart.
+   *
+   * @return the colors, or null if nvd3 defaults applies
+   */
+  public RGB[] getColors() {
+    checkWidget();
+    return colors;
+  }
+
+  /**
+   * Defines the margins for the chart component. Default is <code>0</code> for all margins.
+   *
+   * @param margin object with margins of chart
+   */
+  public void setMargin( BoxDimensions margin ) {
+    checkWidget();
+    if( margin != null && !margin.equals( this.margin ) ) {
+      this.margin = margin;
+      JsonObject marginJson = new JsonObject()
+        .add( "top", margin.top )
+        .add( "right", margin.right)
+        .add( "bottom", margin.bottom )
+        .add( "left", margin.left);
+      setOption( "margin", marginJson );
+    }
+  }
+
+  /**
+   * Returns the margins of the chart.
+   *
+   * @return the margins of the chart
+   */
+  public BoxDimensions getMargin() {
+    checkWidget();
+    return margin;
+  }
+
 }
diff --git a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/BarChart.java b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/BarChart.java
index a78cb56..b59aad5 100644
--- a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/BarChart.java
+++ b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/BarChart.java
@@ -31,6 +31,11 @@
 public class BarChart extends NvChart {
 
   private boolean showValues = true;
+  private boolean showXAxis = true;
+  private boolean showYAxis = true;
+  private String xAxisLabel = "";
+  private String yAxisLabel = "";
+  private boolean staggerLabels;
 
   /**
    * Creates a new empty BarChart.
@@ -41,7 +46,8 @@
   }
 
   /**
-   * Whether the y values should be displayed in the chart. The default is <code>true</code>.
+   * Whether the y values should be displayed in the chart. Only recommended to use
+   * if there aren't many bars. The default is <code>true</code>.
    *
    * @param show <code>true</code> to display y values
    */
@@ -64,6 +70,122 @@
   }
 
   /**
+   * Sets the X axis label. Default is empty.
+   *
+   * @param label the label text
+   */
+  public void setXAxisLabel( String label ) {
+    checkWidget();
+    if( label != null && !label.equals( xAxisLabel ) ) {
+      xAxisLabel = label;
+      setOption( "xAxis.axisLabel", label );
+    }
+  }
+
+  /**
+   * Returns the X axis label.
+   *
+   * @return the label for the X axis.
+   */
+  public String getXAxisLabel() {
+    checkWidget();
+    return xAxisLabel;
+  }
+
+  /**
+   * Sets the Y axis label. Default is empty.
+   *
+   * @param label the label text
+   */
+  public void setYAxisLabel( String label ) {
+    checkWidget();
+    if( label != null && !label.equals( yAxisLabel ) ) {
+      yAxisLabel = label;
+      setOption( "yAxis.axisLabel", label );
+    }
+  }
+
+  /**
+   * Returns the X axis label.
+   *
+   * @return the label for the Y axis
+   */
+  public String getYAxisLabel() {
+    checkWidget();
+    return yAxisLabel;
+  }
+
+  /**
+   * Display or hide the X axis. Default is <code>true</code>.
+   *
+   * @param show <code>true</code> to display X axis
+   */
+  public void setShowXAxis( boolean show ) {
+    checkWidget();
+    if( showXAxis != show ) {
+      showXAxis = show;
+      setOption( "showXAxis", show );
+    }
+  }
+
+  /**
+   * Returns whether X axis is displayed in chart.
+   *
+   * @return <code>true</code> if X axis is displayed.
+   */
+  public boolean getShowXAxis() {
+    checkWidget();
+    return showXAxis;
+  }
+
+  /**
+   * Display or hide the Y axis. Default is <code>true</code>.
+   *
+   * @param show <code>true</code> to display Y axis
+   */
+  public void setShowYAxis( boolean show ) {
+    checkWidget();
+    if( showYAxis != show ) {
+      showYAxis = show;
+      setOption( "showYAxis", show );
+    }
+  }
+
+  /**
+   * Returns whether Y axis is displayed in chart.
+   *
+   * @return <code>true</code> if Y axis is displayed.
+   */
+  public boolean getShowYAxis() {
+    checkWidget();
+    return showYAxis;
+  }
+
+  /**
+   * Makes the X labels stagger at different distances from the axis so they are less likely to
+   * overlap. Default is <code>false</code>.
+   *
+   * @param staggerLabels <code>true</code> to display labels in staggered layout.
+   */
+  public void setStaggerLabels( boolean staggerLabels ) {
+    checkWidget();
+    if( this.staggerLabels != staggerLabels ) {
+      this.staggerLabels = staggerLabels;
+      setOption( "staggerLabels", staggerLabels );
+    }
+  }
+
+  /**
+   * Returns whether labels are displayed in staggered layout.
+   *
+   * @return <code>true</code> if labels are displayed in staggered layout.
+   */
+  public boolean getStaggerLabels() {
+    checkWidget();
+    return staggerLabels;
+  }
+
+  /**
    * Sets the data items to display. Later changes to this list won't be reflected. To change the
    * chart data, call this method with a new list of items.
    *
diff --git a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/DonutChart.java b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/DonutChart.java
new file mode 100644
index 0000000..6a633eb
--- /dev/null
+++ b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/DonutChart.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Ralf Sternberg - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.addons.chart.basic;
+
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Donut chart control based on nv.models.pieChart of nvd3 library.
+ */
+public class DonutChart extends PieChart {
+
+  private double cornerRadius = 0d;
+  private double donutRatio = 0.5d;
+  private double padAngle = 0d;
+  private String title = "";
+
+  /**
+   * Constructor for a donut chart.
+   *
+   * @param parent a composite control which will be the parent of the new instance (cannot be null)
+   * @param style the style of control to construct
+   */
+  public DonutChart( Composite parent, int style ) {
+    super( parent, style );
+    setOption( "donut", true );
+  }
+
+  /**
+   * The corner radius of the slices. Typically used together with padAngle. Default is 0.
+   *
+   * @param cornerRadius the corner radius
+   */
+  public void setCornerRadius( double cornerRadius ) {
+    checkWidget();
+    if( this.cornerRadius != cornerRadius ) {
+      this.cornerRadius = cornerRadius;
+      setOption( "cornerRadius", cornerRadius );
+    }
+  }
+
+  /**
+   * Returns the cornerRadius of the donut slices.
+   *
+   * @return the cornerRadius
+   */
+  public double getCornerRadius() {
+    checkWidget();
+    return cornerRadius;
+  }
+
+  /**
+   * Percent of pie radius to cut out of the middle to make the donut. It is multiplied by the outer
+   * radius to calculate the inner radius, thus it should be between 0 and 1. Default is 0.5.
+   *
+   * @param donutRatio the ratio of the cut-out middle
+   */
+  public void setDonutRatio( double donutRatio ) {
+    checkWidget();
+    if( this.donutRatio != donutRatio ) {
+      this.donutRatio = donutRatio;
+      setOption( "donutRatio", donutRatio );
+    }
+  }
+
+  /**
+   * Returns the donut ratio.
+   *
+   * @return the donut ratio
+   */
+  public double getDonutRatio() {
+    checkWidget();
+    return donutRatio;
+  }
+
+  /**
+   * Defines the spacing between slices as percentage of the chart. Default is 0.
+   *
+   * @param padAngle the padding angle between slices
+   */
+  public void setPadAngle( double padAngle ) {
+    checkWidget();
+    if( this.padAngle != padAngle ) {
+      this.padAngle = padAngle;
+      setOption( "padAngle", padAngle );
+    }
+  }
+
+  /**
+   * Returns the padding angle between slices.
+   *
+   * @return the padding angle between slices
+   */
+  public double getPadAngle() {
+    checkWidget();
+    return padAngle;
+  }
+
+  /**
+   * Text to include within the middle of the donut chart. Default is empty.
+   *
+   * @param title the donut title
+   */
+  public void setTitle( String title ) {
+    checkWidget();
+    if( title != null && !title.equals( this.title ) ) {
+      this.title = title;
+      setOption( "title", title );
+    }
+  }
+
+  /**
+   * Returns the donut title.
+   *
+   * @return the title
+   */
+  public String getTitle() {
+    checkWidget();
+    return title;
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/LineChart.java b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/LineChart.java
index 9bc183b..8b77a8b 100644
--- a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/LineChart.java
+++ b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/LineChart.java
@@ -30,10 +30,17 @@
  */
 public class LineChart extends NvChart {
 
-  private String xAxisLabel;
-  private String yAxisLabel;
-  private String xAxisFormat;
-  private String yAxisFormat;
+  private String xAxisLabel = "";
+  private String yAxisLabel = "";
+  private String xAxisFormat = "d";
+  private String yAxisFormat = "d";
+
+  private boolean interactive = true;
+  private String interpolate = "linear";
+  private boolean area;
+  private boolean useInteractiveGuideline;
+  private boolean useVoronoi = true;
+  private boolean padData = true;
 
   /**
    * Creates a new empty LineChart.
@@ -44,13 +51,13 @@
   }
 
   /**
-   * Sets the label to display on the x-axis.
+   * Sets the label to display on the x-axis. Default is empty.
    *
    * @param label the label for the x-axis
    */
   public void setXAxisLabel( String label ) {
     checkWidget();
-    if( this.xAxisLabel != label ) {
+    if( label != null && !label.equals( xAxisLabel ) ) {
       xAxisLabel = label;
       setOption( "xAxis.axisLabel", label );
     }
@@ -63,17 +70,17 @@
    */
   public String getXAxisLabel() {
     checkWidget();
-    return xAxisLabel != null ? xAxisLabel : "";
+    return xAxisLabel;
   }
 
   /**
-   * Sets the label to display on the y-axis.
+   * Sets the label to display on the y-axis. Default is empty.
    *
    * @param label the label for the y-axis
    */
   public void setYAxisLabel( String label ) {
     checkWidget();
-    if( this.yAxisLabel != label ) {
+    if( label != null && !label.equals( yAxisLabel ) ) {
       yAxisLabel = label;
       setOption( "yAxis.axisLabel", label );
     }
@@ -86,19 +93,20 @@
    */
   public String getYAxisLabel() {
     checkWidget();
-    return xAxisLabel != null ? xAxisLabel : "";
+    return yAxisLabel;
   }
 
   /**
    * Sets the format for the labels on the x-axis. The format string must be recognizable by the
    * <a href="https://github.com/mbostock/d3/wiki/Formatting#d3_format">d3.format()</a> function.
+   * Default is <code>d</code>.
    *
    * @see "https://github.com/mbostock/d3/wiki/Formatting#d3_format"
    * @param format a d3 format string for the labels of the x-axis
    */
   public void setXAxisFormat( String format ) {
     checkWidget();
-    if( this.xAxisFormat != format ) {
+    if( format != null && !format.equals( xAxisFormat ) ) {
       xAxisFormat = format;
       setOption( "xAxisFormat", format );
     }
@@ -117,13 +125,14 @@
   /**
    * Sets the format for the labels on the y-axis. The format string must be recognizable by the
    * <a href="https://github.com/mbostock/d3/wiki/Formatting#d3_format">d3.format()</a> function.
+   * Default is <code>d</code>.
    *
    * @see "https://github.com/mbostock/d3/wiki/Formatting#d3_format"
    * @param format a d3 format string for the labels of the y-axis
    */
   public void setYAxisFormat( String format ) {
     checkWidget();
-    if( this.yAxisFormat != format ) {
+    if( format != null && !format.equals( yAxisFormat ) ) {
       yAxisFormat = format;
       setOption( "yAxisFormat", format );
     }
@@ -140,6 +149,154 @@
   }
 
   /**
+   * A master flag for turning chart interaction on and off. This overrides all tooltip, voronoi,
+   * and guideline options. Default is <code>true</code>.
+   *
+   * @param interactive whether chart interaction is turned on
+   */
+  public void setInteractive( boolean interactive ) {
+    checkWidget();
+    if( this.interactive != interactive ) {
+      this.interactive = interactive;
+      setOption( "interactive", interactive );
+    }
+  }
+
+  /**
+   * Returns whether chart interaction is turned on.
+   *
+   * @return <code>true</code> if chart interaction is turned on
+   */
+  public boolean isInteractive() {
+    checkWidget();
+    return this.interactive;
+  }
+
+  /**
+   * Controls the line interpolation between points, see the
+   * <a href="https://github.com/mbostock/d3/wiki/SVG-Shapes#line_interpolate">D3 reference</a> for
+   * valid options. Default is <code>linear</code>.
+   *
+   * @see "https://github.com/mbostock/d3/wiki/SVG-Shapes#line_interpolate"
+   * @param interpolate the line interpolation function
+   */
+  public void setInterpolate( String interpolate ) {
+    checkWidget();
+    if( interpolate != null && !interpolate.equals( this.interpolate ) ) {
+      this.interpolate = interpolate;
+      setOption( "interpolate", interpolate );
+    }
+  }
+
+  /**
+   * Returns the line interpolation function.
+   *
+   * @return the line interpolation function
+   */
+  public String getInterpolate() {
+    checkWidget();
+    return interpolate;
+  }
+
+  /**
+   * Function to define if a line is a normal line or if it fills in the area. Notice the default
+   * gets the value from the line's definition in data. If a non-function is given, it the value is
+   * used for all lines. Default is <code>false</code>.
+   *
+   * @param area whether area below lines is filled.
+   */
+  public void setArea( boolean area ) {
+    checkWidget();
+    if( this.area != area ) {
+      this.area = area;
+      setOption( "isArea", area );
+    }
+  }
+
+  /**
+   * Returns whether area below lines is filled.
+   *
+   * @return <code>true</code> if area is filled below lines.
+   */
+  public boolean getArea() {
+    checkWidget();
+    return area;
+  }
+
+  /**
+   * Sets the chart to use a guideline and floating tooltip instead of requiring the user to hover
+   * over specific hotspots. Turning this on will set the 'interactive' and 'useVoronoi' options to
+   * false to avoid conflicting. Default is <code>false</code>.
+   *
+   * @param useInteractiveGuideline whether to use interactive guidelines
+   */
+  public void setUseInteractiveGuideline( boolean useInteractiveGuideline ) {
+    checkWidget();
+    if( this.useInteractiveGuideline != useInteractiveGuideline ) {
+      this.useInteractiveGuideline = useInteractiveGuideline;
+      setOption( "useInteractiveGuideline", useInteractiveGuideline );
+    }
+  }
+
+  /**
+   * Returns whether guidelines are interactive.
+   *
+   * @return <code>true</code> if interactive guidelines are used
+   */
+  public boolean getUseInteractiveGuideline() {
+    checkWidget();
+    return useInteractiveGuideline;
+  }
+
+  /**
+   * Use voronoi diagram to select nearest point to display tooltip instead of requiring a hover
+   * over the specific point itself. Setting this to <code>false</code> will also set clipVoronoi to
+   * <code>false</code>. Default is <code>true</code>.
+   *
+   * @param useVoronoi whether to determine nearest point for tooltips using voronoi diagram
+   */
+  public void setUseVoronoi( boolean useVoronoi ) {
+    checkWidget();
+    if( this.useVoronoi != useVoronoi ) {
+      this.useVoronoi = useVoronoi;
+      setOption( "useVoronoi", useVoronoi );
+    }
+  }
+
+  /**
+   * Returns whether to determine nearest point for tooltips using voronoi diagram.
+   *
+   * @return <code>true</code> if voronoi diagram is used to determine nearest point for tooltips
+   */
+  public boolean getUseVoronoi() {
+    checkWidget();
+    return useVoronoi;
+  }
+
+  /**
+   * Whether to pad the data. Default is <code>true</code>.
+   *
+   * @param padData <code>true</code> if data is padded.
+   */
+  public void setPadData( boolean padData ) {
+    checkWidget();
+    if( this.padData != padData ) {
+      this.padData = padData;
+      setOption( "padData", padData );
+    }
+  }
+
+  /**
+   * Returns whether to pad the data.
+   *
+   * @return <code>true</code> if data is padded
+   */
+  public boolean getPadData() {
+    checkWidget();
+    return padData;
+  }
+
+  /**
    * Sets the data items to display. Every item represents a separate line. Later changes to this
    * list won't be reflected. To change the chart data, call this method with a new list of items.
    *
diff --git a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/PieChart.java b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/PieChart.java
index cd116fa..22ba085 100644
--- a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/PieChart.java
+++ b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/basic/PieChart.java
@@ -31,7 +31,12 @@
 public class PieChart extends NvChart {
 
   private boolean showLabels = true;
-  private boolean donut;
+  private boolean labelsOutside;
+  private boolean growOnHover = true;
+  private boolean labelSunbeamLayout;
+  private double labelThreshold = 0.02d;
+  private String labelType = "key";
+  private String legendPosition = "top";
 
   /**
    * Creates a new empty Pie chart.
@@ -65,25 +70,146 @@
   }
 
   /**
-   * Sets whether this chart should be displayed as a donut chart. The default is
-   * <code>false</code>.
+   * Whether chart labels should be outside the slices instead of inside them. Default is
+   * <code>true</code>.
    *
-   * @param donut <code>true</code> to display as a donut chart
+   * @param labelsOutside <code>true</code> to show labels outside of slices
    */
-  public void setDonut( boolean donut ) {
-    if( this.donut != donut ) {
-      this.donut = donut;
-      setOption( "donut", donut );
+  public void setLabelsOutside( boolean labelsOutside ) {
+    checkWidget();
+    if( this.labelsOutside != labelsOutside ) {
+      this.labelsOutside = labelsOutside;
+      setOption( "labelsOutside", labelsOutside );
     }
   }
 
   /**
-   * Returns whether this chart is displayed as a donut chart.
+   * Returns whether labels are shown outside of slices.
    *
-   * @return <code>true</code> if displayed as a donut chart
+   * @return <code>true</code> if labels are shown outside of slices
    */
-  public boolean getDonut() {
-    return donut;
+  public boolean getLabelsOutside() {
+    checkWidget();
+    return labelsOutside;
+  }
+
+  /**
+   * Whether to increase slice radius on hover or not. Default is <code>true</code>.
+   *
+   * @param growOnHover <code>true</code> if slices should increase on hover
+   */
+  public void setGrowOnHover( boolean growOnHover ) {
+    checkWidget();
+    if( this.growOnHover != growOnHover ) {
+      this.growOnHover = growOnHover;
+      setOption( "growOnHover", growOnHover );
+    }
+  }
+
+  /**
+   * Returns whether to increase slice radius on hover.
+   *
+   * @return <code>true</code> if slices should increase on hover
+   */
+  public boolean getGrowOnHover() {
+    checkWidget();
+    return growOnHover;
+  }
+
+  /**
+   * Whether item labels are drawn in sunbeam layout instead of horizontally. Default is
+   * <code>false</code>.
+   *
+   * @param labelSunbeamLayout <code>true</code> if labels are drawn in sunbeam layout
+   */
+  public void setLabelSunbeamLayout( boolean labelSunbeamLayout ) {
+    checkWidget();
+    if( this.labelSunbeamLayout != labelSunbeamLayout ) {
+      this.labelSunbeamLayout = labelSunbeamLayout;
+      setOption( "labelSunbeamLayout", labelSunbeamLayout );
+    }
+  }
+
+  /**
+   * Returns whether labels are drawn in sunbeam layout or not.
+   *
+   * @return <code>true</code> if labels are drawn in sunbeam layout
+   */
+  public boolean getLabelSunbeamLayout() {
+    checkWidget();
+    return labelSunbeamLayout;
+  }
+
+  /**
+   * The slice threshold size (as percentage of the chart) to not display the label because it would
+   * be too small of a space. Default is 0.02, i.e. 2% of chart size.
+   *
+   * @param labelThreshold the threshold size
+   */
+  public void setLabelThreshold( double labelThreshold ) {
+    checkWidget();
+    if( this.labelThreshold != labelThreshold ) {
+      this.labelThreshold = labelThreshold;
+      setOption( "labelThreshold", labelThreshold );
+    }
+  }
+
+  /**
+   * Returns the slice threshold size for labels to be displayed.
+   *
+   * @return the label threshold size
+   */
+  public double getLabelThreshold() {
+    checkWidget();
+    return labelThreshold;
+  }
+
+  /**
+   * What kind of data to display for the slice labels. Valid options are <code>key</code>,
+   * <code>value</code>, or <code>percent</code>. Default is <code>key</code>.
+   *
+   * @param labelType the kind of data to be displayed as labels
+   */
+  public void setLabelType( String labelType ) {
+    checkWidget();
+    if( labelType != null && !labelType.equals( this.labelType ) ) {
+      this.labelType = labelType;
+      setOption( "labelType", labelType );
+    }
+  }
+
+  /**
+   * Returns the kind of data to be displayed as labels.
+   *
+   * @return the labelType the kind of data to be displayed as labels
+   */
+  public String getLabelType() {
+    checkWidget();
+    return labelType;
+  }
+
+  /**
+   * Position of the chart legend. Valid options are <code>top</code> or <code>right</code>. Default
+   * is <code>top</code>.
+   *
+   * @param legendPosition the position of the legend
+   */
+  public void setLegendPosition( String legendPosition ) {
+    checkWidget();
+    if( legendPosition != null && !legendPosition.equals( this.legendPosition ) ) {
+      this.legendPosition = legendPosition;
+      setOption( "legendPosition", legendPosition );
+    }
+  }
+
+  /**
+   * Returns the position of the chart legend.
+   *
+   * @return the position of the legend.
+   */
+  public String getLegendPosition() {
+    checkWidget();
+    return legendPosition;
   }
 
   /**
diff --git a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/internal/ColorUtil.java b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/internal/ColorUtil.java
index bd3db7c..b490ae5 100644
--- a/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/internal/ColorUtil.java
+++ b/bundles/org.eclipse.rap.addons.chart/src/org/eclipse/rap/addons/chart/internal/ColorUtil.java
@@ -10,11 +10,20 @@
  ******************************************************************************/
 package org.eclipse.rap.addons.chart.internal;
 
+import org.eclipse.rap.json.JsonArray;
 import org.eclipse.swt.graphics.RGB;
 
 
 public class ColorUtil {
 
+  public static JsonArray toJson( RGB[] colors ) {
+    JsonArray colorSequence = new JsonArray();
+    for( RGB color : colors ) {
+      colorSequence.add( toHtmlString( color ) );
+    }
+    return colorSequence;
+  }
+
   public static String toHtmlString( RGB color ) {
     StringBuilder result = new StringBuilder( 7 ).append( '#' );
     append2x( result, color.red );
diff --git a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/BarChartSnippet.java b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/BarChartSnippet.java
index 39e0d30..959b304 100644
--- a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/BarChartSnippet.java
+++ b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/BarChartSnippet.java
@@ -10,7 +10,7 @@
  ******************************************************************************/
 package org.eclipse.rap.addons.chart.demo;
 
-import static org.eclipse.rap.addons.chart.demo.Colors.CAT10_COLORS;
+import static org.eclipse.rap.addons.chart.Colors.CATEGORY_10;
 
 import org.eclipse.rap.addons.chart.basic.BarChart;
 import org.eclipse.rap.addons.chart.basic.DataItem;
@@ -64,11 +64,11 @@
 
   private static DataItem[] createItems() {
     return new DataItem[] {
-      new DataItem( Math.random() * 100, "Item 1", CAT10_COLORS[ 0 ] ),
-      new DataItem( Math.random() * 100, "Item 2", CAT10_COLORS[ 1 ] ),
-      new DataItem( Math.random() * 100, "Item 3", CAT10_COLORS[ 2 ] ),
-      new DataItem( Math.random() * 100, "Item 4", CAT10_COLORS[ 3 ] ),
-      new DataItem( Math.random() * 100, "Item 5", CAT10_COLORS[ 4 ] )
+      new DataItem( Math.random() * 100, "Item 1", CATEGORY_10[ 0 ] ),
+      new DataItem( Math.random() * 100, "Item 2", CATEGORY_10[ 1 ] ),
+      new DataItem( Math.random() * 100, "Item 3", CATEGORY_10[ 2 ] ),
+      new DataItem( Math.random() * 100, "Item 4", CATEGORY_10[ 3 ] ),
+      new DataItem( Math.random() * 100, "Item 5", CATEGORY_10[ 4 ] )
     };
   }
 
diff --git a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/ChartSnippetPage.java b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/ChartSnippetPage.java
index 50c1c43..dbfccd1 100644
--- a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/ChartSnippetPage.java
+++ b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/ChartSnippetPage.java
@@ -26,6 +26,7 @@
     createBarChart( parent );
     createPieChart( parent );
     createLineChart( parent );
+    createDonutChart( parent );
   }
 
   private static void createBarChart( Composite parent ) {
@@ -46,10 +47,18 @@
 
   private static void createLineChart( Composite parent ) {
     Composite composite = new Composite( parent, SWT.NONE );
-    composite.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true, 2, 1 ) );
+    composite.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
     composite.setBackground( new Color( parent.getDisplay(), 250, 250, 250 ) );
     composite.setBackgroundMode( SWT.INHERIT_DEFAULT );
     new LineChartSnippet().createContents( composite );
   }
 
+  private static void createDonutChart( Composite parent ) {
+    Composite composite = new Composite( parent, SWT.NONE );
+    composite.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
+    composite.setBackground( new Color( parent.getDisplay(), 250, 250, 250 ) );
+    composite.setBackgroundMode( SWT.INHERIT_DEFAULT );
+    new DonutChartSnippet().createContents( composite );
+  }
+
 }
diff --git a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/Colors.java b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/Colors.java
deleted file mode 100644
index ec9648b..0000000
--- a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/Colors.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 EclipseSource and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Ralf Sternberg - initial API and implementation
- ******************************************************************************/
-package org.eclipse.rap.addons.chart.demo;
-
-import org.eclipse.swt.graphics.RGB;
-
-
-public class Colors {
-
-  public static final RGB[] CAT10_COLORS = {
-    new RGB( 0x1f, 0x77, 0xb4 ),
-    new RGB( 0xff, 0x7f, 0x0e ),
-    new RGB( 0x2c, 0xa0, 0x2c ),
-    new RGB( 0xd6, 0x27, 0x28 ),
-    new RGB( 0x94, 0x67, 0xbd ),
-    new RGB( 0x8c, 0x56, 0x4b ),
-    new RGB( 0xe3, 0x77, 0xc2 ),
-    new RGB( 0x7f, 0x7f, 0x7f ),
-    new RGB( 0xbc, 0xbd, 0x22 ),
-    new RGB( 0x17, 0xbe, 0xcf )
-  };
-
-}
diff --git a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/DonutChartSnippet.java b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/DonutChartSnippet.java
new file mode 100644
index 0000000..2c071ae
--- /dev/null
+++ b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/DonutChartSnippet.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Ralf Sternberg - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.addons.chart.demo;
+
+
+import static org.eclipse.rap.addons.chart.Colors.CATEGORY_10;
+
+import org.eclipse.rap.addons.chart.basic.DataItem;
+import org.eclipse.rap.addons.chart.basic.DonutChart;
+import org.eclipse.rap.rwt.application.AbstractEntryPoint;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+
+public class DonutChartSnippet extends AbstractEntryPoint {
+
+  private DonutChart donutChart;
+
+  @Override
+  public void createContents( Composite parent ) {
+    parent.setLayout( new GridLayout() );
+    createDonutChart( parent );
+    createUpdateButton( parent );
+    update();
+  }
+
+  private void createDonutChart( Composite parent ) {
+    donutChart = new DonutChart( parent, SWT.NONE );
+    donutChart.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
+    donutChart.addListener( SWT.Selection, new Listener() {
+      @Override
+      public void handleEvent( Event event ) {
+        System.out.println( "Selected donut item #" + event.index );
+      }
+    } );
+  }
+
+  private void createUpdateButton( Composite parent ) {
+    Button button = new Button( parent, SWT.PUSH );
+    button.setText( "Change data" );
+    button.addListener( SWT.Selection, new Listener() {
+      @Override
+      public void handleEvent( Event event ) {
+        update();
+      }
+    } );
+  }
+
+  private void update() {
+    donutChart.setItems( createItems() );
+  }
+
+  private static DataItem[] createItems() {
+    return new DataItem[] {
+      new DataItem( Math.random() * 100, "Item 1", CATEGORY_10[ 0 ] ),
+      new DataItem( Math.random() * 100, "Item 2", CATEGORY_10[ 1 ] ),
+      new DataItem( Math.random() * 100, "Item 3", CATEGORY_10[ 2 ] ),
+      new DataItem( Math.random() * 100, "Item 4", CATEGORY_10[ 3 ] ),
+      new DataItem( Math.random() * 100, "Item 5", CATEGORY_10[ 4 ] )
+    };
+  }
+
+}
diff --git a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/LineChartSnippet.java b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/LineChartSnippet.java
index 9627e0b..5082350 100644
--- a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/LineChartSnippet.java
+++ b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/LineChartSnippet.java
@@ -10,11 +10,11 @@
  ******************************************************************************/
 package org.eclipse.rap.addons.chart.demo;
 
-import static org.eclipse.rap.addons.chart.demo.Colors.CAT10_COLORS;
+import static org.eclipse.rap.addons.chart.Colors.CATEGORY_10;
 
-import org.eclipse.rap.addons.chart.basic.LineChart;
 import org.eclipse.rap.addons.chart.basic.DataGroup;
 import org.eclipse.rap.addons.chart.basic.DataItem;
+import org.eclipse.rap.addons.chart.basic.LineChart;
 import org.eclipse.rap.rwt.application.AbstractEntryPoint;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.GridData;
@@ -68,8 +68,8 @@
 
   private static DataGroup[] createItems() {
     return new DataGroup[] {
-      new DataGroup( createRandomPoints(), "Series 1", CAT10_COLORS[ 0 ] ),
-      new DataGroup( createRandomPoints(), "Series 2", CAT10_COLORS[ 1 ] )
+      new DataGroup( createRandomPoints(), "Series 1", CATEGORY_10[ 0 ] ),
+      new DataGroup( createRandomPoints(), "Series 2", CATEGORY_10[ 1 ] )
     };
   }
 
diff --git a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/PieChartSnippet.java b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/PieChartSnippet.java
index 5ffcf27..be53459 100644
--- a/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/PieChartSnippet.java
+++ b/examples/org.eclipse.rap.addons.chart.demo/src/org/eclipse/rap/addons/chart/demo/PieChartSnippet.java
@@ -11,10 +11,9 @@
 package org.eclipse.rap.addons.chart.demo;
 
 
+import static org.eclipse.rap.addons.chart.Colors.CATEGORY_10;
+
 import org.eclipse.rap.addons.chart.basic.DataItem;
-
-import static org.eclipse.rap.addons.chart.demo.Colors.CAT10_COLORS;
-
 import org.eclipse.rap.addons.chart.basic.PieChart;
 import org.eclipse.rap.rwt.application.AbstractEntryPoint;
 import org.eclipse.swt.SWT;
@@ -41,7 +40,6 @@
   private void createPieChart( Composite parent ) {
     pieChart = new PieChart( parent, SWT.NONE );
     pieChart.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
-    pieChart.setDonut( true );
     pieChart.addListener( SWT.Selection, new Listener() {
       @Override
       public void handleEvent( Event event ) {
@@ -67,11 +65,11 @@
 
   private static DataItem[] createItems() {
     return new DataItem[] {
-      new DataItem( Math.random() * 100, "Item 1", CAT10_COLORS[ 0 ] ),
-      new DataItem( Math.random() * 100, "Item 2", CAT10_COLORS[ 1 ] ),
-      new DataItem( Math.random() * 100, "Item 3", CAT10_COLORS[ 2 ] ),
-      new DataItem( Math.random() * 100, "Item 4", CAT10_COLORS[ 3 ] ),
-      new DataItem( Math.random() * 100, "Item 5", CAT10_COLORS[ 4 ] )
+      new DataItem( Math.random() * 100, "Item 1", CATEGORY_10[ 0 ] ),
+      new DataItem( Math.random() * 100, "Item 2", CATEGORY_10[ 1 ] ),
+      new DataItem( Math.random() * 100, "Item 3", CATEGORY_10[ 2 ] ),
+      new DataItem( Math.random() * 100, "Item 4", CATEGORY_10[ 3 ] ),
+      new DataItem( Math.random() * 100, "Item 5", CATEGORY_10[ 4 ] )
     };
   }
 
diff --git a/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/BarChart_Test.java b/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/BarChart_Test.java
index 434982c..75894e0 100644
--- a/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/BarChart_Test.java
+++ b/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/BarChart_Test.java
@@ -10,10 +10,16 @@
  ******************************************************************************/
 package org.eclipse.rap.addons.chart.basic;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import org.eclipse.rap.json.JsonObject;
 import org.eclipse.rap.json.JsonValue;
@@ -28,11 +34,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
 
 @SuppressWarnings( "restriction" )
 public class BarChart_Test {
@@ -70,7 +71,7 @@
     assertTrue( chart.getShowValues() );
   }
 
-  @Test
+ @Test
   public void testSetShowValues_changesValue() {
     chart.setShowValues( false );
 
@@ -79,17 +80,122 @@
 
   @Test
   public void testSetShowValues_isRendered() {
-    reset( remoteObject );
-
     chart.setShowValues( false );
 
     verify( remoteObject ).call( "setOptions", new JsonObject().add( "showValues", false ) );
   }
 
   @Test
-  public void testSetItems() {
-    reset( remoteObject );
+  public void testGetShowXAxis_defaultsToTrue() {
+    assertTrue( chart.getShowXAxis() );
+  }
 
+  @Test
+  public void testSetShowXAxis_changesValue() {
+    chart.setShowXAxis( false );
+
+    assertFalse( chart.getShowXAxis() );
+  }
+
+  @Test
+  public void testSetShowXAxis_isRendered() {
+    chart.setShowXAxis( false );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "showXAxis", false ) );
+  }
+
+  @Test
+  public void testGetShowYAxis_defaultsToTrue() {
+    assertTrue( chart.getShowYAxis() );
+  }
+
+  @Test
+  public void testSetShowYAxis_changesValue() {
+    chart.setShowYAxis( false );
+
+    assertFalse( chart.getShowYAxis() );
+  }
+
+  @Test
+  public void testSetShowYAxis_isRendered() {
+    chart.setShowYAxis( false );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "showYAxis", false ) );
+  }
+
+  @Test
+  public void testGetXAxisLabel_hasDefault() {
+    assertEquals( "", chart.getXAxisLabel() );
+  }
+
+  @Test
+  public void testSetXAxisLabel_changesValue() {
+    chart.setXAxisLabel( "foo" );
+
+    assertEquals( "foo", chart.getXAxisLabel() );
+  }
+
+  @Test
+  public void testSetXAxisLabel_isRendered() {
+    chart.setXAxisLabel( "foo" );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "xAxis.axisLabel", "foo" ) );
+  }
+
+  @Test
+  public void testSetXAxisLabel_notRenderedIfUnchanged() {
+    chart.setXAxisLabel( chart.getXAxisLabel() );
+
+    verify( remoteObject, times( 0 ) ).set( eq( "barWidth" ), anyInt() );
+  }
+
+  @Test
+  public void testGetYAxisLabel_hasDefault() {
+    assertEquals( "", chart.getYAxisLabel() );
+  }
+
+  @Test
+  public void testSetYAxisLabel_changesValue() {
+    chart.setYAxisLabel( "foo" );
+
+    assertEquals( "foo", chart.getYAxisLabel() );
+  }
+
+  @Test
+  public void testSetYAxisLabel_isRendered() {
+    chart.setYAxisLabel( "foo" );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "yAxis.axisLabel", "foo" ) );
+  }
+
+  @Test
+  public void testSetYAxisLabel_notRenderedIfUnchanged() {
+    chart.setYAxisLabel( chart.getYAxisLabel() );
+
+    verify( remoteObject, times( 0 ) ).set( eq( "barWidth" ), anyInt() );
+  }
+
+  @Test
+  public void testGetStaggerLabels_defaultsToFalse() {
+    assertFalse( chart.getStaggerLabels() );
+  }
+
+  @Test
+  public void testSetStaggerLabels_changesValue() {
+    chart.setStaggerLabels( true );
+
+    assertTrue( chart.getStaggerLabels() );
+  }
+
+  @Test
+  public void testSetStaggerLabels_isRendered() {
+    chart.setStaggerLabels( true );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "staggerLabels", true ) );
+  }
+
+ @Test
+  public void testSetItems() {
     chart.setItems( new DataItem( 23, "foo" ), new DataItem( 42, "bar" ) );
 
     String expected = "[ { \"values\": [ { \"value\": 23, \"label\": \"foo\" },"
diff --git a/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/DonutChart_Test.java b/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/DonutChart_Test.java
new file mode 100644
index 0000000..ef4d3fa
--- /dev/null
+++ b/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/DonutChart_Test.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Ralf Sternberg - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.addons.chart.basic;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.json.JsonValue;
+import org.eclipse.rap.rwt.internal.remote.ConnectionImpl;
+import org.eclipse.rap.rwt.remote.Connection;
+import org.eclipse.rap.rwt.remote.RemoteObject;
+import org.eclipse.rap.rwt.testfixture.TestContext;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+
+@SuppressWarnings( "restriction" )
+public class DonutChart_Test {
+
+  private Display display;
+  private Shell shell;
+  private RemoteObject remoteObject;
+  private Connection connection;
+  private DonutChart chart;
+
+  @Rule
+  public TestContext context = new TestContext();
+
+  @Before
+  public void setUp() {
+    display = new Display();
+    shell = new Shell( display );
+    remoteObject = mock( RemoteObject.class );
+    connection = fakeConnection( remoteObject );
+    chart = new DonutChart( shell, SWT.NONE );
+  }
+
+  @Test
+  public void testCreate_createsRemoteObject() {
+    verify( connection ).createRemoteObject( eq( "rwt.chart.Chart" ) );
+  }
+
+  @Test
+  public void testCreate_setsRenderer() {
+    verify( remoteObject ).set( "renderer", "nv-pie" );
+  }
+
+  @Test
+  public void testGetCornerRadius_hasDefault() {
+    assertEquals( 0.0d, chart.getCornerRadius(), 0.0d );
+  }
+
+  @Test
+  public void testSetCornerRadius_changesValue() {
+    chart.setCornerRadius( 0.2d );
+
+    assertEquals( 0.2d, chart.getCornerRadius(), 0.0d );
+  }
+
+  @Test
+  public void testSetCornerRadius_isRendered() {
+    chart.setCornerRadius( 0.2d );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "cornerRadius", 0.2d ) );
+  }
+
+  @Test
+  public void testGetDonutRatio_hasDefault() {
+    assertEquals( 0.5d, chart.getDonutRatio(), 0.0d );
+  }
+
+  @Test
+  public void testSetDonutRatio_changesValue() {
+    chart.setDonutRatio( 0.2d );
+
+    assertEquals( 0.2d, chart.getDonutRatio(), 0.0d );
+  }
+
+  @Test
+  public void testSetDonutRatio_isRendered() {
+    chart.setDonutRatio( 0.2d );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "donutRatio", 0.2d ) );
+  }
+
+  @Test
+  public void testGetPadAngle_hasDefault() {
+    assertEquals( 0.0d, chart.getPadAngle(), 0.0d );
+  }
+
+  @Test
+  public void testSetPadAngle_changesValue() {
+    chart.setPadAngle( 0.2d );
+
+    assertEquals( 0.2d, chart.getPadAngle(), 0.0d );
+  }
+
+  @Test
+  public void testSetPadAngle_isRendered() {
+    chart.setPadAngle( 0.2d );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "padAngle", 0.2d ) );
+  }
+
+  @Test
+  public void testGetTitle_hasDefault() {
+    assertEquals( "", chart.getTitle() );
+  }
+
+  @Test
+  public void testSetTitle_changesValue() {
+    chart.setTitle( "foo" );
+
+    assertEquals( "foo", chart.getTitle() );
+  }
+
+  @Test
+  public void testSetTitle_isRendered() {
+    chart.setTitle( "foo" );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "title", "foo" ) );
+  }
+
+  @Test
+  public void testSetItems() {
+    chart.setItems( new DataItem( 23, "foo" ), new DataItem( 42, "bar" ) );
+
+    String expected = "[{ \"value\": 23, \"label\": \"foo\" },"
+                     + "{ \"value\": 42, \"label\": \"bar\" }]";
+    verify( remoteObject ).set( "items", JsonValue.readFrom( expected ) );
+  }
+
+  private Connection fakeConnection( RemoteObject remoteObject ) {
+    ConnectionImpl connection = mock( ConnectionImpl.class );
+    when( connection.createRemoteObject( anyString() ) ).thenReturn( remoteObject );
+    when( connection.createServiceObject( anyString() ) ).thenReturn( mock( RemoteObject.class ) );
+    context.replaceConnection( connection );
+    return connection;
+  }
+
+}
diff --git a/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/LineChart_Test.java b/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/LineChart_Test.java
index 22b74d0..1da8ce8 100644
--- a/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/LineChart_Test.java
+++ b/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/LineChart_Test.java
@@ -10,10 +10,16 @@
  ******************************************************************************/
 package org.eclipse.rap.addons.chart.basic;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import org.eclipse.rap.json.JsonObject;
 import org.eclipse.rap.json.JsonValue;
@@ -29,12 +35,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
 
 @SuppressWarnings( "restriction" )
 public class LineChart_Test {
@@ -95,8 +95,6 @@
 
   @Test
   public void testSetXAxisLabel_isRendered() {
-    reset( remoteObject );
-
     chart.setXAxisLabel( "foo" );
 
     verify( remoteObject ).call( "setOptions", new JsonObject().add( "xAxis.axisLabel", "foo" ) );
@@ -132,11 +130,9 @@
 
   @Test
   public void testSetXAxisFormat_isRendered() {
-    reset( remoteObject );
+    chart.setXAxisFormat( "x" );
 
-    chart.setXAxisFormat( "d" );
-
-    verify( remoteObject ).call( "setOptions", new JsonObject().add( "xAxisFormat", "d" ) );
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "xAxisFormat", "x" ) );
   }
 
   @Test
@@ -147,9 +143,121 @@
   }
 
   @Test
-  public void testSetItems() {
-    reset( remoteObject );
+  public void testIsInteractive_defaultsToTrue() {
+    assertTrue( chart.isInteractive() );
+  }
 
+  @Test
+  public void testSetInteractive_changesValue() {
+    chart.setInteractive( false );
+
+    assertFalse( chart.isInteractive() );
+  }
+
+  @Test
+  public void testSetInteractive_isRendered() {
+    chart.setInteractive( false );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "interactive", false ) );
+  }
+
+  @Test
+  public void testGetInterpolate_hasDefault() {
+    assertEquals( "linear", chart.getInterpolate() );
+  }
+
+  @Test
+  public void testSetInterpolate_changesValue() {
+    chart.setInterpolate( "foo" );
+
+    assertEquals( "foo", chart.getInterpolate() );
+  }
+
+  @Test
+  public void testSetInterpolate_isRendered() {
+    chart.setInterpolate( "foo" );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "interpolate", "foo" ) );
+  }
+
+  @Test
+  public void testGetArea_defaultsToFalse() {
+    assertFalse( chart.getArea() );
+  }
+
+  @Test
+  public void testSetArea_changesValue() {
+    chart.setArea( true );
+
+    assertTrue( chart.getArea() );
+  }
+
+  @Test
+  public void testSetArea_isRendered() {
+    chart.setArea( true );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "isArea", true ) );
+  }
+
+  @Test
+  public void testGetUseInteractiveGuideline_defaultsToFalse() {
+    assertFalse( chart.getUseInteractiveGuideline() );
+  }
+
+  @Test
+  public void testSetUseInteractiveGuideline_changesValue() {
+    chart.setUseInteractiveGuideline( true );
+
+    assertTrue( chart.getUseInteractiveGuideline() );
+  }
+
+  @Test
+  public void testSetUseInteractiveGuideline_isRendered() {
+    chart.setUseInteractiveGuideline( true );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "useInteractiveGuideline", true ) );
+  }
+
+  @Test
+  public void testGetUseVoronoi_defaultsToTrue() {
+    assertTrue( chart.getUseVoronoi() );
+  }
+
+  @Test
+  public void testSetUseVoronoi_changesValue() {
+    chart.setUseVoronoi( false );
+
+    assertFalse( chart.getUseVoronoi() );
+  }
+
+  @Test
+  public void testSetUseVoronoi_isRendered() {
+    chart.setUseVoronoi( false );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "useVoronoi", false ) );
+  }
+
+  @Test
+  public void testGetPadData_defaultsToTrue() {
+    assertTrue( chart.getPadData() );
+  }
+
+  @Test
+  public void testSetPadData_changesValue() {
+    chart.setPadData( false );
+
+    assertFalse( chart.getPadData() );
+  }
+
+  @Test
+  public void testSetPadData_isRendered() {
+    chart.setPadData( false );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "padData", false ) );
+  }
+
+  @Test
+  public void testSetItems() {
     chart.setItems( new DataGroup( new DataItem2D[] { new DataItem2D( 1, 2 ),
                                                       new DataItem2D( 3, 4 ) }, "foo" ),
                     new DataGroup( new DataItem2D[] { new DataItem2D( 2, 4 ),
diff --git a/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/PieChart_Test.java b/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/PieChart_Test.java
index 9e30137..3aec619 100644
--- a/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/PieChart_Test.java
+++ b/tests/org.eclipse.rap.addons.chart.test/src/org/eclipse/rap/addons/chart/basic/PieChart_Test.java
@@ -10,10 +10,14 @@
  ******************************************************************************/
 package org.eclipse.rap.addons.chart.basic;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import org.eclipse.rap.json.JsonObject;
 import org.eclipse.rap.json.JsonValue;
@@ -28,11 +32,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
 
 @SuppressWarnings( "restriction" )
 public class PieChart_Test {
@@ -79,38 +78,127 @@
 
   @Test
   public void testSetShowLabels_isRendered() {
-    reset( remoteObject );
-
     chart.setShowLabels( false );
 
     verify( remoteObject ).call( "setOptions", new JsonObject().add( "showLabels", false ) );
   }
 
   @Test
-  public void testDonut_defaultValue() {
-    assertFalse( chart.getDonut() );
+  public void testGetLabelsOutside_defaultsToFalse() {
+    assertFalse( chart.getLabelsOutside() );
   }
 
   @Test
-  public void testDonut_changeValue() {
-    chart.setDonut( true );
+  public void testSetLabelsOutside_changesValue() {
+    chart.setLabelsOutside( true );
 
-    assertTrue( chart.getDonut() );
+    assertTrue( chart.getLabelsOutside() );
   }
 
   @Test
-  public void testDonut_isRendered() {
-    reset( remoteObject );
+  public void testSetLabelsOutside_isRendered() {
+    chart.setLabelsOutside( true );
 
-    chart.setDonut( true );
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "labelsOutside", true ) );
+  }
 
-    verify( remoteObject ).call( "setOptions", new JsonObject().add( "donut", true ) );
+  @Test
+  public void testGetGrowOnHover_defaultsToTrue() {
+    assertTrue( chart.getGrowOnHover() );
+  }
+
+  @Test
+  public void testSetGrowOnHover_changesValue() {
+    chart.setGrowOnHover( false );
+
+    assertFalse( chart.getGrowOnHover() );
+  }
+
+  @Test
+  public void testSetGrowOnHover_isRendered() {
+    chart.setGrowOnHover( false );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "growOnHover", false ) );
+  }
+
+  @Test
+  public void testGetLabelSunbeamLayout_defaultsToFalse() {
+    assertFalse( chart.getLabelSunbeamLayout() );
+  }
+
+  @Test
+  public void testSetLabelSunbeamLayout_changesValue() {
+    chart.setLabelSunbeamLayout( true );
+
+    assertTrue( chart.getLabelSunbeamLayout() );
+  }
+
+  @Test
+  public void testSetLabelSunbeamLayout_isRendered() {
+    chart.setLabelSunbeamLayout( true );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "labelSunbeamLayout", true ) );
+  }
+
+  @Test
+  public void testGetLabelThreshold_hasDefault() {
+    assertEquals( 0.02D, chart.getLabelThreshold(), 0.0 );
+  }
+
+  @Test
+  public void testSetLabelThreshold_changesValue() {
+    chart.setLabelThreshold( 0.0 );
+
+    assertEquals( 0.0, chart.getLabelThreshold(), 0.0 );
+  }
+
+  @Test
+  public void testSetLabelThreshold_isRendered() {
+    chart.setLabelThreshold( 0.0 );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "labelThreshold", 0.0 ) );
+  }
+
+  @Test
+  public void testGetLabelType_hasDefault() {
+    assertEquals( "key", chart.getLabelType() );
+  }
+
+  @Test
+  public void testSetLabelType_changesValue() {
+    chart.setLabelType( "foo" );
+
+    assertEquals( "foo", chart.getLabelType() );
+  }
+
+  @Test
+  public void testSetLabelType_isRendered() {
+    chart.setLabelType( "foo" );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "labelType", "foo" ) );
+  }
+
+  @Test
+  public void testGetLegendPosition_hasDefault() {
+    assertEquals( "top", chart.getLegendPosition() );
+  }
+
+  @Test
+  public void testSetLegendPosition_changesValue() {
+    chart.setLegendPosition( "foo" );
+
+    assertEquals( "foo", chart.getLegendPosition() );
+  }
+
+  @Test
+  public void testSetLegendPosition_isRendered() {
+    chart.setLegendPosition( "foo" );
+
+    verify( remoteObject ).call( "setOptions", new JsonObject().add( "legendPosition", "foo" ) );
   }
 
   @Test
   public void testSetItems() {
-    reset( remoteObject );
-
     chart.setItems( new DataItem( 23, "foo" ), new DataItem( 42, "bar" ) );
 
     String expected = "[{ \"value\": 23, \"label\": \"foo\" },"