import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import javax.swing.*;
public class LineChart extends JPanel {
double[] data = { 13.2, 9.2, 4, 16.7, 4.3, 9.5, 12, 5.4 };
final int PAD = 25;
final int TICK = 2;
final int STICK = 3;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawAxes(g2);
// plot data
Point2D.Double lastP = null;
for(int j = 0; j < data.length; j++) {
g2.setPaint(Color.red);
Point2D.Double p = modelToView(j, data[j]);
g2.fill(new Ellipse2D.Double(p.x-2, p.y-2, 4, 4));
if(lastP != null) {
g2.setPaint(Color.blue);
g2.draw(new Line2D.Double(lastP, p));
}
lastP = p;
}
}
private Point2D.Double modelToView(double x, double y) {
double w = getWidth();
double h = getHeight();
double tx = PAD;
double ty = h-PAD;
AffineTransform at = AffineTransform.getTranslateInstance(tx, ty);
double xScale = (w - 2*PAD)/(data.length-1);
int max = (int)Math.ceil(getMaxValue());
double yScale = (h - 2*PAD)/max;
at.scale(xScale, -yScale);
Point2D.Double dst = new Point2D.Double();
at.transform(new Point2D.Double(x, y), dst);
return dst;
}
private void drawAxes(Graphics2D g2) {
double w = getWidth();
double h = getHeight();
double xInc = (w - 2*PAD)/(data.length-1);
int max = (int)Math.ceil(getMaxValue());
double yInc = (h - 2*PAD)/max;
// grid lines
g2.setPaint(new Color(220,230,240));
// vertical
for(int j = 0; j <= data.length; j++) {
double x = PAD + j*xInc;
g2.draw(new Line2D.Double(x, PAD, x, h-PAD));
}
// horizontal
for(int j = 0; j <= max; j++) {
double y = PAD + j*yInc;
g2.draw(new Line2D.Double(PAD, y, w-PAD, y));
}
// axes
g2.setPaint(new Color(51,51,51));
// ordinate
g2.draw(new Line2D.Double(PAD, PAD, PAD, h-PAD));
// tick marks
for(int j = 0; j <= max; j++) {
double y = PAD + j*yInc;
g2.draw(new Line2D.Double(PAD, y, PAD-TICK, y));
}
// labels
Font font = g2.getFont().deriveFont(14f);
g2.setFont(font);
FontRenderContext frc = g2.getFontRenderContext();
LineMetrics lm = font.getLineMetrics("0", frc);
for(int j = 0; j <= max; j++) {
String s = String.valueOf(max-j);
float y = (float)(PAD + j*yInc + lm.getDescent());
float width = (float)font.getStringBounds(s, frc).getWidth();
float x = (float)(PAD - TICK - STICK - width);
g2.drawString(s, x, y);
}
// abcissa
g2.draw(new Line2D.Double(PAD, h-PAD, w-PAD, h-PAD));
// tick marks
for(int j = 0; j <= data.length; j++) {
double x = PAD + j*xInc;
g2.draw(new Line2D.Double(x, h-PAD, x, h-PAD+TICK));
}
// labels
for(int j = 0; j <= data.length; j++) {
String s = String.valueOf(j);
float width = (float)font.getStringBounds(s, frc).getWidth();
float x = (float)(PAD + j*xInc - width/2);
float y = (float)(h-PAD + TICK + STICK + lm.getAscent());
g2.drawString(s, x, y);
}
}
private double getMaxValue() {
double max = -Double.MAX_VALUE;
for(int j = 0; j < data.length; j++) {
if(data[j] > max)
max = data[j];
}
return max;
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new LineChart());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
}