import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;

public class AnimatedCubicGraph extends JPanel implements ActionListener {
    JButton start, reset;
    JPanel buttonPanel;
    javax.swing.Timer timer;
    float param = -1;
    float dparam = 0.03f;
    AffineTransform transform;

    public AnimatedCubicGraph() {
	setBackground(Color.white);
	
	start = new JButton("Start");
	reset = new JButton("Reset");
	start.addActionListener(this);
	reset.addActionListener(this);
	
	buttonPanel = new JPanel();
	buttonPanel.add(start);
	buttonPanel.add(reset);
	
	timer = new javax.swing.Timer(20, new ActionListener() {
		public void actionPerformed(ActionEvent event) {
		    param += dparam;
		    if (param >= 1) {
			param = 1;
			timer.stop();
			start.setEnabled(false);
		    }
		    repaint();
		}
	    });

	transform = new AffineTransform();
        transform.translate(150, 150);
        transform.scale(1, -1);
        transform.scale(75, 50);
    }

    public JPanel getButtonPanel() {
	return buttonPanel;
    }
	
    public void paintComponent(Graphics gfx) {
        super.paintComponent(gfx);
        setBackground(Color.white);
        Graphics2D g = (Graphics2D) gfx;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                           RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                           RenderingHints.VALUE_STROKE_PURE);

        g.setPaint(Color.lightGray);
        GeneralPath path = new GeneralPath();
        for (int i = -2; i <= 2; i++) {
            path.moveTo(i, -3);
            path.lineTo(i, 3);
        }
        for (int i = -3; i <= 3; i++) {
            path.moveTo(-2, i);
            path.lineTo(2, i);
        }

        g.draw(transform.createTransformedShape(path));
        int steps = 40;
        float dx = 4.0f/steps;
        g.setPaint(Color.black);
        path = new GeneralPath();
        path.moveTo(-2, valueAt(-2));
        for (float x = -2+dx;  x <= 2; x += dx)
            path.lineTo(x, valueAt(x));
        g.draw(transform.createTransformedShape(path));

    }

    public void actionPerformed(ActionEvent event) {
	String actionCommand = event.getActionCommand();
	if (actionCommand.equals("Start")) {
	    timer.start();
	    start.setText("Pause");
	} else if (actionCommand.equals("Pause")) {
	    timer.stop();
	    start.setText("Start");
	} else {
	    timer.stop();
	    start.setEnabled(true);
	    start.setText("Start");
	    param = -1;
	    repaint();
	}
    }

    public float valueAt(float x) {
        return x*x*x + param*x;
    }
    
    public static void main(String[] args) {
        JFrame frame = new JFrame("CubicGraph");
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        AnimatedCubicGraph quad = new AnimatedCubicGraph();
        quad.setPreferredSize(new Dimension(301, 301));
        frame.getContentPane().add(quad, BorderLayout.CENTER);
        frame.getContentPane().add(quad.getButtonPanel(), BorderLayout.SOUTH);
	
        frame.pack();
        frame.setVisible(true);
    }
}
