changeset 1439:dcc106432347

fix RT-23057 PieChart draws garbage when at min size
author Paru Somashekar <paru.somashekar@oracle.com>
date Thu, 12 Jul 2012 15:53:03 -0700
parents 32a2ac15cc0e
children 74b5a4b24935
files javafx-ui-charts/src/javafx/scene/chart/Chart.java javafx-ui-charts/src/javafx/scene/chart/PieChart.java
diffstat 2 files changed, 100 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-charts/src/javafx/scene/chart/Chart.java	Thu Jul 12 15:34:03 2012 -0700
+++ b/javafx-ui-charts/src/javafx/scene/chart/Chart.java	Thu Jul 12 15:53:03 2012 -0700
@@ -62,6 +62,9 @@
 
     // -------------- PRIVATE FIELDS -----------------------------------------------------------------------------------
 
+    private static final int MIN_WIDTH_TO_LEAVE_FOR_CHART_CONTENT = 200;
+    private static final int MIN_HEIGHT_TO_LEAVE_FOR_CHART_CONTENT = 150;
+
     /** Title Label */
     private final Label titleLabel = new Label();
     /**
@@ -169,12 +172,7 @@
      */
     private final BooleanProperty legendVisible = new StyleableBooleanProperty(true) {
         @Override protected void invalidated() {
-            boolean vis = get();
-            Node legend = getLegend();
-            if(legend != null) {
-                legend.setVisible(vis);
-                requestLayout();
-            }
+            requestLayout();
         }
             
         @Override
@@ -340,28 +338,48 @@
         }
         // layout legend
         final Node legend = getLegend();
-        if (legend != null && isLegendVisible()) {
-            if (getLegendSide().equals(Side.TOP)) {
-                final double legendHeight = snapSize(legend.prefHeight(width-left-right));
-                final double legendWidth = snapSize(legend.prefWidth(-1));
-                legend.resizeRelocate(left + (((width - left - right)-legendWidth)/2), top, legendWidth, legendHeight);
-                top += legendHeight;
-            } else if (getLegendSide().equals(Side.BOTTOM)) {
-                final double legendHeight = snapSize(legend.prefHeight(width-left-right));
-                final double legendWidth = snapSize(legend.prefWidth(-1));
-                legend.resizeRelocate(left + (((width - left - right)-legendWidth)/2), height-bottom-legendHeight, legendWidth, legendHeight);
-                bottom += legendHeight;
-            } else if (getLegendSide().equals(Side.LEFT)) {
-                final double legendWidth = snapSize(legend.prefWidth(height-top-bottom));
-                final double legendHeight = snapSize(legend.prefHeight(-1));
-                legend.resizeRelocate(left,top +(((height-top-bottom)-legendHeight)/2),legendWidth,legendHeight);
-                left += legendWidth;
-            } else if (getLegendSide().equals(Side.RIGHT)) {
-                final double legendWidth = snapSize(legend.prefWidth(height-top-bottom));
-                final double legendHeight = snapSize(legend.prefHeight(-1));
-                legend.resizeRelocate(width-right-legendWidth,top +(((height-top-bottom)-legendHeight)/2),legendWidth,legendHeight);
-                right += legendWidth;
+        if (legend != null) {
+            boolean shouldShowLegend = isLegendVisible();
+            if (shouldShowLegend) {
+                if (getLegendSide().equals(Side.TOP)) {
+                    final double legendHeight = snapSize(legend.prefHeight(width-left-right));
+                    final double legendWidth = snapSize(legend.prefWidth(-1));
+                    legend.resizeRelocate(left + (((width - left - right)-legendWidth)/2), top, legendWidth, legendHeight);
+                    if ((height - bottom - top - legendHeight) < MIN_HEIGHT_TO_LEAVE_FOR_CHART_CONTENT) {
+                        shouldShowLegend = false;
+                    } else {
+                        top += legendHeight;
+                    }
+                } else if (getLegendSide().equals(Side.BOTTOM)) {
+                    final double legendHeight = snapSize(legend.prefHeight(width-left-right));
+                    final double legendWidth = snapSize(legend.prefWidth(-1));
+                    legend.resizeRelocate(left + (((width - left - right)-legendWidth)/2), height-bottom-legendHeight, legendWidth, legendHeight);
+                    if ((height - bottom - top - legendHeight) < MIN_HEIGHT_TO_LEAVE_FOR_CHART_CONTENT) {
+                        shouldShowLegend = false;
+                    } else {
+                        bottom += legendHeight;
+                    }
+                } else if (getLegendSide().equals(Side.LEFT)) {
+                    final double legendWidth = snapSize(legend.prefWidth(height-top-bottom));
+                    final double legendHeight = snapSize(legend.prefHeight(-1));
+                    legend.resizeRelocate(left,top +(((height-top-bottom)-legendHeight)/2),legendWidth,legendHeight);
+                    if ((width - left - right - legendWidth) < MIN_WIDTH_TO_LEAVE_FOR_CHART_CONTENT) {
+                        shouldShowLegend = false;
+                    } else {
+                        left += legendWidth;
+                    }
+                } else if (getLegendSide().equals(Side.RIGHT)) {
+                    final double legendWidth = snapSize(legend.prefWidth(height-top-bottom));
+                    final double legendHeight = snapSize(legend.prefHeight(-1));
+                    legend.resizeRelocate(width-right-legendWidth,top +(((height-top-bottom)-legendHeight)/2),legendWidth,legendHeight);
+                    if ((width - left - right - legendWidth) < MIN_WIDTH_TO_LEAVE_FOR_CHART_CONTENT) {
+                        shouldShowLegend = false;
+                    } else {
+                        right += legendWidth;
+                    }
+                }
             }
+            legend.setVisible(shouldShowLegend);
         }
         // whats left is for the chart content
         chartContent.resizeRelocate(left,top,width-left-right,height-top-bottom);
--- a/javafx-ui-charts/src/javafx/scene/chart/PieChart.java	Thu Jul 12 15:34:03 2012 -0700
+++ b/javafx-ui-charts/src/javafx/scene/chart/PieChart.java	Thu Jul 12 15:53:03 2012 -0700
@@ -24,6 +24,7 @@
  */
 package javafx.scene.chart;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -52,14 +53,10 @@
 import javafx.geometry.Side;
 import javafx.scene.Node;
 import javafx.scene.layout.Region;
-import javafx.scene.shape.Arc;
-import javafx.scene.shape.ArcTo;
-import javafx.scene.shape.ArcType;
-import javafx.scene.shape.ClosePath;
-import javafx.scene.shape.LineTo;
-import javafx.scene.shape.MoveTo;
-import javafx.scene.shape.Path;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.*;
 import javafx.scene.text.Text;
+import javafx.scene.transform.Scale;
 import javafx.util.Duration;
 
 import com.sun.javafx.charts.Legend;
@@ -84,6 +81,7 @@
 public class PieChart extends Chart {
 
     // -------------- PRIVATE FIELDS -----------------------------------------------------------------------------------
+    private static final int MIN_PIE_RADIUS = 25;
     private int defaultColorIndex = 0;
     private static final double LABEL_TICK_GAP = 6;
     private static final double LABEL_BALL_RADIUS = 2;
@@ -474,7 +472,9 @@
         double[] labelsX = null;
         double[] labelsY = null;
         double[] labelAngles = null;
+        double labelScale = 1;
         ArrayList<LabelLayoutInfo> fullPie = null;
+        boolean shouldShowLabels = true;
         if(getLabelsVisible()) {
             labelsX = new double[getDataSize()];
             labelsY = new double[getDataSize()];
@@ -483,17 +483,20 @@
             int index = 0;
             double start = getStartAngle();
             for (Data item = begin; item != null; item = item.next) {
+                // remove any scale on the text node
+                item.textNode.getTransforms().clear();
+
                 double size = (isClockwise()) ? (-scale * Math.abs(item.getCurrentPieValue())) : (scale * Math.abs(item.getCurrentPieValue()));
                 labelAngles[index] = normalizeAngle(start + (size / 2));
-                final boolean isLeftSide = !(labelAngles[index] > -90 && labelAngles[index] < 90);
                 final double sproutX = calcX(labelAngles[index], getLabelLineLength(), 0);
                 final double sproutY = calcY(labelAngles[index], getLabelLineLength(), 0);
                 labelsX[index] = sproutX;
                 labelsY[index] = sproutY;
-                if (sproutX > 0) { // on left
+                if (sproutX < 0) { // on left
                     minX = Math.min(minX, sproutX-item.textNode.getLayoutBounds().getWidth()-LABEL_TICK_GAP);
                 } else { // on right
                     maxX = Math.max(maxX, sproutX+item.textNode.getLayoutBounds().getWidth()+LABEL_TICK_GAP);
+
                 }
                 if (sproutY > 0) { // on bottom
                     maxY = Math.max(maxY, sproutY+item.textNode.getLayoutBounds().getMaxY());
@@ -506,16 +509,41 @@
             double xPad = (Math.max(Math.abs(minX), Math.abs(maxX))) * 2;
             double yPad = (Math.max(Math.abs(minY), Math.abs(maxY))) * 2;
             pieRadius = Math.min(contentWidth - xPad, contentHeight - yPad) / 2;
-        } else {
+            // check if this makes the pie too small
+            if (pieRadius < MIN_PIE_RADIUS ) {
+                // calculate scale for text to fit labels in
+                final double roomX = contentWidth-MIN_PIE_RADIUS-MIN_PIE_RADIUS;
+                final double roomY = contentHeight-MIN_PIE_RADIUS-MIN_PIE_RADIUS;
+                labelScale = Math.min(
+                        roomX/xPad,
+                        roomY/yPad
+                );
+                // hide labels if pie radius is less than minimum
+                if ((begin == null && labelScale < 0.7) || ((begin.textNode.getFont().getSize()*labelScale) < 9)) {
+                    shouldShowLabels = false;
+                    labelScale = 1;
+                } else {
+                    // set pieRadius to minimum
+                    pieRadius = MIN_PIE_RADIUS;
+                    // apply scale to all label positions
+                    for(int i=0; i< labelsX.length; i++) {
+                        labelsX[i] =  labelsX[i] * labelScale;
+                        labelsY[i] =  labelsY[i] * labelScale;
+                    }
+                }
+            }
+        }
+
+        if(!shouldShowLabels) {
             pieRadius = Math.min(contentWidth,contentHeight) / 2;
         }
-      
+
         if (getChartChildren().size() > 0) {
             int index = 0;
             for (Data item = begin; item != null; item = item.next) {
                 // layout labels for pie slice
-                item.textNode.setVisible(getLabelsVisible());
-                if (getLabelsVisible()) {
+                item.textNode.setVisible(shouldShowLabels);
+                if (shouldShowLabels) {
                     double size = (isClockwise()) ? (-scale * Math.abs(item.getCurrentPieValue())) : (scale * Math.abs(item.getCurrentPieValue()));
                     final boolean isLeftSide = !(labelAngles[index] > -90 && labelAngles[index] < 90);
                     
@@ -532,13 +560,26 @@
                     LabelLayoutInfo info = new LabelLayoutInfo(sliceCenterEdgeX,
                             sliceCenterEdgeY,lineEndX, lineEndY, xval, yval, item.textNode, Math.abs(size));
                     fullPie.add(info);
+
+                    // set label scales
+                    if (labelScale < 1) {
+                        item.textNode.getTransforms().add(
+                            new Scale(
+                                    labelScale, labelScale,
+                                    isLeftSide ? item.textNode.getLayoutBounds().getWidth() : 0,
+//                                    0,
+                                    0
+                            )
+                        );
+                    }
                 }
                 index++;
             }
 
              // Check for collision and resolve by hiding the label of the smaller pie slice
             resolveCollision(fullPie);
-            
+
+            // update/draw pie slices
             double sAngle = getStartAngle();
             for (Data item = begin; item != null; item = item.next) {
              Node node = item.getNode();