Mega Code Archive

 
Categories / Java / 2D Graphics GUI
 

Line-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.]  *  * ------------  * LineGraphDrawable.java  * ------------  */ import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; /**  * A very fast and very simple line-graph drawable. This code is based on the  * LineGraph 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 LineGraphDrawable {   private static final int DEFAULT_SPACING = 2;   private int spacing;   private Color color;   private Color background;   private Number[] data;   /**    * Creates a default bargraph drawable with some sensible default colors and    * spacings.    */   public LineGraphDrawable() {     this.color = Color.black;     this.spacing = 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 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 graphics    *          the graphics context on which the bargraph should be rendered.    * @param drawArea    *          the area on which the bargraph should be drawn.    */   public void draw(final Graphics2D graphics, final Rectangle2D drawArea) {     if (graphics == null) {       throw new NullPointerException();     }     if (drawArea == null) {       throw new NullPointerException();     }     final int height = (int) drawArea.getHeight();     if (height <= 0) {       return;     }     final Graphics2D g2 = (Graphics2D) graphics.create();     if (background != null) {       g2.setPaint(background);       g2.draw(drawArea);     }     if (data == null || data.length == 0) {       g2.dispose();       return;     }     g2.translate(drawArea.getX(), drawArea.getY());     float d = getDivisor(data, height);     final int spacing = getSpacing();     final int w = (((int) drawArea.getWidth()) - (spacing * (data.length - 1))) / (data.length - 1);     float min = Float.MAX_VALUE;     for (int index = 0; index < data.length; index++) {       Number i = data[index];       if (i == null) {         continue;       }       final float value = i.floatValue();       if (value < min) {         min = value;       }     }     int x = 0;     int y = -1;     if (d == 0.0) {       // special case -- a horizontal straight line       d = 1.0f;       y = -height / 2;     }     final Line2D.Double line = new Line2D.Double();     for (int i = 0; i < data.length - 1; i++) {       final int px1 = x;       x += (w + spacing);       final int px2 = x;       g2.setPaint(color);       final Number number = data[i];       final Number nextNumber = data[i + 1];       if (number == null && nextNumber == null) {         final float delta = height - ((0 - min) / d);         line.setLine(px1, y + delta, px2, y + delta);       } else if (number == null) {         line.setLine(px1, y + (height - ((0 - min) / d)), px2, y             + (height - ((nextNumber.floatValue() - min) / d)));       } else if (nextNumber == null) {         line.setLine(px1, y + (height - ((number.floatValue() - min) / d)), px2, y             + (height - ((0 - min) / d)));       } else {         line.setLine(px1, y + (height - ((number.floatValue() - min) / d)), px2, y             + (height - ((nextNumber.floatValue() - min) / d)));       }       g2.draw(line);     }     g2.dispose();   }   /**    * 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);   } }