/**************************************************************** ** Calculus for Kinetic Modeling Mathlet: Reaction Kinetics ** ** Interactive MathVision, Copyright by John Pais 1997-2000. ** ** All Rights Reserved. Created by John Pais, September 2000. ** ****************************************************************/ /** USE EXISTING JAVA CLASSES **/ import java.awt.*; import java.awt.event.*; // Needed for version 1.1 of the AWT. import java.applet.Applet; /** EXTEND THE JAVA APPLET CLASS **/ public class ReactionKinetics extends Applet // Declare some class instance variables: {backgroundChangeButton colorbutton; // backgroundChangeButton (a 2nd class), animatorControlButton controlbutton; // animatorControlButton (a 3rd class), animatorScrollableCanvas animatorCanvas; // animatorScrollableCanvas (a 4th class). int animatorinitframeNumber = -1; Button pinkButton,purpleButton,plumButton, // Declare all the Buttons. skyblueButton,aquaButton,cyanButton, backoneButton,forwardoneButton, stopButton,startButton, fasterButton,slowerButton, scrollLeftButton,scrollRightButton, stopLeftRightButton, scrollUpButton,scrollDownButton, stopUpDownButton, panelUpButton,panelDownButton; boolean scrollLeft,scrollRight, scrollUp,scrollDown, panelUp,panelDown; Font gridBagFont = new Font("TimesRoman",Font.BOLD,20); // The gridBagFont for the FontMetrics gridBagFontm = getFontMetrics(gridBagFont); // top level text. Dimension gridBagPreImageDim; // Define preImage variables needed to Image gridBagPreImage; // create the offscreen copy of the image Graphics gridBagPreImageGraphics; // we want to paint on the screen. Image gifImage[]; // Define an array of gif images and MediaTracker tracker; // a tracker to preload them. Color pink = new Color(234,173,234); // Primary colors used in this applet Color purple = new Color(135,31,120); // and on corresponding web page. Color plum = new Color(127,0,127); Color skyblue = new Color(112,147,219); Color aqua = new Color(56,176,222); Color richblue = new Color(63,0,255); Color newmidnightblue = new Color(0,0,156); Color starblue = new Color(0,100,255); Color darkblue = new Color(0,0,80); Color hotpink = new Color(255,28,174); // Several additional colors to try. Color neonpink = new Color(255,110,199); Color turquoise = new Color(56,147,219); Color aquamarine = new Color(112,219,147); Color chocolate = new Color(92,51,23); Color blueviolet = new Color(159,95,159); Color darkgreen = new Color(74,118,110); Color darkorchid = new Color(153,50,205); Color firebrick = new Color(142,35,35); Color forestgreen = new Color(35,142,35); Color huntergreen = new Color(33,94,33); Color limegreen = new Color(50,205,50); Color mandarinorange = new Color(228,120,51); Color maroon = new Color(142,35,107); Color mediumblue = new Color(50,50,205); Color mediumorchid = new Color(147,112,219); Color mediumslateblue = new Color(127,0,255); Color mediumturquoise = new Color(112,219,219); Color mediumvioletred = new Color(219,112,147); Color midnightblue = new Color(47,47,79); Color navyblue = new Color(35,35,142); Color neonblue = new Color(77,77,255); Color brightgold = new Color(217,217,25); Color orchid = new Color(219,112,219); //Color richblue = new Color(89,89,171); Color seagreen = new Color(35,142,104); //Color skyblue = new Color(50,153,204); Color slateblue = new Color(0,127,255); Color springgreen = new Color(0,255,127); Color lightturquoise = new Color(173,234,234); Color violetred = new Color(204,50,153); Color verydarkbrown = new Color(92,64,51); public void init() {setBackground(purple); String str; gifImage = new Image[127]; //gifImage = new Image[170]; //gifImage = new Image[168]; //gifImage = new Image[165]; //gifImage = new Image[111]; tracker = new MediaTracker(this); // Spawn the tracker background thread(s) // in order to preload the images. gifImage[0] = getImage(getCodeBase(),"images/RK1pnl1.gif"); // Panel 1. tracker.addImage(gifImage[0],0); gifImage[1] = getImage(getCodeBase(),"images/RK1pnl2.gif"); // Panel 2. tracker.addImage(gifImage[1],0); for (int i = 1; i <= 31; i++) {gifImage[i+1] = getImage(getCodeBase(),"images/RK1pnl3"+i+".gif"); // Panel 3. tracker.addImage(gifImage[i+1],0); gifImage[31+i+1] = getImage(getCodeBase(),"images/RK1pnl4"+i+".gif"); // Panel 4. tracker.addImage(gifImage[31+i+1],0); } for (int i = 1; i <= 10; i++) {gifImage[63+i] = getImage(getCodeBase(),"images/RK2pnl1a.gif"); // Panel 5. tracker.addImage(gifImage[63+i],0); gifImage[73+i] = getImage(getCodeBase(),"images/RK2pnl1b.gif"); tracker.addImage(gifImage[73+i],0); } gifImage[84] = getImage(getCodeBase(),"images/RK2pnl2.gif"); // Panel 6. tracker.addImage(gifImage[84],0); for (int i = 1; i <= 41; i++) {gifImage[84+i] = getImage(getCodeBase(),"images/RK2pnl3"+i+".gif"); // Panel 7. tracker.addImage(gifImage[84+i],0); } gifImage[126] = getImage(getCodeBase(),"images/RK2pnl4.gif"); // Panel 8. tracker.addImage(gifImage[126],0); /* for (int i = 1; i <= 80; i++) // This loop codes the first 80 images for Panel 1 {j = (i - (i % 20))/20; // into an array of 108 images with extra padded if (i % 20 == 0) // images at the important transition frames. {gifImage[i+(j-1)*7+4] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+(j-1)*7+4],0); gifImage[i+(j-1)*7+5] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+(j-1)*7+4],0); gifImage[i+(j-1)*7+6] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+(j-1)*7+4],0); } else if (i % 20 == 1) {gifImage[i+j*7-1] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+j*7-1],0); gifImage[i+j*7] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+j*7],0); gifImage[i+j*7+1] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+j*7+1],0); } else if ( (1 < i % 20) && (i % 20 < 10)) {gifImage[i+j*7+1] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+j*7+1],0); } else if (i % 20 == 10) {gifImage[i+j*7+1] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+j*7+1],0); gifImage[i+j*7+2] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+j*7+2],0); gifImage[i+j*7+3] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+j*7+3],0); gifImage[i+j*7+4] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+j*7+4],0); } else if (i % 20 < 20) {gifImage[i+j*7+4] = getImage(getCodeBase(),"images/rpfpnl1"+i+".gif"); tracker.addImage(gifImage[i+j*7+4],0); } } gifImage[108] = getImage(getCodeBase(),"images/rpfpnl21.gif"); // Panel 2. tracker.addImage(gifImage[108],0); gifImage[109] = getImage(getCodeBase(),"images/rpfpnl31.gif"); // Panel 3. tracker.addImage(gifImage[109],0); gifImage[110] = getImage(getCodeBase(),"images/rpfpnl32.gif"); tracker.addImage(gifImage[110],0); for (int i = 1; i <= 40; i++) // Panel 4. {j = (i - (i % 20))/20; if (i % 20 == 0) {gifImage[111+i+(j-1)*7+4] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+(j-1)*7+4],0); gifImage[111+i+(j-1)*7+5] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+(j-1)*7+4],0); gifImage[111+i+(j-1)*7+6] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+(j-1)*7+4],0); } else if (i % 20 == 1) {gifImage[111+i+j*7-1] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+j*7-1],0); gifImage[111+i+j*7] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[i+j*7],0); gifImage[111+i+j*7+1] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+j*7+1],0); } else if ( (1 < i % 20) && (i % 20 < 10)) {gifImage[111+i+j*7+1] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+j*7+1],0); } else if (i % 20 == 10) {gifImage[111+i+j*7+1] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+j*7+1],0); gifImage[111+i+j*7+2] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+j*7+2],0); gifImage[111+i+j*7+3] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+j*7+3],0); gifImage[111+i+j*7+4] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+j*7+4],0); } else if (i % 20 < 20) {gifImage[111+i+j*7+4] = getImage(getCodeBase(),"images/rpfpnl4"+i+".gif"); tracker.addImage(gifImage[111+i+j*7+4],0); } } gifImage[165] = getImage(getCodeBase(),"images/rpfpnl51.gif"); // Panel 5. tracker.addImage(gifImage[165],0); gifImage[166] = getImage(getCodeBase(),"images/rpfpnl52.gif"); tracker.addImage(gifImage[166],0); gifImage[167] = getImage(getCodeBase(),"images/rpfpnl53.gif"); tracker.addImage(gifImage[167],0); gifImage[168] = getImage(getCodeBase(),"images/rpfpnl61.gif"); // Panel 6. tracker.addImage(gifImage[168],0); gifImage[169] = getImage(getCodeBase(),"images/rpfpnl62.gif"); tracker.addImage(gifImage[169],0); */ GridBagLayout gridBag = new GridBagLayout(); // Define a GridBagLayout GridBagConstraints constraints = new GridBagConstraints(); // and GridBagConstraints. setLayout(gridBag); // Note that it is DIFFICULT // to understand the total /*************************************************** // cumulative effect of ** DEFAULT VALUES OF GridBagConstraints // several components and *************************************************** // their constraints. ** constraints.anchor = GridBagConstraints.CENTER; [EAST,NORTH,NORTHEAST,NORTHWEST,etc.] ** constraints.fill = GridBagConstraints.NONE; [BOTH,HORIZONTAL,VERTICAL] ** constraints.gridx = GridBagConstraints.RELATIVE; [0,1,2,3,4,etc.] ** constraints.gridy = GridBagConstraints.RELATIVE; [0,1,2,3,4,etc.] ** constraints.gridwidth = 1; [RELATIVE,REMAINDER,1,2,3,4,etc.] ** constraints.gridheight = 1; [RELATIVE,REMAINDER,1,2,3,4,etc.] ** constraints.ipadx = 0; [1,2,3,4,etc.] ** constraints.ipady = 0; [1,2,3,4,etc.] ** constraints.insets = new Insets(0,0,0,0); [1,2,3,4,etc.] ** constraints.weightx = 0.0; [floats] ** constraints.weighty = 0.0; [floats] ***************************************************/ /******************************************************************************************************* ** GridBagConstraints for backgroundChangeButtons and Animation animatorContolButtons (Begin First Row) *******************************************************************************************************/ constraints.anchor = GridBagConstraints.CENTER; constraints.fill = GridBagConstraints.BOTH; // Fill grid cell in both directions. constraints.gridx = GridBagConstraints.RELATIVE; constraints.gridy = GridBagConstraints.RELATIVE; constraints.gridwidth = 1; constraints.gridheight = 1; constraints.ipadx = 0; constraints.ipady = 0; //constraints.insets = new Insets(2,2,2,2); // Space 2 pixels between buttons. constraints.weightx = 1.0; // Use one grid cell per button in first row. constraints.weighty = 0.0; constraints.insets = new Insets(2,25,2,2); backoneButton = new Button("Back One"); // Create and position the labeled buttons in controlbutton = new animatorControlButton(this); // order of desired layout, register the Button backoneButton.addActionListener(controlbutton); // ActionListeners, and add the Buttons to the gridBag.setConstraints(backoneButton,constraints); // GridBagLayout. add(backoneButton); constraints.insets = new Insets(2,2,2,2); forwardoneButton = new Button("Forward One"); controlbutton = new animatorControlButton(this); forwardoneButton.addActionListener(controlbutton); gridBag.setConstraints(forwardoneButton,constraints); add(forwardoneButton); constraints.insets = new Insets(2,2,2,2); stopButton = new Button("Stop"); controlbutton = new animatorControlButton(this); stopButton.addActionListener(controlbutton); gridBag.setConstraints(stopButton,constraints); add(stopButton); constraints.insets = new Insets(2,2,2,2); startButton = new Button("Start"); controlbutton = new animatorControlButton(this); startButton.addActionListener(controlbutton); gridBag.setConstraints(startButton,constraints); add(startButton); constraints.insets = new Insets(2,2,2,2); fasterButton = new Button("Faster"); controlbutton = new animatorControlButton(this); fasterButton.addActionListener(controlbutton); gridBag.setConstraints(fasterButton,constraints); add(fasterButton); constraints.insets = new Insets(2,2,2,25); slowerButton = new Button("Slower"); controlbutton = new animatorControlButton(this); slowerButton.addActionListener(controlbutton); gridBag.setConstraints(slowerButton,constraints); add(slowerButton); constraints.insets = new Insets(2,2,2,2); pinkButton = new Button("Pink"); colorbutton = new backgroundChangeButton(this,pink); pinkButton.addActionListener(colorbutton); gridBag.setConstraints(pinkButton,constraints); add(pinkButton); constraints.insets = new Insets(2,2,2,2); purpleButton = new Button("Purple"); colorbutton = new backgroundChangeButton(this,purple); purpleButton.addActionListener(colorbutton); gridBag.setConstraints(purpleButton,constraints); add(purpleButton); constraints.insets = new Insets(2,2,2,2); plumButton = new Button("Dark Purple"); colorbutton = new backgroundChangeButton(this,plum); plumButton.addActionListener(colorbutton); gridBag.setConstraints(plumButton,constraints); add(plumButton); constraints.insets = new Insets(2,2,2,2); cyanButton = new Button("Cyan"); colorbutton = new backgroundChangeButton(this,Color.cyan); cyanButton.addActionListener(colorbutton); gridBag.setConstraints(cyanButton,constraints); add(cyanButton); constraints.insets = new Insets(2,2,2,2); aquaButton = new Button("Aqua"); colorbutton = new backgroundChangeButton(this,aqua); aquaButton.addActionListener(colorbutton); gridBag.setConstraints(aquaButton,constraints); add(aquaButton); /****************************************************** ** GridBagConstraints for Cyan button (End First Row) ******************************************************/ constraints.anchor = GridBagConstraints.CENTER; constraints.fill = GridBagConstraints.BOTH; // Fill each grid cell in both directions. constraints.gridx = GridBagConstraints.RELATIVE; constraints.gridy = GridBagConstraints.RELATIVE; constraints.gridwidth = GridBagConstraints.REMAINDER; // End the first row with this button. constraints.gridheight = 1; constraints.ipadx = 0; constraints.ipady = 0; //constraints.insets = new Insets(2,2,2,2); // Space 2 pixels between buttons. constraints.weightx = 1.0; // Use one grid cell per button in current row. constraints.weighty = 0.0; constraints.insets = new Insets(2,2,2,25); skyblueButton = new Button("Sky Blue"); colorbutton = new backgroundChangeButton(this,skyblue); skyblueButton.addActionListener(colorbutton); gridBag.setConstraints(skyblueButton,constraints); add(skyblueButton); /******************************************************************* ** GridBagConstraints for ScrollPane (Begin Second and Third Rows) *******************************************************************/ constraints.anchor = GridBagConstraints.CENTER; constraints.fill = GridBagConstraints.BOTH; // Fill each grid cell in both directions. constraints.gridx = GridBagConstraints.RELATIVE; constraints.gridy = GridBagConstraints.RELATIVE; constraints.gridwidth = GridBagConstraints.REMAINDER; // End the second row with this ScrollPane. constraints.gridheight = 2; // Set height to span rows 2 and 3. constraints.ipadx = 0; constraints.ipady = 0; constraints.insets = new Insets(5,5,5,5); // Space 5 pixels. constraints.weightx = 0.0; constraints.weighty = 1.0; // Since this ScrollPane spans rows 2 and 3, this // weighty value gets assigned to row 3. /********************************************************************************************* ** NOTE that the SCROLLBARS are not used in the ScrollPane, since vertical and horizontal ** ** change events flashed terribly when viewed using either Nescape Communicator 4.05 or MS ** ** Explorer 4.0, in spite of the fact that everything looked lovely in the Applet viewer. ** *********************************************************************************************/ ScrollPane scrollPane = new ScrollPane(ScrollPane.SCROLLBARS_NEVER); animatorCanvas = new animatorScrollableCanvas(this,gifImage,animatorinitframeNumber); animatorCanvas.setBackground(richblue); scrollPane.add(animatorCanvas); // Add animatorScrollableCanvas to ScrollPane gridBag.setConstraints(scrollPane,constraints); // and then add ScrollPane to GridBagLayout. add(scrollPane); // Event Listeners for ScrollPane are // implemented automatically in 1.1 AWT. /* animatorCanvas = new animatorScrollableCanvas(this,gifImage,animatorinitframeNumber); animatorCanvas.setBackground(richblue); gridBag.setConstraints(animatorCanvas,constraints); add(animatorCanvas); */ /***************************************************************************** ** GridBagConstraints for Scrolling animatorContolButtons (Begin Fourth Row) *****************************************************************************/ constraints.anchor = GridBagConstraints.CENTER; constraints.fill = GridBagConstraints.BOTH; // Fill grid cell in both directions. constraints.gridx = GridBagConstraints.RELATIVE; constraints.gridy = GridBagConstraints.RELATIVE; //constraints.gridwidth = 2; constraints.gridheight = 1; constraints.ipadx = 0; constraints.ipady = 0; //constraints.insets = new Insets(2,2,2,2); // Space 2 pixels between buttons. constraints.weightx = 1.0; // Use one grid cell per button in first row. constraints.weighty = 0.0; constraints.gridwidth = 1; constraints.insets = new Insets(2,25,2,2); scrollLeftButton = new Button("Scroll Left"); controlbutton = new animatorControlButton(this); scrollLeftButton.addActionListener(controlbutton); gridBag.setConstraints(scrollLeftButton,constraints); add(scrollLeftButton); constraints.gridwidth = 1; constraints.insets = new Insets(2,2,2,2); stopLeftRightButton = new Button("Stop Scrolling"); controlbutton = new animatorControlButton(this); stopLeftRightButton.addActionListener(controlbutton); gridBag.setConstraints(stopLeftRightButton,constraints); add(stopLeftRightButton); constraints.gridwidth = 2; constraints.insets = new Insets(2,2,2,2); scrollRightButton = new Button("Scroll Right"); controlbutton = new animatorControlButton(this); scrollRightButton.addActionListener(controlbutton); gridBag.setConstraints(scrollRightButton,constraints); add(scrollRightButton); constraints.gridwidth = 2; constraints.insets = new Insets(2,25,2,2); panelUpButton = new Button("Panel Up"); controlbutton = new animatorControlButton(this); panelUpButton.addActionListener(controlbutton); gridBag.setConstraints(panelUpButton,constraints); add(panelUpButton); constraints.gridwidth = 2; constraints.insets = new Insets(2,2,2,2); panelDownButton = new Button("Panel Down"); controlbutton = new animatorControlButton(this); panelDownButton.addActionListener(controlbutton); gridBag.setConstraints(panelDownButton,constraints); add(panelDownButton); constraints.gridwidth = 1; constraints.insets = new Insets(2,25,2,2); scrollUpButton = new Button("Scroll Up"); controlbutton = new animatorControlButton(this); scrollUpButton.addActionListener(controlbutton); gridBag.setConstraints(scrollUpButton,constraints); add(scrollUpButton); constraints.gridwidth = 2; constraints.insets = new Insets(2,2,2,2); stopUpDownButton = new Button("Stop Scrolling"); controlbutton = new animatorControlButton(this); stopUpDownButton.addActionListener(controlbutton); gridBag.setConstraints(stopUpDownButton,constraints); add(stopUpDownButton); /************************************************************** ** GridBagConstraints for Scroll Down button (End Fourth Row) **************************************************************/ constraints.anchor = GridBagConstraints.CENTER; constraints.fill = GridBagConstraints.BOTH; // Fill each grid cell in both directions. constraints.gridx = GridBagConstraints.RELATIVE; constraints.gridy = GridBagConstraints.RELATIVE; constraints.gridwidth = GridBagConstraints.REMAINDER; // End the first row with this button. constraints.gridheight = 1; constraints.ipadx = 0; constraints.ipady = 0; //constraints.insets = new Insets(2,2,2,2); // Space 2 pixels between buttons. constraints.weightx = 1.0; // Use one grid cell per button in current row. constraints.weighty = 0.0; constraints.insets = new Insets(2,2,2,25); scrollDownButton = new Button("Scroll Down"); controlbutton = new animatorControlButton(this); scrollDownButton.addActionListener(controlbutton); gridBag.setConstraints(scrollDownButton,constraints); add(scrollDownButton); } public Insets getInsets() // Set all (top, left, bottom, right) {return new Insets(40,2,40,2);} // outer boundary insets of GridBagLayout: // 40 pixels on top and 40 on bottom for // identification/user-instruction text, // and 2 pixels at left and at right. public void start() {animatorCanvas.start();} public void stop() {animatorCanvas.stop();} public void backoneButtonMethod() {animatorCanvas.backoneButtonMethod();} public void forwardoneButtonMethod() {animatorCanvas.forwardoneButtonMethod();} public void startButtonMethod() {animatorCanvas.startButtonMethod();} public void stopButtonMethod() {animatorCanvas.stopButtonMethod();} public void fasterButtonMethod() {animatorCanvas.fasterButtonMethod();} public void slowerButtonMethod() {animatorCanvas.slowerButtonMethod();} public void scrollingCanvasMethod() {animatorCanvas.scrollingCanvasMethod();} public void stopscrollingCanvasMethod() {animatorCanvas.stopscrollingCanvasMethod();} public void panelUpDownMethod() {animatorCanvas.panelUpDownMethod();} /** CREATE THE CURRENT GRIDBAG FRAME **/ public void paint(Graphics g) // This technique of painting by calling {update(g);} // update, prevents the default (and hidden) // behavior of update, and instead allows public void update(Graphics g) // the creation of an offscreen gridBagPreImage {Dimension d = size(); // before painting the screen. if ((gridBagPreImageGraphics == null) || // When all images are loaded, compare (d.width != gridBagPreImageDim.width) || // the current applet viewing size to (d.height != gridBagPreImageDim.height)) // our gridBagPreImage, and if different, {gridBagPreImageDim = d; // resize our next gridBagPreImage. gridBagPreImage = createImage(d.width,d.height); gridBagPreImageGraphics = gridBagPreImage.getGraphics(); } gridBagPreImageGraphics.setColor(getBackground()); // Clear the previous gridBagPreImage gridBagPreImageGraphics.fillRect(0,0,d.width,d.height); // by filling with the current // background. gridBagPreImageGraphics.setFont(gridBagFont); String toptext = "CKM Mathlet: Reaction Kinetics"; String bottext = "pais@interactive-mathvision.com"; int topxstart = (size().width - gridBagFontm.stringWidth(toptext))/2; int botxstart = (size().width - gridBagFontm.stringWidth(bottext))/2; int fontA = gridBagFontm.getAscent(); // Contrary to the usual int fontD = gridBagFontm.getDescent(); // description, the Ascent int fontL = gridBagFontm.getLeading(); // of a font contains white // space at the top. int fontAwhite = fontD - fontL; // The Ascent white space. int fontAtext = fontA - fontAwhite; // The Ascent text space. int fonttext = fontAtext + fontD; // The actual text space. int topyspacing = (40 - fonttext)/2; // Compute vertical spacing. int botyspacing = (44 - fonttext)/2; int topystart = topyspacing -2 + fonttext; int botystart = (size().height -44) + botyspacing + fonttext; gridBagPreImageGraphics.setColor(newmidnightblue); gridBagPreImageGraphics.drawString(toptext,topxstart,topystart); gridBagPreImageGraphics.drawString(bottext,botxstart,botystart); // Offscreen preImage completed. g.drawImage(gridBagPreImage,0,0,this); // Paint preImage on the screen. } } /*********************************************** ** END OF 1ST CLASS: ReactionKinetics ** *********************************************** ** BEGIN 2ND CLASS: backgroundChangeButton ** ***********************************************/ class backgroundChangeButton implements ActionListener {Color newBackgroundColor; ReactionKinetics callingApplet; backgroundChangeButton(ReactionKinetics methodArg, Color newColor) {callingApplet = methodArg; newBackgroundColor = newColor; } public void actionPerformed(ActionEvent evt) // Uses version 1.1 of the AWT. {if (evt.getSource() instanceof Button) {if((evt.getSource() == callingApplet.pinkButton) || (evt.getSource() == callingApplet.purpleButton) || (evt.getSource() == callingApplet.plumButton) || (evt.getSource() == callingApplet.skyblueButton) || (evt.getSource() == callingApplet.aquaButton) || (evt.getSource() == callingApplet.cyanButton)) {callingApplet.setBackground(newBackgroundColor); callingApplet.repaint(); } } } } /********************************************* ** END 2ND CLASS: backgroundChangeButton ** ********************************************* ** BEGIN 3RD CLASS: animatorControlButton ** *********************************************/ class animatorControlButton implements ActionListener {ReactionKinetics callingApplet; animatorControlButton(ReactionKinetics methodArg) {callingApplet = methodArg;} public void actionPerformed(ActionEvent evt) {if (evt.getSource() instanceof Button) {if (evt.getSource() == callingApplet.backoneButton) callingApplet.backoneButtonMethod(); else if (evt.getSource() == callingApplet.forwardoneButton) callingApplet.forwardoneButtonMethod(); else if (evt.getSource() == callingApplet.stopButton) callingApplet.stopButtonMethod(); else if (evt.getSource() == callingApplet.startButton) callingApplet.startButtonMethod(); else if (evt.getSource() == callingApplet.fasterButton) callingApplet.fasterButtonMethod(); else if (evt.getSource() == callingApplet.slowerButton) callingApplet.slowerButtonMethod(); else {callingApplet.scrollLeft = false; callingApplet.scrollRight = false; callingApplet.scrollUp = false; callingApplet.scrollDown = false; callingApplet.panelUp = false; callingApplet.panelDown = false; if (evt.getSource() == callingApplet.scrollLeftButton) {callingApplet.scrollLeft = true; callingApplet.scrollingCanvasMethod(); } else if (evt.getSource() == callingApplet.scrollRightButton) {callingApplet.scrollRight = true; callingApplet.scrollingCanvasMethod(); } else if (evt.getSource() == callingApplet.scrollUpButton) {callingApplet.scrollUp = true; callingApplet.scrollingCanvasMethod(); } else if (evt.getSource() == callingApplet.scrollDownButton) {callingApplet.scrollDown = true; callingApplet.scrollingCanvasMethod(); } else if (evt.getSource() == callingApplet.stopLeftRightButton) callingApplet.stopscrollingCanvasMethod(); else if (evt.getSource() == callingApplet.stopUpDownButton) callingApplet.stopscrollingCanvasMethod(); else if (evt.getSource() == callingApplet.panelUpButton) {callingApplet.panelUp = true; callingApplet.panelUpDownMethod(); } else if (evt.getSource() == callingApplet.panelDownButton) {callingApplet.panelDown = true; callingApplet.panelUpDownMethod(); } } } } } /*********************************************** ** END 3RD CLASS: backgroundChangeButton ** *********************************************** ** BEGIN 4TH CLASS: animatorScrollableCanvas ** ***********************************************/ class animatorScrollableCanvas extends Canvas implements Runnable {ReactionKinetics callingApplet; Image[] image; int frameNumber; int saveframeNumber; //Dimension preferredSize = new Dimension(815, 1819); // Panels 1-12 //Dimension preferredSize = new Dimension(815, 1519); // Panels 1-10 Dimension preferredSize = new Dimension(815, 1219); // Panels 1-8 //Dimension preferredSize = new Dimension(815, 919); // Panels 1-6 //Dimension preferredSize = new Dimension(815, 619); // Panels 1-4 //Dimension preferredSize = new Dimension(815, 319); // Panels 1-2 Dimension minimumSize = new Dimension(10, 10); //int delayBetweenFrames = 200; // milisecond delay between frames. int delayBetweenFrames = 400; int savedelayBetweenFrames; int displayframeNumber; int displayFrameH = 0; int displayFrameV = 0; boolean scrolling = false; Thread animatorThread; boolean frozen = false; Font waitfont=new Font("TimesRoman",Font.BOLD,14); FontMetrics waitfontm = getFontMetrics(waitfont); String waitstr1, waitstr2 = ""; Font panelfont = new Font("TimesRoman",Font.PLAIN,12); FontMetrics panelfontm = getFontMetrics(panelfont); Dimension preImageDim; // Define preImage variables needed to Image preImage; // create the offscreen copy of the image Graphics preImageGraphics; // we want to paint on the canvas. animatorScrollableCanvas(ReactionKinetics methodArg, Image[] img, int frameNum) {callingApplet = methodArg; image = img; frameNumber = frameNum; } public Dimension getMinimumSize() {return minimumSize;} public Dimension getPreferredSize() {return preferredSize;} /** CLICK TO START OR STOP THE ANIMATOR SCROLLABLE CANVAS **/ public boolean mouseDown(Event e, int x, int y) {if (!scrolling) {if (frozen) {frozen = false; start(); } else {frozen = true; animatorThread = null; // Instead of calling stop() here, since } // stop() now nullifies our preImage context, } // nullify only the animation thread in case else if (scrolling) stopscrollingCanvasMethod(); return true; } public void backoneButtonMethod() {if (!scrolling) {if (!frozen) {frozen = true; animatorThread = null; } /* frameNumber--; // These 8 lines of code remove the if (frameNumber % 27 == 1) frameNumber -= 2; // frame padding. Here we remove 2 else if (frameNumber % 27 == 0) frameNumber -= 1; // extra padded frames. else if (frameNumber % 27 == 13) frameNumber -= 3; // Here we remove 3 extra padded frames. else if (frameNumber % 27 == 12) frameNumber -= 2; // else if (frameNumber % 27 == 11) frameNumber -= 1; // else if (frameNumber % 27 == 25) frameNumber -= 2; // Here we remove 2 extra padded frames. else if (frameNumber % 27 == 24) frameNumber -= 1; // if (frameNumber == -1) frameNumber = 107; // // frameNumber--; // These 2 lines of code may be used // if (frameNumber == -1) frameNumber = 107; // if you don't want to remove padding. */ frameNumber--; if (frameNumber == -1) frameNumber = 0; repaint(); } } public void forwardoneButtonMethod() {if (!scrolling) {if (!frozen) {frozen = true; animatorThread = null; } /* frameNumber = (frameNumber + 1) % 108; // This line *alone* displays padded frames. // Including these 7 lines below removes the if (frameNumber % 27 == 1) frameNumber += 2; // frame padding. Here we remove 2 extra else if (frameNumber % 27 == 2) frameNumber += 1; // padded frames. else if (frameNumber % 27 == 12) frameNumber += 3; // Here we remove 3 extra padded frames. else if (frameNumber % 27 == 13) frameNumber += 2; // else if (frameNumber % 27 == 14) frameNumber += 1; // else if (frameNumber % 27 == 25) frameNumber += 2; // Here we remove 2 extra padded frames. else if (frameNumber % 27 == 26) frameNumber += 1; // */ frameNumber++; repaint(); } } public void startButtonMethod() {if (!scrolling) {if (frozen) {frozen = false; start(); } } } public void stopButtonMethod() {if (!scrolling) {if (!frozen) {frozen = true; animatorThread = null; } } } public void fasterButtonMethod() {if (!scrolling) {if (!frozen) {frozen = true; animatorThread = null; } delayBetweenFrames = Math.max(25,delayBetweenFrames-25); frozen = false; start(); } } public void slowerButtonMethod() {if (!scrolling) {if (!frozen) {frozen = true; animatorThread = null; } delayBetweenFrames = Math.min(600,delayBetweenFrames+25); frozen = false; start(); } } public void scrollingCanvasMethod() {if (!scrolling) {scrolling = true; if (!frozen) {frozen = true; animatorThread = null; } saveframeNumber = frameNumber; savedelayBetweenFrames = delayBetweenFrames; delayBetweenFrames = 10; frozen = false; start(); } } public void stopscrollingCanvasMethod() {if (scrolling) {scrolling = false; if (!frozen) {frozen = true; animatorThread = null; } frameNumber = saveframeNumber; delayBetweenFrames = savedelayBetweenFrames; } } public void panelUpDownMethod() {scrollingCanvasMethod();} /** GENERATE AND/OR START THE ANIMATOR SCROLLABLE CANVAS ANIMATION THREAD **/ public void start() {if (frozen) { } // The animation is supposed to stay frozen. else // Otherwise, generate and/or start the {if (animatorThread == null) // animation thread. Apparently, if run {animatorThread = new Thread(this);} // breaks after catching an exception, animatorThread.start(); // the animatorThread though not null } // will still need to be restarted. } /** STOP THE ANIMATOR SCROLLABLE CANVAS ANIMATION THREAD **/ public void stop() {animatorThread = null; // The user either clicked to stop or left the page, preImageGraphics = null; // so wipe out the current thread and preImage context. preImage = null; } /** CREATE AND DISPLAY FRAMES OF THE ANIMATOR SCROLLABLE CANVAS ANIMATION THREAD **/ public void run() {try // Start loading the images and {callingApplet.tracker.waitForAll();} // wait until done before starting catch (InterruptedException e) {} // the animation. Thread.currentThread().setPriority(Thread.MIN_PRIORITY); // Set the priority low. long startTime = System.currentTimeMillis(); // Remember start time. while (Thread.currentThread() == animatorThread) // The animation loop. {frameNumber++; // Advance the frame number. repaint(); try // Sleep for the delay period. {startTime += delayBetweenFrames; Thread.sleep(Math.max(0, startTime-System.currentTimeMillis())); } catch (InterruptedException e) {break;} // In case the try caused } // something strange, exit } // the while loop. /** CREATE THE CURRENT FRAME OF THE ANIMATOR SCROLLABLE CANVAS ANIMATION THREAD **/ public void paint(Graphics g) // This technique of painting by calling {update(g);} // update, prevents the default (and hidden) // behavior of update, and instead allows public void update(Graphics g) // the creation of an offscreen preImage {Dimension d = size(); // before painting the canvas. if (!callingApplet.tracker.checkAll()) // If the images aren't all loaded, then {g.clearRect(0, 0, d.width, d.height); // clear the canvas and notify the user g.setColor(Color.yellow); // to wait. g.setFont(waitfont); waitstr1 = "Loading images, please wait... Depending upon your computer "; waitstr2 = "and/or your connection speed, this may take several minutes..."; g.drawString(waitstr1,25,50); g.drawString(waitstr2,25,50 + waitfontm.getHeight()); } else {if ((preImageGraphics == null) || // When all images are loaded, (d.width != preImageDim.width) || // compare the current applet (d.height != preImageDim.height)) // viewing size to our preImage, {preImageDim = d; // and if different, resize our preImage = createImage(d.width,d.height); // next preImage. preImageGraphics = preImage.getGraphics(); } preImageGraphics.setColor(getBackground()); // Clear the previous preImage preImageGraphics.fillRect(0,0,d.width,d.height); // by filling with the current // background. if (!scrolling) displayframeNumber = frameNumber; else if (scrolling) {displayframeNumber = saveframeNumber; if ((callingApplet.scrollLeft == true) && (displayFrameH < 0)) displayFrameH++; else if ((callingApplet.scrollRight == true) && (displayFrameH > -30)) displayFrameH--; else if ((callingApplet.scrollUp == true)&& (displayFrameV < 0)) displayFrameV++; //else if ((callingApplet.scrollDown == true) && (displayFrameV > -300)) displayFrameV--; //else if ((callingApplet.scrollDown == true) && (displayFrameV > -600)) displayFrameV--; else if ((callingApplet.scrollDown == true) && (displayFrameV > -900)) displayFrameV--; else if ((callingApplet.panelUp == true) && (-900 <= displayFrameV) && (displayFrameV < -600)) {callingApplet.panelUp = false; //displayFrameH = 0; displayFrameV = -600; } else if ((callingApplet.panelUp == true) && // Not the most concise logic (-600 <= displayFrameV) && (displayFrameV < -300)) // for the panelUp and panelDown {callingApplet.panelUp = false; // events. Had a lot of trouble //displayFrameH = 0; // obtaining the desired behavior displayFrameV = -300; // and so this code is somewhat } // kludged. The statments that else if ((callingApplet.panelUp == true) && // reset panelUp/panelDown back (-300 <= displayFrameV) && (displayFrameV <= 0)) // to false are necessary in order {callingApplet.panelUp = false; // to prevent undesired interaction //displayFrameH = 0; // between the various cases, e.g. displayFrameV = 0; // when panelUp is true and displayFrameV } // has just been changed to -300, the else if ((callingApplet.panelDown == true) && // next time through the run method loop (-300 < displayFrameV) && (displayFrameV <= 0)) // displayFrameV is reassigned to 0. {callingApplet.panelDown = false; // Similar comments hold when panelDown //displayFrameH = 0; // is true. To prevent this we can set displayFrameV = -300; // PanelUp/PanelDown to false, so that //g.setColor(getBackground()); // the screen is continually refreshed //g.fillRect(0,300,815,319); } else if ((callingApplet.panelDown == true) && // to the desired Panel as the run (-600 < displayFrameV) && (displayFrameV <= -300)) // method iterates frameNumber, and {callingApplet.panelDown = false; // while displayframeNumber stays fixed //displayFrameH = 0; // at saveframeNumber. displayFrameV = -600; //g.setColor(getBackground()); //g.fillRect(0,300,815,319); // Clear screen bottom. } else if ((callingApplet.panelDown == true) && (-900 <= displayFrameV) && (displayFrameV <= -600)) {callingApplet.panelDown = false; //displayFrameH = 0; displayFrameV = -900; g.setColor(getBackground()); g.fillRect(0,300,815,319); } else stopscrollingCanvasMethod(); } int imageWidth = image[0].getWidth(this); int imageHeight = image[0].getHeight(this); // Panel 1 preImageGraphics.drawImage(image[0],0,12,getBackground(), this); // Panel 2 preImageGraphics.drawImage(image[1],imageWidth+8,12,getBackground(), this); // Panel 3 preImageGraphics.drawImage( image[2+(displayframeNumber % 31)],0,imageHeight+24,getBackground(), this); // Panel 4 preImageGraphics.drawImage( image[33+(displayframeNumber % 31)],imageWidth+8,imageHeight+24,getBackground(), this); // Panel 5 preImageGraphics.drawImage( image[64+(displayframeNumber % 20)],0,2*imageHeight+36,getBackground(), this); // Panel 6 preImageGraphics.drawImage(image[84],imageWidth+8,2*imageHeight+36,getBackground(), this); // Panel 7 preImageGraphics.drawImage( image[85+(displayframeNumber % 41)],0,3*imageHeight+48,getBackground(), this); // Panel 8 preImageGraphics.drawImage(image[126],imageWidth+8,3*imageHeight+48,getBackground(), this); preImageGraphics.setFont(panelfont); preImageGraphics.setColor(Color.white); preImageGraphics.drawString("Panel 1",1,10); preImageGraphics.drawString("Panel 2",imageWidth+9,10); preImageGraphics.drawString("Panel 3",1,imageHeight+22); preImageGraphics.drawString("Panel 4",imageWidth+9,imageHeight+22); preImageGraphics.drawString("Panel 5",1,2*imageHeight+34); preImageGraphics.drawString("Panel 6",imageWidth+9,2*imageHeight+34); preImageGraphics.drawString("Panel 7",1,3*imageHeight+46); preImageGraphics.drawString("Panel 8",imageWidth+9,3*imageHeight+46); g.drawImage(preImage,displayFrameH,displayFrameV,this); } } } /********************************************* ** END 4TH CLASS: animatorScrollableCanvas ** *********************************************/