/* * Copyright (C) 2004 The Concord Consortium, Inc., * 10 Concord Crossing, Concord, MA 01742 * * Web Site: http://www.concord.org * Email: info@concord.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * 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. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * END LICENSE */ package org.concord.swing.graph; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.Vector; import javax.swing.JComponent; import javax.swing.JFrame; /** * Value gauge.<p> * Graphic component that shows a simple scalar value as a vertical bar.<p> * This component can also represent multiple scalar values additively with * stacked vertical rectangles. */ public class Gauge extends JComponent implements ValueGraph { public final static double DEFAULT_MIN_VALUE = 0.0d; public final static double DEFAULT_MAX_VALUE = 100.0d; public final static double DEFAULT_VALUE = DEFAULT_MAX_VALUE / colors.length; protected double min = DEFAULT_MIN_VALUE; protected double max = DEFAULT_MAX_VALUE; protected double [] values = { DEFAULT_VALUE }; protected double range = max - min; protected int gaugeWidth; protected int gaugeHeight; protected int majorTicks = 0; protected int minorTicks = 0; protected int tickSpace = 2; protected int majorTickLength = 10; protected int minorTickLength = 6; protected int majorTickValue; // Spacing of major ticks protected int minorTickValue; // Spacing of minor ticks protected String [] valueStrings = { "" + values[0] }; protected String minString = "" + min; protected String maxString = "" + max; protected boolean editable = false; protected boolean drawBoundary = false; protected Vector oldBars = new Vector(); protected Rectangle [] bars = { new Rectangle() }; protected Color [] barColors = { Color.red }; protected int numberOfBars = bars.length; protected int [] gaugeValues = new int[bars.length]; protected ComponentAdapter sizeChanged = new ComponentAdapter() { public void componentResized(ComponentEvent event) { setGaugeSize(Gauge.this.getSize()); } }; protected MouseMotionAdapter dragGauge = new MouseMotionAdapter() { public void mouseDragged(MouseEvent event) { setValueFromMouseEvent(event); } }; protected MouseAdapter setGauge = new MouseAdapter() { public void mousePressed(MouseEvent event) { setValueFromMouseEvent(event); } }; /** * Gauge constructor. */ public Gauge() { addComponentListener(sizeChanged); updateValue(values[0]); setEditable(editable); } protected int findBarIndex(int x, int y) { for (int i = 0; i < bars.length; i++) { if (bars[i].contains(x, y)) return i; } return -1; } protected double getBarValue(int index, int x, int y) { Rectangle bar = bars[index]; double barRange = (bar.height * range) / gaugeHeight; double barValue = barRange - ((y - bar.y) * barRange) / bar.height; return barValue; } protected void setValueFromMouseEvent(MouseEvent event) { int x = event.getX(); int y = event.getY(); int index = findBarIndex(x, y); if (index == -1) index = bars.length - 1; Rectangle bar = bars[index]; if ((y - bar.y) > (bar.height / 2)) index--; if (index < 0) index = 0; updateValue(getBarValue(index, x, y), index); repaint(); } protected void setGaugeSize(Dimension size) { if ((majorTicks > 0) && (minorTicks > 0)) gaugeWidth = (int) (0.35 * size.width); else gaugeWidth = size.width; gaugeHeight = size.height; for (int i = 0; i < gaugeValues.length; i++) { gaugeValues[i] = (int) ((values[i] * gaugeHeight) / range); updateValue(getValue(i), i); } setMajorTickMarks(majorTicks); } public void setNumberOfBars(int number) { if (bars != null) { for (int i = 0; i < bars.length; i++) { oldBars.addElement(bars[i]); bars[i] = null; } } numberOfBars = number; bars = new Rectangle[number]; barColors = new Color[number]; values = new double[number]; gaugeValues = new int[number]; for (int i = 0; i < number; i++) { if (oldBars.size() > 0) { bars[i] = (Rectangle) oldBars.elementAt(0); oldBars.removeElementAt(0); } else bars[i] = new Rectangle(); barColors[i] = colors[i % colors.length]; values[i] = DEFAULT_VALUE; } setGaugeSize(getSize()); } /** * Returns editable state. * Gauge value can be set with pointer device interaction. * This method returns whether or not that feature is enabled.<p> */ public boolean getEditable() { return editable; } /** * Make gauges editable. * Gauge value can be set with pointer device interaction. * This method enables and disables that feature.<p> */ public void setEditable(boolean value) { editable = value; if (editable) { addMouseMotionListener(dragGauge); addMouseListener(setGauge); } else { removeMouseMotionListener(dragGauge); removeMouseListener(setGauge); } } /** * Returns the range of values shown by this gauge.<p> * @return - double range of values. */ public double getRange() { return range; } /** * Set the minimum value of the gauge.<p> * @param value - double minumum value. */ public void setMin(double value) { min = value; minString = " " + min; range = Math.abs(max - min); } /** * Get the minimum value of the gauge.<p> * @return - double minimum value. */ public double getMin() { return min; } /** * Set the maximum value of the gauge.<p> * @param value - double maxumum value. */ public void setMax(double value) { max = value; maxString = " " + max; range = Math.abs(max - min); } /** * Get the maximum value of the gauge.<p> * @return double maximum value. */ public double getMax() { return max; } public void setScaleMax(int scale) { double value = (((double) scale) - 50.0d) / 10.0d; max = Math.pow(10.0d, value); } /** * Updates gauge sub-bar at index with new value. * <p> * @param x double value to update. * @param index int index of sub-bar. */ public void updateValue(double value, int index) { values[index] = value; gaugeValues[index] = (int) ((values[index] * gaugeHeight) / range); for (int i = index; i < numberOfBars; i++) { Rectangle bar = bars[i]; int gaugeValue = gaugeValues[i]; bar.x = 0; bar.width = gaugeWidth; bar.height = gaugeValue; if (i == 0) { bar.y = gaugeHeight - gaugeValue; } else { bar.y = bars[i - 1].y - bar.height; } } repaint(); } public void updateValue(double value) { updateValue(value, 0); } public void updateValue(float value, int index) { updateValue((double) value, index); } public void updateValue(float value) { updateValue((double) value); } /** * Get value of gauge sub-bar at index. * <p> * @param index int index of sub-bar. * @return double sub-bar value. */ public double getValue(int index) { return values[index]; } /** * Get value of gauge sub-bar. * <p> * @return double gauge value. */ public double getValue() { return values[0]; } /** * Returns color associated with a particular index. * <p> * @param index int index of sub-bar. * @return Color color of sub-bar. */ public Color getColor(int index) { return barColors[index]; } /** * Sets the color associated with a particular index. * <p> * @param color Color of sub-bar. * @param index int index of sub-bar. */ public void setColor(Color color, int index) { barColors[index] = color; } /** * Returns color associated with a particular index. * <p> * @return Color color of gauge. */ public Color getColor() { return barColors[0]; } /** * Sets the color. * <p> * @param color Color of gauge. */ public void setColor(Color color) { barColors[0] = color; } public void setMajorTickMarks(int ticks) { majorTicks = ticks; if (majorTicks > 0) majorTickValue = gaugeHeight / majorTicks; // Spacing of major ticks setMinorTickMarks(minorTicks); } public void setMinorTickMarks(int ticks) { minorTicks = ticks; if (minorTicks > 0) minorTickValue = majorTickValue / minorTicks; // Spacing of minor ticks } public void paintComponent(Graphics g) { for(int i = 0; i < numberOfBars; i++) { g.setColor(barColors[i]); g.fillRect(bars[i].x, bars[i].y, bars[i].width, bars[i].height); } if (drawBoundary) { g.setColor(Color.black); g.drawRect(0, 0, gaugeWidth, gaugeHeight); // Draw the outline of the gauge } if ((majorTicks > 0) && (minorTicks > 0)) { int x1 = gaugeWidth + tickSpace; for (int y1 = gaugeHeight; y1 >= 0; y1 -= majorTickValue) { int x2 = x1 + majorTickLength; g.drawLine(x1, y1, x2, y1); x2 = x1 + minorTickLength; int min = (y1 - majorTickValue + minorTickValue);; for (int y2 = y1 - minorTickValue; y2 >= min; y2 -= minorTickValue) { g.drawLine(x1, y2, x2, y2); } } int x = x1 + majorTickLength + tickSpace; for (int i = 0; i < gaugeValues.length; i++) { int y = (gaugeHeight - gaugeValues[i]) + 10; g.drawString(valueStrings[i], x, y); g.drawString(maxString, x, 10); g.drawString(minString, x, gaugeHeight + 10); } } } public static void main(String [] args) { JFrame frame = new JFrame("Test gauge"); Gauge gauge = new Gauge(); gauge.setEditable(true); gauge.setNumberOfBars(6); frame.getContentPane().add(gauge, "Center"); frame.setSize(150, 500); frame.setVisible(true); } }