home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-02-05 | 12.0 KB | 389 lines |
- /*
- * @(#)SpiroAnim.java 1.0 97/11/04 Jos van den Oever
- *
- * based on: <A HREF=http://www.wordsmith.org/anu/java/spirograph.html>Spiro.java</A> by Anu Garg
- *
- * Copyright (c) 1997 Jos van den Oever
- *
- */
-
- import java.awt.AWTEvent;
- import java.awt.Canvas;
- import java.awt.Color;
- import java.awt.Container;
- import java.awt.Graphics;
- import java.awt.Image;
- import java.awt.Window;
- import java.awt.event.ComponentEvent;
- import java.awt.event.MouseEvent;
- import java.awt.event.WindowEvent;
- import java.awt.event.WindowListener;
-
- /**
- * SpiroAnim - a class that produces an animated spirograph.
- *
- * SpiroAnim is an ideal component for entertaining users waiting for
- * downloading applications. You can add it to any Container and an animation of a
- * spirograph starts. It's thread has minimum priority. You can configure the
- * component to stop and start or to reset when clicked.
- * <P>
- * If you like this class, feel free to use it. I'd like to hear how you like
- * it, so don't hesitate to inform me if you use it.
- * <P>
- * @author <A HREF="mailto:Jos.vandenOever@nmr.bc.wau.nl">Jos van den Oever</A>
- * @version 1.00
- */
- public class SpiroAnim extends Canvas implements Runnable, WindowListener {
-
- private int I = 100; // Number of Iterations
-
- private float Rvar = 0.03f, rvar = 0.03f, ovar = 0.03f, // variation in radii
- R, r, O, // radii per frame
- Rnew, rnew, Onew, // new radii
- Rold, rold, Oold; // old radii
-
- private int cvar=200, // variation in color
- svar = 10, // variation in #frames
- redBits, blueBits, greenBits, // current color
- rednew, greennew, bluenew, // new colors
- redold, blueold, greenold, // old colors
- step, // current frame
- steps; // # of frames
-
- private Thread t; // the animation thread
-
- private boolean go, // if paint has drawn new frame, go == true
- mouseUpStopsAnimation = true,
- // this boolean determines wheter mouseUp stops
- // the animation or reset it.
- stopped = false;
-
- private Image osi; // yes, the double buffering image again
-
- /**
- * Constructs a SpiroAnim with 100 lines per frame.
- */
- public SpiroAnim() {
- this(100);
- }
-
- /**
- * Constructs a SpiroAnim with 100 lines per frame.
- * @param mouseUpStopsAnimation if true the animation stops when clicked else resets when clicked
- */
- public SpiroAnim(boolean mouseUpStopsAnimation) {
- this(100, mouseUpStopsAnimation);
- }
-
- /**
- * Constructs a SpiroAnim with the specified number of lines per frame.
- * @param I the number of lines per frame
- */
- public SpiroAnim(int I) {
- this(I, true);
- }
-
- /**
- * Constructs a SpiroAnim with the specified number of lines per frame.
- * @param I the number of lines per frame
- * @param mouseUpStopsAnimation if true the animation stops when clicked else resets when clicked
- */
- public SpiroAnim(int I, boolean mouseUpStopsAnimation) {
- super();
- this.I = (I > 0) ? I : this.I;
- this.mouseUpStopsAnimation = mouseUpStopsAnimation;
- reset();
- enableEvents(AWTEvent.COMPONENT_EVENT_MASK);
- enableEvents(AWTEvent.MOUSE_EVENT_MASK);
- }
-
- /**
- * Starts the animation.
- */
- public void start() {
- if (t == null && !stopped) {
- t = new Thread(this);
- t.setPriority(Thread.MIN_PRIORITY);
- t.start();
- }
- }
-
- /**
- * Stops the animation.
- */
- public void stop() {
- if (t != null) {
- t.stop();
- t = null;
- }
- }
-
- /**
- * Called when the animation is started. Shouldn't be called by user.
- */
- public void run() {
- while (true) {
- try {
- t.sleep(40); // 25 frames per second at maximum speed
- } catch (InterruptedException e) {
- System.out.println(e);
- }
- if (go && isShowing()) {
- nextFrame();
- repaint();
- }
- }
- }
-
- private void nextFrame() {
- if (step == 0) {
-
- Rold = Rnew;
- rold = rnew;
- Oold = Onew;
-
- redold = rednew;
- blueold = bluenew;
- greenold = greennew;
-
- Rnew = (float)Math.max(0.1,
- Math.min(1,
- Rold+((Math.random()-0.5)*Rvar)));
- rnew = (float)Math.max(0.1,
- Math.min(1,
- rold+((Math.random()-0.5)*rvar)));
- Onew = (float)Math.max(0,
- Math.min(1,
- Oold+((Math.random()-0.5)*rvar)));
-
- rednew = Math.max(0,
- Math.min(255,
- redold+(int)((Math.random()-0.5)*cvar)));
- bluenew = Math.max(0,
- Math.min(255,
- blueold+(int)((Math.random()-0.5)*cvar)));
- greennew = Math.max(0,
- Math.min(255,
- greenold+(int)((Math.random()-0.5)*cvar)));
- steps = Math.max(50,
- Math.min(100,
- steps+(int)((Math.random()-0.5)*svar)));
- }
-
- R = Rold + (Rnew-Rold)*step/steps;
- r = rold + (rnew-rold)*step/steps;
- O = Oold + (Onew-Oold)*step/steps;
-
- redBits = redold + (rednew-redold)*step/steps;
- blueBits = blueold + (bluenew-blueold)*step/steps;
- greenBits = greenold + (greennew-greenold)*step/steps;
- go = false;
- step++;
- if (step == steps) {
- step = 0;
- }
- }
-
- /**
- * Update method, calls paint().
- * @param g the graphics object on which is to be drawn
- */
- public void update(Graphics g) {
- paint(g);
- }
-
- /**
- * The paint method draws the spirograph using double buffering.
- * @param g the graphics object on which is to be drawn
- */
- public void paint(Graphics g) {
- if(osi == null) {
- osi = createImage(getSize().width, getSize().height);
- }
- Graphics osg = osi.getGraphics();
- osg.setColor(getBackground());
- osg.fillRect(0,0,getSize().width, getSize().height);
- osg.setColor(g.getColor());
- osg.setClip(0, 0, getSize().width, getSize().height);
-
- int x = 0, xpos = getSize().width/2;
- int y = 0, ypos = getSize().height/2;
- int prevx = 0;
- int prevy = 0;
- int t;
-
- float scalex = getSize().width / (2*(R + O + 2 * r));
- float scaley = getSize().height/ (2*(R + O + 2 * r));
-
- osg.setColor(new Color(redBits, greenBits, blueBits));
-
- for(t=0; t<=I; t++){
- prevx = x;
- prevy = y;
- x = (int)(scalex*((R+r)*Math.cos((double)t)
- - (r+O)*Math.cos(((R+r)/r)*t)));
- y = (int)(scaley*((R+r)*Math.sin((double)t)
- - (r+O)*Math.sin(((R+r)/r)*t)));
-
- if (t > 0){
- osg.drawLine(prevx+xpos, prevy+ypos,
- x+xpos, y+ypos);
- }
- }
- go = true;
- g.drawImage(osi, 0, 0, null);
- osg.dispose();
- }
-
- /**
- * Resets the animation.
- */
-
- public void reset() {
- Rnew = (float)Math.random();
- rnew = (float)Math.random();
- Onew = (float)Math.random();
- rednew = (int)(Math.random()*255);
- greennew = (int)(Math.random()*255);
- bluenew = (int)(Math.random()*255);
- nextFrame();
- repaint();
- step = 0;
- }
-
- /**
- * Invalidate the component. Shouldn't be called by user.
- */
- public void invalidate() {
- super.invalidate();
- osi = null;
- stop();
- }
-
- /**
- * Validate the component. Is called by the system before the component is painted,
- * if it has been invalidated. Shouldn't be called by user.
- */
- public void validate() {
- super.validate();
- start();
- }
-
- /**
- * Notifies the component it has been added to a Container. Shouldn't be called by user.
- */
- public void addNotify() {
- super.addNotify();
- Container p = getParent();
- while (p != null && !(p instanceof Window)) {
- p = p.getParent();
- }
- if (p instanceof Window) {
- ((Window)p).addWindowListener(this);
- }
- start();
- }
-
- /**
- * Notifies the component is has been removed from a component. Shouldn't be called by
- * user.
- */
- public void removeNotify() {
- super.removeNotify();
- Container p = getParent();
- while (p != null && !(p instanceof Window)) {
- p = p.getParent();
- }
- if (p instanceof Window) {
- ((Window)p).removeWindowListener(this);
- }
- stop();
- }
-
- /**
- * Processes ComponentEvents concerning this component. Deals with showing and hiding
- * this component. The SpiroAnim doesn't animate when hidden to save cpu time.
- * @param e The ComponentEvent to be handled.
- */
- protected void processComponentEvent(ComponentEvent e) {
- if (e.getID() == ComponentEvent.COMPONENT_HIDDEN) {
- stop();
- } else if (e.getID() == ComponentEvent.COMPONENT_SHOWN) {
- start();
- }
- }
-
- /**
- * Processes MouseEvents concerning this component. Deals with mouse clicking on this
- * component. The animation starts/stops or resets on mouse click according to
- * configuration.
- * @param e The MouseEvent to be handled.
- */
- protected void processMouseEvent(MouseEvent e) {
- if (e.getID() == MouseEvent.MOUSE_CLICKED) {
- if (mouseUpStopsAnimation) {
- if (stopped) {
- stopped = false;
- start();
- } else {
- stopped = true;
- stop();
- }
- } else {
- reset();
- }
- }
- }
-
- /**
- * Unused WindowListener interface function.
- * @param e The WindowEvent to be handled.
- */
- public void windowOpened(WindowEvent e) {
- }
-
- /**
- * Unused WindowListener interface function.
- * @param e The WindowEvent to be handled.
- */
- public void windowClosing(WindowEvent e) {
- }
-
- /**
- * Unused WindowListener interface function.
- * @param e The WindowEvent to be handled.
- */
- public void windowClosed(WindowEvent e) {
- }
-
- /**
- * Function handles iconification of parent window to stop animation.
- * This save cpu time.
- * @param e The WindowEvent to be handled.
- */
- public void windowIconified(WindowEvent e) {
- stop();
- }
-
- /**
- * Function handles deiconification of parent window to start animation.
- * @param e The WindowEvent to be handled.
- */
- public void windowDeiconified(WindowEvent e) {
- start();
- }
-
- /**
- * Unused WindowListener interface function.
- * @param e The WindowEvent to be handled.
- */
- public void windowActivated(WindowEvent e) {
- }
-
- /**
- * Unused WindowListener interface function.
- * @param e The WindowEvent to be handled.
- */
- public void windowDeactivated(WindowEvent e) {
- }
- }