## TangentsApplet

This applet draws the graph of a function and its derivative.

A tangent line is drawn on the function, and a crosshair marks the

corresponding point on the graph of the tangent. You can move the

tangent line by clicking-and-dragging on either graph. Aside from

this, the canvas does not respond to mouse actions. A formula for

the derivative is shown at the bottom of the applet:The following source code shows how the applet is built from

WCM components. This one gets pretty complicated! Features that

appeared in previous examples are not commented:

import java.awt.BorderLayout;

import java.awt.Color;

import javax.swing.JLabel;

import javax.swing.JApplet;

import net.sourceforge.webcompmath.awt.Computable;

import net.sourceforge.webcompmath.awt.ComputeButton;

import net.sourceforge.webcompmath.awt.Controller;

import net.sourceforge.webcompmath.awt.ExpressionInput;

import net.sourceforge.webcompmath.awt.Tie;

import net.sourceforge.webcompmath.awt.Tieable;

import net.sourceforge.webcompmath.awt.WcmPanel;

import net.sourceforge.webcompmath.data.Expression;

import net.sourceforge.webcompmath.data.Function;

import net.sourceforge.webcompmath.data.Parser;

import net.sourceforge.webcompmath.data.Value;

import net.sourceforge.webcompmath.data.ValueMath;

import net.sourceforge.webcompmath.data.Variable;

import net.sourceforge.webcompmath.draw.Crosshair;

import net.sourceforge.webcompmath.draw.DisplayCanvas;

import net.sourceforge.webcompmath.draw.DrawBorder;

import net.sourceforge.webcompmath.draw.DrawString;

import net.sourceforge.webcompmath.draw.Graph1D;

import net.sourceforge.webcompmath.draw.LimitControlPanel;

import net.sourceforge.webcompmath.draw.MouseTracker;

import net.sourceforge.webcompmath.draw.TangentLine;

import net.sourceforge.webcompmath.draw.WcmAxes;

/**

* This is an example WCM applet

*/

public class TangentsApplet extends JApplet {

private static final long serialVersionUID = -4457550735230739341L;

DisplayCanvas canvas;

/**

* Overrides init() in JApplet

*

* @see java.applet.Applet#init()

*/

public void init() {

/*

* By default, a canvas contains just one CoordinateRect. However, it

* can contain more than one. Here, I add two CoordinateRects to the

* canvas. The parameters specify the portion of the canvas occupied by

* the coords, where 0,1,0,1 would mean the entire canvas, both

* horizontally and vertically. The first coords occupies the left half

* of the canvas, and the second occupies the right.

*/

canvas = new DisplayCanvas();

canvas.addNewCoordinateRect(0, 0.5, 0, 1);

canvas.addNewCoordinateRect(0.5, 1, 0, 1);

/*

* When an object is added to the canvas, you can specify which

* coordinate rect it is being added to. CoordinateRects in the canvas

* are numbered starting from zero.

*/

canvas.add(new WcmAxes(), 0);

canvas.add(new WcmAxes(), 1);

/*

* Previously, I added canvasses LimitControlPanels, but really its the

* CoordinateRects that are added. Here, I explicitely add both

* CoordinateRects to the LimitControlPanel. This has the effect of

* synchronizing the limits on the two coords with each other as well as

* with the limits panel.

*/

LimitControlPanel limits = new LimitControlPanel();

limits.addCoords(canvas.getCoordinateRect(0));

limits.addCoords(canvas.getCoordinateRect(1)); // to

limits.setErrorReporter(canvas);

Parser p = new Parser();

Variable x = new Variable("x");

p.add(x);

ExpressionInput input = new ExpressionInput("sin(x)*cos(2*x) + x/3", p);

Function func = input.getFunction(x);

/*

* Every function object has one or more derivatives. func.derivative(1)

* is the Function object that represents the derivative of func with

* respect to its first (and only) parameter. This derivative is

* computed symbolically from the expression that defines func, that is,

* the expression entered by the user. The derivative function changes

* along with the function when the user's input changes.

*/

Function deriv = func.derivative(1);

// Graph of the function.

Graph1D graph1 = new Graph1D(func);

// Graph of the derivative function.

Graph1D graph2 = new Graph1D(deriv);

canvas.add(graph1, 0); // Add each graph to a separate CoordinateRect.

canvas.add(graph2, 1);

/*

* A MouseTracker can be added to a CoordinateRect (or DisplayCanvas) to

* respond to user clicks-and-drags of the mouse. (To make them work, I

* had to leave the zoom feature of the DisplayCanvas turned off in this

* applet.)

*/

MouseTracker m1 = new MouseTracker();

MouseTracker m2 = new MouseTracker();

/*

* There are two variables associated with a MouseTracker. They

* represent the x- and y-coordinates of the mouse in the coordinate

* system defined by the CoordinateRect.

*/

Variable xMouse1 = m1.getXVar();

xMouse1.setVal(0);

Variable xMouse2 = m2.getXVar();

xMouse2.setVal(0);

// Tangent line for first graph.

TangentLine tangent = new TangentLine(xMouse1, func);

// Crosshair for second graph. Positions are determined from

// MouseTrackers.

Crosshair cross = new Crosshair(xMouse2, deriv);

// Add the mouse trackers to the two CoordinateRects.

canvas.add(m1, 0);

canvas.add(m2, 1);

canvas.add(tangent, 0); // Add tangent line to the first rect.

canvas.add(cross, 1); // Add the Crosshair to the second rect.

DrawString values = new DrawString("x = #\nf(x) = #\nf'(x) = #",

DrawString.BOTTOM_LEFT, new Value[] { xMouse1,

new ValueMath(func, xMouse1),

new ValueMath(deriv, xMouse1) });

values.setNumSize(6); // Limit the size of numbers in the DrawString.

values.setColor(new Color(0, 100, 0));

canvas.add(values, 1); // Add some DrawStrings to the canvas.

canvas.add(new DrawString("y = f(x)"), 0);

canvas.add(new DrawString("y = f'(x)"), 1);

// Add a border around each coordinate rect.

canvas.add(new DrawBorder(), 0);

canvas.add(new DrawBorder(), 1);

ComputeButton button = new ComputeButton("Draw graph");

WcmPanel funcPanel = new WcmPanel(3);

funcPanel.add(new JLabel(" f(x) = "), BorderLayout.WEST);

funcPanel.add(input, BorderLayout.CENTER);

funcPanel.add(button, BorderLayout.EAST);

WcmPanel bottom = new WcmPanel(2, 1);

bottom.add(funcPanel);

bottom.add(new FuncLabel(input.getExpression().derivative(x)));

/*

* A FuncLabel is a custom "Computable", defined below, for displaying

* the formula for an expression. In this case, the expression that is

* displayed is the derivative of the user's input with respect to x.

*/

WcmPanel main = new WcmPanel(3);

main.add(bottom, BorderLayout.SOUTH);

main.add(canvas, BorderLayout.CENTER);

main.add(limits, BorderLayout.EAST);

setBackground(Color.lightGray);

setLayout(new BorderLayout(3, 3));

add(main, BorderLayout.CENTER);

Controller c = main.getController();

c.setErrorReporter(canvas);

c.add(new Tie((Tieable) xMouse1, (Tieable) xMouse2));

/*

* An interesting point in this applet is that the x-coordinates of the

* tangent line and crosshair are synchronized. This is done by "Tieing"

* the x-variables associated with the two MouseTrackers. When the user

* changes one of the values, the other is changed to have the same

* value. Note that xMouse1 and xMouse2 are declared to be of type

* Variable, but they also implement the Tieable interface so that they

* can be synchronized with other MouseTracker variables or with

* VariableSliders or VariableInputs.

*/

button.setOnUserAction(c); // Make controller respond to button.

main.gatherInputs();

/*

* Must respond to input objects! This applet would actually be more

* efficient if Were built of regular Panels and set up the the

* controllers by hand, as in GraphApplet3

*/

} // end init();

static class FuncLabel extends JLabel implements Computable {

private static final long serialVersionUID = 2638507674457461374L;

/*

* Objects that are meant to be recomputed by Controllers implement the

* Computable interface. There is no standard JCM component for

* displaying an expression, but it's easy enough to make one. A

* FuncLabel, when properly added to a Controller, will display the

* String representation of an expression.

*/

Expression exp;

FuncLabel(Expression e) {

super(" f'(x) = " + e);

exp = e;

}

/**

* @see net.sourceforge.webcompmath.awt.Computable#compute()

*/

public void compute() {

/*

* Recompute the display. This is meant to be called whenever the

* expression might have changed.

*/

setText(" f'(x) = " + exp);

}

} // end nested class FuncLabel

} // end class TangentsApplet