Mega Code Archive

 
Categories / Java / Advanced Graphics
 

Bar-graph drawable

/**  *   * LibSparkline : a free Java sparkline chart library  *   *  * Project Info:  http://reporting.pentaho.org/libsparkline/  *  * (C) Copyright 2008, by Larry Ogrodnek, Pentaho Corporation and Contributors.  *  * This library is free software; you can redistribute it and/or modify it under the terms  * of the Apache License 2.0.  *  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  *  * You should have received a copy of the Apache License 2.0 along with this library;  * if not, a online version is available at http://www.apache.org/licenses/  *  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.  * in the United States and other countries.]  *  * ------------  * BarGraphDrawable.java  * ------------  */ import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; /**  * A very fast and very simple bar-graph drawable. This code is based on the BarGraph class writen by Larry Ogrodnek  * but instead of producing a low-resolution image, this class writes the content into a Graphics2D context.    *  * @author Thomas Morgner  */ public class BarGraphDrawable {   private static final int DEFAULT_SPACING = 2;   private static final Color DEFAULT_COLOR = Color.gray;   private static final Color DEFAULT_HIGH_COLOR = Color.black;   private static final Color DEFAULT_LAST_COLOR = Color.red;   private Number[] data;   private Color color;   private Color highColor;   private Color lastColor;   private Color background;   private int spacing;   /**    * Creates a default bargraph drawable with some sensible default colors and spacings.    */   public BarGraphDrawable()   {     this.highColor = BarGraphDrawable.DEFAULT_HIGH_COLOR;     this.lastColor = BarGraphDrawable.DEFAULT_LAST_COLOR;     this.color = BarGraphDrawable.DEFAULT_COLOR;     this.spacing = BarGraphDrawable.DEFAULT_SPACING;   }   /**    * Returns the numeric data for the drawable or null, if the drawable has no data.    *    * @return the data.    */   public Number[] getData()   {     return data;   }   /**    * Defines the numeric data for the drawable or null, if the drawable has no data.    *    * @param data the data (can be null).    */   public void setData(final Number[] data)   {     this.data = data;   }   /**    * Returns the main color for the bars.    *    * @return the main color for the bars, never null.    */   public Color getColor()   {     return color;   }   /**    * Defines the main color for the bars.    *    * @param color the main color for the bars, never null.    */   public void setColor(final Color color)   {     if (color == null)     {       throw new NullPointerException();     }     this.color = color;   }   /**    * Returns the color for the highest bars. This property is optional and the high-color can be null.    *    * @return the color for the higest bars, or null if high bars should not be marked specially.    */   public Color getHighColor()   {     return highColor;   }   /**    * Defines the color for the highest bars. This property is optional and the high-color can be null.    *    * @param highColor the color for the higest bars, or null if high bars should not be marked specially.    */   public void setHighColor(final Color highColor)   {     this.highColor = highColor;   }   /**    * Returns the color for the last bar. This property is optional and the last-bar-color can be null.    *    * @return the color for the last bar in the graph, or null if last bars should not be marked specially.    */   public Color getLastColor()   {     return lastColor;   }   /**    * Defines the color for the last bar. This property is optional and the last-bar-color can be null.    *    * @param lastColor the color for the last bar in the graph, or null if last bars should not be marked specially.    */   public void setLastColor(final Color lastColor)   {     this.lastColor = lastColor;   }   /**    * Returns the color for the background of the graph. This property can be null, in which case the bar    * will have a transparent background.    *    * @return color for the background or null, if the graph has a transparent background color.    */   public Color getBackground()   {     return background;   }   /**    * Defines the color for the background of the graph. This property can be null, in which case the bar    * will have a transparent background.    *    * @param background the background or null, if the graph has a transparent background color.    */   public void setBackground(final Color background)   {     this.background = background;   }   /**    * Returns the spacing between the bars.    *    * @return the spacing between the bars.    */   public int getSpacing()   {     return spacing;   }   /**    * Defines the spacing between the bars.    *    * @param spacing the spacing between the bars.    */   public void setSpacing(final int spacing)   {     this.spacing = spacing;   }   /**    * Draws the bar-graph into the given Graphics2D context in the given area. This method will not draw a graph    * if the data given is null or empty.    *    * @param g2 the graphics context on which the bargraph should be rendered.     * @param drawArea the area on which the bargraph should be drawn.    */   public void draw(Graphics2D g2, Rectangle2D drawArea)   {     if (g2 == null)     {       throw new NullPointerException();     }     if (drawArea == null)     {       throw new NullPointerException();     }     final int height = (int) drawArea.getHeight();     if (height <= 0)     {       return;     }          Graphics2D g = (Graphics2D) g2.create();     g.translate(drawArea.getX(), drawArea.getY());     if (background != null)     {       g.setBackground(background);       g.clearRect(0, 0, (int) drawArea.getWidth(), height);     }     if (data == null || data.length == 0)     {       g.dispose();       return;     }     final float d = getDivisor(data, height);     final int a = computeAverage(data);     final int spacing1 = getSpacing();     final int w = ((int) drawArea.getWidth() - (spacing1 * data.length)) / data.length;     int x = 0;     final int y = 0;     final double vHeight = drawArea.getHeight();     final Rectangle2D.Double bar = new Rectangle2D.Double();          for (int index = 0; index < data.length; index++)     {       Number i = data[index];       if (i == null)       {         continue;       }              final int h = (int) (i.floatValue() / d);       final int intVal = i.intValue();       if (index == (data.length - 1) && lastColor != null)       {         g.setPaint(lastColor);       }       else if (intVal < a || (highColor == null))       {         g.setPaint(color);       }       else       {         g.setPaint(highColor);       }       bar.setRect(x, y + (vHeight - h), w, intVal / d);       g.fill(bar);       x += (w + spacing1);     }     g.dispose();   }   /**    * Computes the average for all numbers in the array.    *    * @param data the numbers for which the average should be computed.    * @return the average.    */   private static int computeAverage(final Number[] data)   {     int total = 0;     int length = 0;     for (int index = 0; index < data.length; index++)     {       Number i = data[index];       if (i == null)       {         continue;       }       total += i.intValue();       length += 1;     }     return (total / length);   }   /**    * Computes the scale factor to scale the given numeric data into the target    * height.    *     * @param data    *          the numeric data.    * @param height    *          the target height of the graph.    * @return the scale factor.    */   public static float getDivisor(final Number[] data, final int height) {     if (data == null) {       throw new NullPointerException("Data array must not be null.");     }     if (height < 1) {       throw new IndexOutOfBoundsException("Height must be greater or equal to 1");     }     float max = Float.MIN_VALUE;     float min = Float.MAX_VALUE;     for (int index = 0; index < data.length; index++) {       Number i = data[index];       if (i == null) {         continue;       }       final float numValue = i.floatValue();       if (numValue < min) {         min = numValue;       }       if (numValue > max) {         max = numValue;       }     }     if (max <= min) {       return 1.0f;     }     if (height == 1) {       return 0;     }     return (max - min) / (height - 1);   } }