package iiuf.swing; import java.awt.Graphics; import java.awt.Dimension; import java.awt.Color; import java.awt.BorderLayout; import java.awt.FontMetrics; import javax.swing.JPanel; import javax.swing.JFrame; import javax.swing.ListModel; import javax.swing.DefaultListModel; import javax.swing.event.ListDataListener; import javax.swing.event.ListDataEvent; import iiuf.util.Util; /** Simple charting panel. (c) 2001, DIUF<p> @author $Author: ohitz $ @version $Name: $ $Revision: 1.1 $ */ public class ChartPanel extends JPanel implements ListDataListener { private ListModel model; private Dimension prefSize = new Dimension(100, 100); private Color[] colors; private Labels labels = new Labels(); public ChartPanel(ListModel model_) { model = model_; setColors(new Color[] { Color.black, Color.green, Color.blue, Color.yellow, Color.gray, Color.lightGray, Color.magenta, Color.orange, Color.pink, Color.red, Color.white, Color.cyan, Color.darkGray, }); model.addListDataListener(this); } public void contentsChanged(ListDataEvent e) { update(); } public void intervalAdded(ListDataEvent e) { update(); } public void intervalRemoved(ListDataEvent e) { update(); } public Dimension getMinimalSize() { return getPreferredSize(); } public Dimension getPreferredSize() { return prefSize; } public void setLabels(Labels l) { labels = l; } private boolean showPoints; public void setPointsVisible(boolean show) { showPoints = show; repaint(); } private boolean showZero; public void setZeroVisible(boolean show) { showZero = show; repaint(); } private boolean showLastPoints; public void setLastPointsVisible(boolean show) { showLastPoints = show; repaint(); } private int xLabelIndex = -1; public void setXLabelIndex(int idx) { xLabelIndex = idx; repaint(); } private int size = 0; private double maxVal = Double.MIN_VALUE; private double minVal = Double.MAX_VALUE; private int valCnt = 0; private double[][] data = new double[0][0]; private double[] normalize(Object o) { if(o instanceof Number) return new double[] {((Number)o).doubleValue()}; else if(o instanceof Boolean) return new double[] {((Boolean)o).booleanValue() ? 1.0 : 0.0}; else if(o instanceof boolean[]) { boolean[] n = (boolean[])o; double[] result = new double[n.length]; for(int i = 0; i < result.length; i++) result[i] = n[i] ? 1.0 : 0; return result; } else if(o instanceof byte[]) { byte[] n = (byte[])o; double[] result = new double[n.length]; for(int i = 0; i < result.length; i++) result[i] = n[i]; return result; } else if(o instanceof short[]) { short[] n = (short[])o; double[] result = new double[n.length]; for(int i = 0; i < result.length; i++) result[i] = n[i]; return result; } else if(o instanceof int[]) { int[] n = (int[])o; double[] result = new double[n.length]; for(int i = 0; i < result.length; i++) result[i] = n[i]; return result; } else if(o instanceof long[]) { long[] n = (long[])o; double[] result = new double[n.length]; for(int i = 0; i < result.length; i++) result[i] = n[i]; return result; } else if(o instanceof float[]) { float[] n = (float[])o; double[] result = new double[n.length]; for(int i = 0; i < result.length; i++) result[i] = n[i]; return result; } else if(o instanceof double[]) return (double[])o; else return new double[0]; } private synchronized void update() { size = model.getSize(); data = new double[size][]; for(int i = 0; i < size; i++) { data[i] = normalize(model.getElementAt(i)); maxVal = Math.max(maxVal, Util.max(data[i])); minVal = Math.min(minVal, Util.min(data[i])); valCnt = Math.max(valCnt, data[i].length); } if(valCnt > colors.length) { Color[] tmp = colors; colors = new Color[valCnt]; System.arraycopy(tmp, 0, colors, 0, tmp.length); for(int i = tmp.length; i < colors.length; i++) colors[i] = new Color(Util.intRandom(0xCFFFFF) + 0x400000); } repaint(); } private static final int YOFF = 15; private static final int LABEL_MARK = 5; public synchronized void paint(Graphics g) { if(size < 2) return; int width = getWidth(); double height = getHeight(); FontMetrics fm = g.getFontMetrics(); int XOFF = LABEL_MARK + 2 + Math.max(fm.stringWidth(labels.getYLabel(maxVal)), fm.stringWidth(labels.getYLabel(minVal))); if(showZero) minVal = Math.min(0, minVal); g.setColor(getBackground()); g.fillRect(getX(), getY(), width, (int)height); g.translate(0, YOFF); width -= XOFF; height -= YOFF + LABEL_MARK + fm.getHeight(); double dHeight = maxVal - minVal; int[] v0 = new int[valCnt]; int[] v1 = new int[valCnt]; for(int j = 0; j < data[0].length; j++) v0[j] = (int)(((height * (maxVal - data[0][j])) / dHeight)); Color fore = getForeground(); int x = 0; int ox = x; int mid = (int)((maxVal * height) / dHeight); int ly = mid + LABEL_MARK + fm.getAscent(); for(int i = 1; i < size; i++) { x = (i * width) / (size - 1); for(int j = 0; j < data[i].length; j++) { if(j == xLabelIndex) continue; v1[j] = (int)(((height * (maxVal - data[i][j])) / dHeight)); g.setColor(colors[j]); g.drawLine(ox, v0[j], x, v1[j]); if(showPoints || (i == size - 1 && showLastPoints)) g.drawString(labels.getPointLabel(data[i][j]), x, v1[j]); } g.setColor(fore); g.drawLine(x, mid - LABEL_MARK, x, mid + LABEL_MARK); String l = labels.getXLabel(xLabelIndex == -1 ? (double)i : data[i][xLabelIndex]); g.drawString(l, x - fm.stringWidth(l), ly); v0 = (int[])v1.clone(); ox = x; } g.drawLine(0, mid, width + LABEL_MARK, mid); g.drawLine(width, 0, width, (int)height); g.drawLine(width, mid, width + LABEL_MARK, mid); g.drawLine(width, (int)height, width + LABEL_MARK, (int)height); g.drawString(labels.getYLabel(maxVal), width + LABEL_MARK, 0); g.drawString(labels.getYLabel(0), width + LABEL_MARK, mid); g.drawString(labels.getYLabel(minVal), width + LABEL_MARK, (int)height); } public void setColors(Color[] colors_) { colors = colors_; } static public class Labels { String getYLabel(double val) { return val + ""; } String getXLabel(double val) { return getYLabel(val); } String getPointLabel(double val) { return getYLabel(val); } } public static void main(String[] argv) { DefaultListModel model = new DefaultListModel(); ChartPanel cp = new ChartPanel(model); JFrame f = new JFrame(); f.getContentPane().setLayout(new BorderLayout()); f.getContentPane().add(BorderLayout.CENTER, cp); f.setSize(400, 400); f.show(); for(;;) { model.addElement(new int[] {Util.intRandom(100) - 50, Util.intRandom(100) - 50, Util.intRandom(100) - 50}); Util.delay(1000); } } } /* $Log: ChartPanel.java,v $ Revision 1.1 2002/07/11 12:09:52 ohitz Initial checkin Revision 1.2 2001/01/15 15:08:58 schubige some sourcewatch bug fixes Revision 1.1 2001/01/14 13:27:33 schubige Wind NT update */