Java/2D Graphics GUI/Chart
Demo bar chart and pie chart
<source lang="java"> import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.Image; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Stroke; import java.awt.event.ruponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.geom.AffineTransform; import java.awt.geom.Arc2D; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class Charts2D extends JFrame {
public Charts2D() { super("2D Charts"); setSize(720, 280); getContentPane().setLayout(new GridLayout(1, 3, 10, 0)); getContentPane().setBackground(Color.white); int[] xData = new int[8]; int[] yData = new int[8]; for (int i = 0; i < xData.length; i++) { xData[i] = i; yData[i] = (int) (Math.random() * 100); if (i > 0) yData[i] = (yData[i - 1] + yData[i]) / 2; } JChart2D chart = new JChart2D(JChart2D.LineChart, xData.length, xData, yData, "Line Chart"); chart.setStroke(new BasicStroke(5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER)); chart.setLineColor(new Color(0, 28, 28)); getContentPane().add(chart); chart = new JChart2D(JChart2D.ColumnChart, xData.length, xData, yData, "Column Chart"); GradientPaint gp = new GradientPaint(0, 100, Color.white, 0, 300, Color.blue, true); chart.setGradient(gp); chart.setEffectIndex(JChart2D.Gradientffect); chart.setDrawShadow(true); getContentPane().add(chart); chart = new JChart2D(JChart2D.PieChart, xData.length, xData, yData, "Pie Chart"); ImageIcon icon = new ImageIcon("largejexplogo.GIF"); chart.setForegroundImage(icon.getImage()); chart.setEffectIndex(JChart2D.ImageEffect); chart.setDrawShadow(true); getContentPane().add(chart); WindowListener wndCloser = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; addWindowListener(wndCloser); setVisible(true); } public static void main(String argv[]) { new Charts2D(); }
} class JChart2D extends JPanel {
public static final int LineChart = 0; public static final int ColumnChart = 1; public static final int PieChart = 2; public static final int PLainEffect = 0; public static final int Gradientffect = 1; public static final int ImageEffect = 2; protected int m_chartType = LineChart; protected JLabel titleLabel; protected ChartPanel chartPanel; protected int dataLength; protected int[] xData; protected int[] yData; protected int xMin; protected int xMax; protected int yMin; protected int yMax; protected double[] pieData; protected int m_effectIndex = PLainEffect; protected Stroke stroke; protected GradientPaint gradient; protected Image foregroundImage; protected Color lineColor = Color.black; protected Color columnColor = Color.blue; protected int columnWidth = 12; protected boolean drawShadow = false; public JChart2D(int type, int nData, int[] yData, String text) { this(type, nData, null, yData, text); } public JChart2D(int type, int nData, int[] xD, int[] yD, String text) { super(new BorderLayout()); setBackground(Color.white); titleLabel = new JLabel(text, JLabel.CENTER); add(titleLabel, BorderLayout.NORTH); m_chartType = type; if (xData == null) { xData = new int[nData]; for (int k = 0; k < nData; k++) xData[k] = k; } if (yD == null) throw new IllegalArgumentException("yData can"t be null"); if (nData > yD.length) throw new IllegalArgumentException("Insufficient yData length"); if (nData > xD.length) throw new IllegalArgumentException("Insufficient xData length"); dataLength = nData; xData = xD; yData = yD; xMin = xMax = 0; // To include 0 into the interval yMin = yMax = 0; for (int k = 0; k < dataLength; k++) { xMin = Math.min(xMin, xData[k]); xMax = Math.max(xMax, xData[k]); yMin = Math.min(yMin, yData[k]); yMax = Math.max(yMax, yData[k]); } if (xMin == xMax) xMax++; if (yMin == yMax) yMax++; if (m_chartType == PieChart) { double sum = 0; for (int k = 0; k < dataLength; k++) { yData[k] = Math.max(yData[k], 0); sum += yData[k]; } pieData = new double[dataLength]; for (int k = 0; k < dataLength; k++) pieData[k] = yData[k] * 360.0 / sum; } chartPanel = new ChartPanel(); add(chartPanel, BorderLayout.CENTER); } public void setEffectIndex(int effectIndex) { m_effectIndex = effectIndex; repaint(); } public int getEffectIndex() { return m_effectIndex; } public void setStroke(Stroke s) { stroke = s; chartPanel.repaint(); } public void setForegroundImage(Image img) { foregroundImage = img; repaint(); } public Image getForegroundImage() { return foregroundImage; } public Stroke getStroke() { return stroke; } public void setGradient(GradientPaint g) { gradient = g; repaint(); } public GradientPaint getGradient() { return gradient; } public void setColumnWidth(int c) { columnWidth = c; chartPanel.calcDimensions(); chartPanel.repaint(); } public int setColumnWidth() { return columnWidth; } public void setColumnColor(Color c) { columnColor = c; chartPanel.repaint(); } public Color getColumnColor() { return columnColor; } public void setLineColor(Color c) { lineColor = c; chartPanel.repaint(); } public Color getLineColor() { return lineColor; } public void setDrawShadow(boolean d) { drawShadow = d; chartPanel.repaint(); } public boolean getDrawShadow() { return drawShadow; } class ChartPanel extends JComponent { int xMargin = 5; int yMargin = 5; int pieGap = 10; int m_x; int m_y; int m_w; int m_h; ChartPanel() { enableEvents(ComponentEvent.ruPONENT_RESIZED); } protected void processComponentEvent(ComponentEvent e) { calcDimensions(); } public void calcDimensions() { Dimension d = getSize(); m_x = xMargin; m_y = yMargin; m_w = d.width - 2 * xMargin; m_h = d.height - 2 * yMargin; if (m_chartType == ColumnChart) { m_x += columnWidth / 2; m_w -= columnWidth; } } public int xChartToScreen(int x) { return m_x + (x - xMin) * m_w / (xMax - xMin); } public int yChartToScreen(int y) { return m_y + (yMax - y) * m_h / (yMax - yMin); } public void paintComponent(Graphics g) { int x0 = 0; int y0 = 0; if (m_chartType != PieChart) { g.setColor(Color.black); x0 = xChartToScreen(0); g.drawLine(x0, m_y, x0, m_y + m_h); y0 = yChartToScreen(0); g.drawLine(m_x, y0, m_x + m_w, y0); } Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); if (stroke != null) g2.setStroke(stroke); GeneralPath path = new GeneralPath(); switch (m_chartType) { case LineChart: g2.setColor(lineColor); path.moveTo(xChartToScreen(xData[0]), yChartToScreen(yData[0])); for (int k = 1; k < dataLength; k++) path.lineTo(xChartToScreen(xData[k]), yChartToScreen(yData[k])); g2.draw(path); break; case ColumnChart: for (int k = 0; k < dataLength; k++) { xMax++; int x = xChartToScreen(xData[k]); int w = columnWidth; int y1 = yChartToScreen(yData[k]); int y = Math.min(y0, y1); int h = Math.abs(y1 - y0); Shape rc = new Rectangle2D.Double(x, y, w, h); path.append(rc, false); xMax--; } if (drawShadow) { AffineTransform s0 = new AffineTransform(1.0, 0.0, 0.0, -1.0, x0, y0); s0.concatenate(AffineTransform.getScaleInstance(1.0, 0.5)); s0.concatenate(AffineTransform.getShearInstance(0.5, 0.0)); s0.concatenate(new AffineTransform(1.0, 0.0, 0.0, -1.0, -x0, y0)); g2.setColor(Color.gray); Shape shadow = s0.createTransformedShape(path); g2.fill(shadow); } if (m_effectIndex == Gradientffect && gradient != null) { g2.setPaint(gradient); g2.fill(path); } else if (m_effectIndex == ImageEffect && foregroundImage != null) fillByImage(g2, path, 0); else { g2.setColor(columnColor); g2.fill(path); } g2.setColor(lineColor); g2.draw(path); break; case PieChart: double start = 0.0; double finish = 0.0; int ww = m_w - 2 * pieGap; int hh = m_h - 2 * pieGap; if (drawShadow) { ww -= pieGap; hh -= pieGap; } for (int i = 0; i < dataLength; i++) { finish = start + pieData[i]; double f1 = Math.min(90 - start, 90 - finish); double f2 = Math.max(90 - start, 90 - finish); Shape shp = new Arc2D.Double(m_x, m_y, ww, hh, f1, f2 - f1, Arc2D.PIE); double f = (f1 + f2) / 2 * Math.PI / 180; AffineTransform s1 = AffineTransform.getTranslateInstance( pieGap * Math.cos(f), -pieGap * Math.sin(f)); s1.translate(pieGap, pieGap); Shape piece = s1.createTransformedShape(shp); path.append(piece, false); start = finish; } if (drawShadow) { AffineTransform s0 = AffineTransform.getTranslateInstance( pieGap, pieGap); g2.setColor(Color.gray); Shape shadow = s0.createTransformedShape(path); g2.fill(shadow); } if (m_effectIndex == Gradientffect && gradient != null) { g2.setPaint(gradient); g2.fill(path); } else if (m_effectIndex == ImageEffect && foregroundImage != null) fillByImage(g2, path, 0); else { g2.setColor(columnColor); g2.fill(path); } g2.setColor(lineColor); g2.draw(path); break; } } protected void fillByImage(Graphics2D g2, Shape shape, int xOffset) { if (foregroundImage == null) return; int wImg = foregroundImage.getWidth(this); int hImg = foregroundImage.getHeight(this); if (wImg <= 0 || hImg <= 0) return; g2.setClip(shape); Rectangle bounds = shape.getBounds(); for (int i = bounds.x + xOffset; i < bounds.x + bounds.width; i += wImg) for (int j = bounds.y; j < bounds.y + bounds.height; j += hImg) g2.drawImage(foregroundImage, i, j, this); } }
}
</source>
Drawing a Pie Chart
<source lang="java"> import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import javax.swing.JComponent; import javax.swing.JFrame; class Slice {
double value; Color color; public Slice(double value, Color color) { this.value = value; this.color = color; }
} class MyComponent extends JComponent {
Slice[] slices = { new Slice(5, Color.black), new Slice(33, Color.green), new Slice(20, Color.yellow), new Slice(15, Color.red) }; MyComponent() { } public void paint(Graphics g) { drawPie((Graphics2D) g, getBounds(), slices); } void drawPie(Graphics2D g, Rectangle area, Slice[] slices) { double total = 0.0D; for (int i = 0; i < slices.length; i++) { total += slices[i].value; } double curValue = 0.0D; int startAngle = 0; for (int i = 0; i < slices.length; i++) { startAngle = (int) (curValue * 360 / total); int arcAngle = (int) (slices[i].value * 360 / total); g.setColor(slices[i].color); g.fillArc(area.x, area.y, area.width, area.height, startAngle, arcAngle); curValue += slices[i].value; } }
} public class PieChart {
public static void main(String[] argv) { JFrame frame = new JFrame(); frame.getContentPane().add(new MyComponent()); frame.setSize(300, 200); frame.setVisible(true); }
}
</source>
Simple bar chart
<source lang="java"> import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import javax.swing.JFrame; import javax.swing.JPanel; public class ChartPanel extends JPanel {
private double[] values; private String[] names; private String title; public ChartPanel(double[] v, String[] n, String t) { names = n; values = v; title = t; } public void paintComponent(Graphics g) { super.paintComponent(g); if (values == null || values.length == 0) return; double minValue = 0; double maxValue = 0; for (int i = 0; i < values.length; i++) { if (minValue > values[i]) minValue = values[i]; if (maxValue < values[i]) maxValue = values[i]; } Dimension d = getSize(); int clientWidth = d.width; int clientHeight = d.height; int barWidth = clientWidth / values.length; Font titleFont = new Font("SansSerif", Font.BOLD, 20); FontMetrics titleFontMetrics = g.getFontMetrics(titleFont); Font labelFont = new Font("SansSerif", Font.PLAIN, 10); FontMetrics labelFontMetrics = g.getFontMetrics(labelFont); int titleWidth = titleFontMetrics.stringWidth(title); int y = titleFontMetrics.getAscent(); int x = (clientWidth - titleWidth) / 2; g.setFont(titleFont); g.drawString(title, x, y); int top = titleFontMetrics.getHeight(); int bottom = labelFontMetrics.getHeight(); if (maxValue == minValue) return; double scale = (clientHeight - top - bottom) / (maxValue - minValue); y = clientHeight - labelFontMetrics.getDescent(); g.setFont(labelFont); for (int i = 0; i < values.length; i++) { int valueX = i * barWidth + 1; int valueY = top; int height = (int) (values[i] * scale); if (values[i] >= 0) valueY += (int) ((maxValue - values[i]) * scale); else { valueY += (int) (maxValue * scale); height = -height; } g.setColor(Color.red); g.fillRect(valueX, valueY, barWidth - 2, height); g.setColor(Color.black); g.drawRect(valueX, valueY, barWidth - 2, height); int labelWidth = labelFontMetrics.stringWidth(names[i]); x = i * barWidth + (barWidth - labelWidth) / 2; g.drawString(names[i], x, y); } } public static void main(String[] argv) { JFrame f = new JFrame(); f.setSize(400, 300); double[] values = new double[3]; String[] names = new String[3]; values[0] = 1; names[0] = "Item 1"; values[1] = 2; names[1] = "Item 2"; values[2] = 4; names[2] = "Item 3"; f.getContentPane().add(new ChartPanel(values, names, "title")); WindowListener wndCloser = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; f.addWindowListener(wndCloser); f.setVisible(true); }
}
</source>