Scripting the techexplorer Hypermedia Browser

The GraphIT Application


The feature described is only available in the Professional Edition of techexplorer.

This section describes a fictitious on-line course module for understanding the relationship between equations and their graphical representation. This example puts in practice much of the techexplorer Core Java API as well as leverages many of the connections between executable content in a web page.

Before we discuss the details of this example, invoke the Java GraphIT application Click to try the GraphIT course module. to get an overall idea of the layout and workings of the interactive Java applets. In particular notice that when you click on the trig expression display or click/drag on the slider with the mouse, both the trig expression display and the graph above it are updated.

To best understand the discussion of this example, the reader should have some understanding of how to implement Java GUI components, know a little about JavaScript, know how to create techexplorer content that can be scripted by both Netscape and Internet Explorer using the <EMBED> and <OBJECT> tags, and understand the Java 1.1 event handling model. It may also help the reader to have copies of the Java source code for the GraphIT and GraphITControl applets for referral while studying this document. The HTML source for the example may also be helpful. The latter can be obtained by going to the GraphIT example web page by pressing the techexplorer example button above and then using the facility of your browser that displays the HTML source code for the page being rendered by the browser.

We begin our explanation of the implementation of this example by focusing on the several components of the GraphIT module: the LaTeX material for the course module, the GraphIT applet, the GraphITControl applet, and the techexplorer trig expression display area. First, let us look at a diagram that shows the overall layout of the browser window.

GraphIT Application Page Layout
Standard HTML display of title and Logo
(1) techexplorer display of introductory mathematical text
(2) techexplorer display of three paragraphs of mathematical text (3) Java Applet GraphIT
(4) techexplorer display of mathematical expressions for trig functions to be graphed
(5) Java Applet GraphITControl
Standard HTML display of navigation buttons and trademark info

Three of the regions, denoted (1), (2), and (4), in the diagram above contain techexplorer displays. The first two are used for formatting the LaTeX text that describes the module. The GraphIT applet, denoted (3) above, plots the trig curves and is controlled remotely by the GraphITControl applet, denoted as (5). The GraphITControl applet displays a slider and provides our first examples of inter-applet communication and techexplorer event listeners using the techexplorer event listener interface. The third techexplorer display region, denoted (4) above, is used to dynamically render the mathematical expressions for the trig functions as they change. It is also the object that fires the techexplorer events for which the GraphITControl applet listens.

The key new ideas in this example are (a) the communication that is needed between the GraphIT applet and the GraphITControl applet (that is, inter-applet communication), (b) the communication that is needed between the GraphITControl applet and the techexplorer trig function display, and (c) the use of the Java interfaces in the techexplorer event listener classes that are needed to implement (b). Consequently, our discussion will concentrate on these three topics.

At this point the reader should clearly fix in his/her mind exactly which component is referred to by each of the three labels: the GraphIT applet, the GraphITControl applet, and the techexplorer trig function display. To do this, refer again, if necessary, to the diagram above (they are components denoted (3), (5), and (4) respectively in the diagram) and/or to the full-blown display. Click to try the GraphIT course module.

The GraphIT Java applet

The GraphIT applet plots the trig curves.



The implementation of the GraphIT applet is a standard Java GUI implementation and the details will not be discussed here. The reader can find more information on how to implement such Java components in any one of the many fine Java references that are available. Two excellent references are The Java Tutorial , an online book by Mary Campione and Kathy Walrath, and Core Java, volumes I and II by Cay Horstmann and Gary Cornell.

There are, however, two methods in the GraphIT applet that are crucial to the communication between the GraphIT and GraphITControl applets so we need to highlight them. They are setParam() and setCurve(). The GraphIT applet graphs either a cos( nx ) or a sin( nx ) function. The n in these functions is a parameter that can be changed by clicking/dragging the slider so setParam() is used by the GraphITControl applet to update this parameter.

Clicking on the trig function display can change the function being graphed from a cos function to a sin function, or vice versa. The setCurve() method is used by the GraphITControl applet to tell the GraphIT applet about these changes. The code looks like this:

import java.awt.*;
import java.applet.Applet;

public class GraphIT extends Applet {
  ...

  public void setParam( int p ) {
     trigCurve.setParam( p );
  } 

  public void setCurve( int curveID ) {
     trigCurve.setCurve( curveID );
  } 
}
The GraphITControl applet uses its updateAll() method to update the graph area in response to the user clicking on the techexplorer display for the trig functions or to clicking/dragging the mouse on the slider. It calls the setParam() and setCurve() methods and then invokes repaint(), using its handle to GraphIT, to redraw the graph. This is discussed in more detail in the section below on the GraphITControl applet.

The GraphIT applet implements the following Java classes:
 

Class Description
GraphIT Remotely controlled graphing applet.
TrigCurve Implements an object representing a sin or cos curve.

Click here for the whole program. Note that since some browsers do not support Java 1.1, the GraphIT applet is Java 1.0 compliant.

The techexplorer trig function display

techexplorer trig function display is used to indicate the current equation that is being plotted by the GraphIT applet. techexplorer sends events to the GraphITControl applet. These events are used to toggle between the two trig equations. The equation currently being graphed is displayed in red.

The following HTML embeds the techexplorer trig function display area in a browser window. Here the web browser object name for the ActiveX control instance of techexplorer is "TrigExprControl" while that for the Netscape plugin is "TrigExprPlugin." These names are used by the JavaScript code in the begin() method to send a handle for the techexplorer instance to the GraphITControl applet.

<OBJECT NAME="TrigExprControl" CLASSID="clsid:5AFAB315-AD87-11D3-98BB-002035EFB1A4" 
           WIDTH=292 HEIGHT=100>
   <PARAM NAME="DataType" VALUE="0">
   <PARAM NAME="Data" VALUE="\pagecolor{lightgray}\colorbox{white}
                                {Select:\makebox[1.6in][r]{\color{black}
                                  \begin{eqnarray}
                                     \color{red} y & \color{red}= & \color{red}\sin(10x)\\
                                                 y &            = & \cos(x)
                                  \end{eqnarray}}}">

   <EMBED NAME="TrigExprPlugin" TYPE="application/x-techexplorer"
      TEXDATA="\pagecolor{lightgray}\colorbox{white}
               {Select:\makebox[1.6in][r]{\color{black}
                 \begin{eqnarray}
                    \color{red}y & \color{red}= & \color{red}\sin(10x)\\
                               y &            = & \cos(x)
                 \end{eqnarray}}}"
      WIDTH=292 HEIGHT=100 >
   </EMBED>
</OBJECT>
The above code is found in the JavaScript method displayTexWithName(). For more information on the HTML code needed to create techexplorer content that can be scripted by both Netscape and Internet Explorer, see Creating techexplorer Documents.

The Java interfaces for techexplorer event listeners

The techexplorer event listener interface is used by the GraphITControl applet to implement the event handlers for the events generated by the techexplorer trig function display. So this section gives a general overview of these facilities.

The techexplorer event listener interface provides for the one-to-many dependency between techexplorer and appropriately registered Java event handler objects. A techexplorer listener can be an instance of any Java class that implements the relevant methods in one or more of the techexplorer listener interfaces:

The last interface listed above, the techexplorerListener interface, defines the methods that a Java object must implement to receive notifications for all possible events generated by a techexplorer plug-in instance. This interface is provided as a convenience since a Java object could subclass from each individual event to achieve the same effect as using the techexplorerListener interface.

When a techexplorer display receives an event such as the user clicking the mouse over the display area, all the Java objects that are registered to listen to that particular event are notified through a call to an interface method. A Java object can register as an event handler by using one of the corresponding ibm.techexplorer.techexplorer event listener registration methods:

For future reference, we point out that the two Java classes ibm.techexplorer.plugin.techexplorerPlugin and ibm.techexplorer.control.techexplorerControl are derived from the ibm.techexplorer.techexplorer for the techexplorer plugin and ActiveX control respectively.

The relationship between techexplorer and Java classes that implement a techexplorer listener interface are based on the Observer/Subject paradigm used by the Java 1.1 event model. However, Java 1.1 is not needed in order to use the techexplorer listener mechanism. More information regarding the techexplorer event listener mechanism can be found in the AWTEvent annotated reference.

To prevent dangling references to techexplorer event listeners, the techexplorerPlugin reflection class provides these listener removal methods

Be sure to call these methods when event notification is no longer needed or a Java object is to be destroyed. The InstanceListener interface defines the methods that a Java object must implement to receive notifications that techexplorer is shutting down. These methods can be used by techexplorer listeners to guard against dangling references to a techexplorerPlugin reflection instance.

Current Restriction: In this release, techexplorer Java objects can only listen to events that affect the whole document. However, the ibm.techexplorer.awt.event.MouseEvent has been augmented to provide programmatic access to the Document Object Model tree representation of the document.

The GraphITControl Java applet

The GraphITControl applet has three main tasks: (a) to implement and display a slider object (shown below),
(b) to control the updating of the graphing panel and the techexplorer trig function display, and (c) to handle the events generated by the techexplorer trig function display. The slider is implemented from scratch, but it could have been implemented using the ScrollBar class from the Java 1.0 AWT. However, the given implementation is lighter weight and, hence, more nimble in response to user inputs.

Since the Slider class is a fairly straightforward Java GUI component implementation, we do not discuss it further except to note that it uses the Java 1.0 event handling model (to enable usage by many browsers) for responding to mouse clicks or dragging by the mouse. This is a different model from the one used by the techexplorer that is based on the new Java event handling model introduced in Java 1.1. The two different models, both used in the GraphITControl implementation, could be confusing to the reader if not clearly distinguished. For more information on writing Java GUI classes like the Slider class, see the general Java references given above. For more information about the Java 1.1 model for events and event handling, see the Lesson: Writing Event Handlers from The Java Tutorial. For more information about the Java 1.0, see the first edition of Horstmann and Cornell, Core Java published by Prentice-Hall. See the Slider class in the complete listing of the GraphITControl code for the details of the implementation of this component.

Inter-applet communication

To control the updating of the graph in response to the user clicking on the slider or the trig function display the GraphITControl applet needs to communicate with the GraphIT applet. This is done in the standard way normally employed by Java programs, that is, the GraphITControl applet gets a reference (or handle) to the GraphIT applet so that it can invoke its public methods. The reference is obtained via the Java code
graphITHandle = getAppletContext().getApplet("GraphIT")
as found in the start() method of GraphITControl. The string argument for the getApplet("GraphIT") method must be the same as the value of the NAME attribute given in the APPLET tag for the GraphIT applet on the HTML page as show below.
<APPLET NAME="GraphIT" ARCHIVE="NpExamples.jar" CODE="GraphIT.class" CODEBASE="Java" 
           WIDTH=292 HEIGHT=300>
  <PARAM NAME="cabbase" VALUE="AxExamples.cab">
</APPLET>

There is one complication, however. getApplet() cannot return a reference to the GraphIT applet until the GraphIT applet is loaded (if the applet is not loaded, the method returns null), but the loading/initialization of the GraphIT and GraphITControl applets is done asynchronously. Thus, to insure that getApplet() eventually returns a non-null value, it is embedded in a loop that waits for a non-null value to be returned as is seen below.

  Applet graphITHandle = null;
    ...
  public void start() {
  	do {
       try {
         Thread.sleep(50);          // Give other threads a chance to run, esp the thread
  	   }                            // loading/initializing the GraphIT applet
       catch (InterruptedException e) { };
  	   graphITHandle = getAppletContext().getApplet("GraphIT");
	}
	while(graphITHandle == null);
  }
Once a handle is obtained, the public methods of the GraphIT applet can be invoked to update the graph.

For more information about inter-applet communication, see the section "The Applet Context" in the chapter on Applets in Horstmann and Cornell, volume I .

techexplorer-applet communication

For the GraphITControl applet to control the techexplorer trig function display, several things must be done. First the applet needs a handle to the techexplorer display. Second, using this handle, the applet must register as a listener for mouse clicks on the display. Thirdly, the applet must implement the five methods of the MouseListener interface. Lastly, the implementations of the event handler interface must update the techexplorer trig function display.

Rather than the applet invoking a method to obtain a handle to the techexplorer display, which is an object created by the HTML page, the JavaScript begin() method from the HTML page passes the handle to the applet by invoking either the setPlugin() or the setControl() method of the GraphITControl applet. Here is the code for the begin() method; note the use of the names TrigExprPlugin and TrigExprControl discussed earlier.

	function begin()
    {
        var app = document.applets["GraphITControl"];

        if ( document.TrigExprPlugin )
            app.setPlugin( document.TrigExprPlugin );
        if ( document.TrigExprControl )
		    app.setControl( document.TrigExprControl );
    }
Both setPlugin() and setControl() initialize the texplorer instance variable with the handle passed by JavaScript and then register the applet as a listener for the display. The code for setPlugin() is given below; the code for setControl() is similar.
  public void setPlugin( techexplorer obj )  // Called by the JavaScript code in the HTML
  {                                          // page to provide a handle to the Netscape plugin.
     if ( obj instanceof techexplorer )      // The handle is used to register a listener
        texplorer = obj;                     // on the techexplorer component that displays
                                             // the formulae for the curves that are graphed

     // Register the event listener for the techexplorer trig function display
     texplorer.addMouseListener( (MouseListener)this );
  }
Now, let's look at GraphITControl's implementation of the MouseListener interface. Actually only one method is needed to respond to the mouse clicks, in this case, the mouseRelease() method. Its implementation decides which equation is being selected by the user in the techexplorer trig function display and then calls updateAll() to update the graph panel and the techexplorer trig function display. The other methods simply appear with empty bodies. Here is the code for implementing the interface.
  public void mouseClicked( MouseEvent e ) { }
  public void mouseEntered( MouseEvent e ) { }
  public void mouseExited( MouseEvent e )  { }
  public void mousePressed( MouseEvent e ) { }
  public void mouseRelease( MouseEvent e ) {
    Dimension d = size();               // Get size of techexplorer display
    int y = e.getY();                   // Get y coordinate of mouse click
    if (y < 3*d.height/5){              // Since y coordinate is at bottom of the cursor, a better
      curveID = TrigCurve.SINCURVE;     // feel is obtained by letting y be a little more than
    }                                   // 1/2.
	if ( y >= 4*d.height/5 ){
	  curveID = TrigCurve.COSCURVE;
	}
    updateAll( );
  }

The updateAll() method, used above in the mouseRelease() method, updates both the techexplorer display and the graphing applet. First, it recalculates the appropriate LaTeX expression needed to update the techexplorer display and then calls the reloadFromTeXString() method from the ibm.techexplorer.techexplorer class to redisplay the trig functions. Then it sets the appropriate curve parameters and invokes GraphIT's repaint() method. Now for the code - the part that updates the techexplorer display is shown in red; the part that updates the GraphIT applet is shown in green.

  public void updateAll( ) {

    int n = slider.getSliderLoc();
	String nStr = "";
	if (n != 1) nStr += n;				// To avoid displaying 1x

	techexplorerDisp = "\\pagecolor{lightgray}\\colorbox{white}{Select:"   +
	   "\\makebox[1.5in][r]{\\color{black}";

    if ( curveID == TrigCurve.SINCURVE ) {
      techexplorerDisp +=
	      "\\begin{eqnarray}" +
          "\\color{red}y & \\color{red}= & \\color{red}\\sin(" + nStr + "x)\\\\" +
          "            y &             = & \\cos(x)" +
	      "\\end{eqnarray}}}";
	}
	if ( curveID == TrigCurve.COSCURVE ) {
      techexplorerDisp +=
	      "\\begin{eqnarray}" +
	      "            y &             = & \\sin(x)\\\\" +
	      "\\color{red}y & \\color{red}= & \\color{red}\\cos(" + nStr + " x)\\\\" +
	      "\\end{eqnarray}}}";
	}

    // Wait, if necessary, until the HTML page has been loaded and texplorer 
    // has been initialized.

    while(texplorer == null && !texplorer.isReady()) {
       try {
         Thread.sleep(50);
       } 
       catch (InterruptedException e) { };
    }

    texplorer.reloadFromTeXString( techexplorerDisp );          // Redisplay the panel



    ((GraphIT)graphITHandle).setParam( slider.getSliderLoc() );	// Update curve definition
    ((GraphIT)graphITHandle).setCurve( curveID );               // Set sin or cos curve to plot
    ((GraphIT)graphITHandle).repaint( );                        // Regraph curve

  }

There is one more coordination issue with which our code must deal. The JavaScript begin() method is called when the HTML page finishes loading. However, the loading of the HTML page and the loading/initialization of the applets are done asynchronously, thus before the first use of the instance variable texplorer in the GraphITControl applet, we insert a wait loop to wait, if necessary, until begin() has done its job. This is the purpose of the code

    // Wait, if necessary, until the HTML page has been loaded and texplorer has been initialized.
    while(texplorer == null && !texplorer.isReady()) {
       try {
         Thread.sleep(50);
       } 
       catch (InterruptedException e) { };
    }
in the implementation of updateAll() displayed above. Normally, one likes to initialize all of an applet's instance variables in either the init() or start() methods of the applet. However, some browser implementations apparently do not consider an HTML page to be fully loaded until all the applets have been loaded and initialized, i.e., both init() and start() have completed. Thus, if we put the above loop in the init() or start() methods of the applet, the begin() that initializes the applets texplorer variable will never be called causing a deadlock. This is the reason the coordination loop is placed just before the first use of texplorer instead of one of the normal places for initializing an instance variable of an applet.

Control of flashing

There is another aspect of the implementation that deserves a few words of explanation. The Java 1.0 AWT system handles repainting by scheduling a call to the update() method. By default, the update() method clears the background and calls the paint() method. Since our paint methods repaint the entire applet, there is no need for update() to clear the screen for the new image. Furthermore, excessive repainting of the screen causes flashing so we redefine the update methods in both the GraphIT and Slider classes to simply call paint(). To also help control flashing of the images, we paint the components off screen. This is called double buffering. However, if you are used to using later versions of Java with Swing components, this code for controlling flashing may seem strange to you since it is not necessary when using Swing because with Swing components buffering is done automatically unless it is explicitly turned off. We do not use the Swing components so that browsers that do not implement Swing can display the applets without additional Java plugins.

Finally, the code of the applet destroy() method removes this applet from the MouseListener event list.

For more information about obtaining cross web browser handles to the ibm.techexplorer.techexplorer instance revisit our discussion, of the Java Editor applet.

The GraphITControl applet implements the following Java classes:

Class Description
GraphITControl Applet for updating the techexplorer display and GraphIT applet. 
Slider Component for changing the curve parameters.

Click here for the whole program. Note that since some browsers do not support Java 1.1, the GraphITControl applet is Java 1.0 compliant.

Note: This application could have been implemented using only one applet if the techexplorer expression display were placed below the slider. It was implemented using two applets in order to demonstrate inter-applet communication.



Click here to to view the previous section. Click here to to view the next section.

IBM techexplorer Hypermedia Browser is a trademark of the IBM Corporation.
Send comments and questions to techexpl@us.ibm.com.
Visit the official techexplorer home page at http://www.software.ibm.com/techexplorer/.