```    1 import java.applet.*;
2 import java.awt.*;
3 import java.awt.Component.*;
4 import java.awt.Component;
5 import java.awt.event.*;
6 import java.lang.Math;
7
8 /**
9  * Applet to demonstrate Fitts Law
10  * Creation date: (02/15/2002 9:52:13 AM)
11  * Modified date: (04/15/2002 2:48:00 PM)
12  * @author: Andrew Freed, arf132@psu.edu
13  */
14
15 /*
16 Development of this applet was sponsored by the Penn State Fund for
17 Excellence in Learning and Teaching (FELT), project "Java-based
18 Teaching of Mathematics in Information Sciences and Technology",
19 supervised by Frank Ritter and David Mudgett.
20 */
21
22 public class FittsLawApplet extends Applet implements MouseMotionListener, MouseListener {
23   private Label  lblTarget    = new Label("TARGET");
24   private Label  lblOutput    = new Label("Distance - ?   Time - ?   Target width - ?");
25   private Button  btnResize    = new Button("Resize");
26
27 /**********************************************************************************
28 Fitts' law is a robust model of human psychomotor behavior developed in 1954.
29 The model is based on time and distance. It enables the prediction of human movement
30  and human motion based on rapid, aimed movement, not drawing or writing.
31
32 It seems intuitive that movement time would be affected by the distance moved
33  and the precision demanded by the size of the target to which one is moving.
34  Fitts discovered that movement time was a logarithmic function of distance when
35  target size was held constant, and that movement time was also a logarithmic
36  function of target size when distance was held constant.
37
38 Mathematically, Fitts' law is stated as follows:
39
40 MT = a + b log2(2A/W)
41
42 where
43
44 MT = movement time
45 a,b = regression coefficients
46 A = distance of movement from start to target center
47 W = width of the target
48
49 Source: http://ei.cs.vt.edu/~cs5724/g1/glance.html
50
51 **********************************************************************************/
52
53 double a = 150.0;    //Constant reaction time
54 double b = 100.0;    //Movement proportion
55
57 double centerTargetX;
58 double centerTargetY;
59 int targetWidth;
60 int targetHeight;
61 int targetX;
62 int targetY;
63
64 //State variables to help us keep track of where the mouse is drug
65 int newX, newY;
66 boolean isMoving = false;
67
68 public void mouseMoved(MouseEvent e)
69 {
70   try
71   {
72   //If we are inside the target, there is nothing to compute
73   if( e.getComponent() == lblTarget )
74   {
75     lblOutput.setText("In target");
76     return;
77   }
78
79   int x = e.getX();
80   int y = e.getY();
81
82   //Compute the distance to target center.  This is sqrt( dx^2 + dy^2 )
83   double distX = Math.abs( (double) x - centerTargetX );
84   double distY = Math.abs( (double) y - centerTargetY );
85   double dist = Math.sqrt( distX * distX + distY * distY );
86
87   //Recalculate width along axis of movement
88   double width = 2.0 *  dist* ( (0.5 * (double) lblTarget.getBounds().width) /Math.max(distX, distY));
89
90   //Use Fitt's Law formula to compute time to target
91   double time = a + b * logBaseTwo( 2.0 * dist /width );
92
93   String result = "";
94   result += " --- DISTANCE (px) " + (int) dist + " ---";
95   result += " --- TIME TO TARGET " + (int) time + " (ms) ---";
96   result += " --- TARGET WIDTH (px) " + (int) width + " ---";
97
98   lblOutput.setText(result);
99
100   }
101
102   catch( Throwable ev)
103   {
104   lblOutput.setText("Error: " + ev.toString());
105   }
106 }
107
108 public void mouseDragged(MouseEvent e)
109 {
111   if( isMoving )
112   {
113     if( e.getComponent() == lblTarget )
114     {
115       newX = e.getX() + targetX;
116       newY = e.getY() + targetY;
117     }
118     //If we try to move out of the applet, this must be captured
119     else
120     {
121       newX = e.getX();
122       newY = e.getY();
123     }
124
125     //Assuming dimensions of 500x350 for this applet,
126     //with the bottom 50 pixels reserved for the output label
127
128     //Make sure center of target is within the applet bounds
129     if( newX < (targetWidth/2) )
130       newX = targetWidth/2;
131     if( newX > 500 - (targetWidth/2))
132       newX = 500 - (targetWidth/2);
133     if( newY < (targetHeight/2) )
134       newY = targetHeight/2;
135     if( newY > 300 - (targetHeight/2))
136       newY = 300 - targetHeight/2;
137
138     //Update the location of the target
139     resizeTarget(new Rectangle( newX - (targetWidth/2),
140          newY - (targetHeight/2),
141          targetWidth,
142          targetHeight ));
143   }
144 }
145
146 public void mousePressed(MouseEvent e)
147 {
148   //If we are over the target, this signifies the beginning of a drag
149   if( e.getComponent() == lblTarget )
150     isMoving = true;
151   else
152     isMoving = false;
153 }
154 public void mouseReleased(MouseEvent e)
155 {
156   //Dragging operation is finished
157   if( isMoving )
158   {
159     isMoving = false;
160   }
161 }
162
163 //This must be implemented because this applet is registered as a MouseListener.
164 //However, a "blank" implementation will do just fine
165 public void mouseClicked(MouseEvent e){}
166 public void mouseEntered(MouseEvent e){}
167 public void mouseExited(MouseEvent e){}
168
169 //This function resizes and relocates the target, and also updates the global
170 //variables related to the target
171 public void resizeTarget(Rectangle newBounds)
172 {
173   lblTarget.setBounds(newBounds);
174
175   targetWidth  = lblTarget.getBounds().width;
176   targetHeight = lblTarget.getBounds().height;
177   targetX    = lblTarget.getBounds().x;
178   targetY    = lblTarget.getBounds().y;
179
180   centerTargetX = targetX  + 0.5 * targetWidth;
181   centerTargetY = targetY  + 0.5 * targetHeight;
182 }
183
184 //This resizes the target to a square between 25 and 100 pixels wide
185 private void doRandomResize()
186 {
187   int myWidth = 25 + (int)( 75 * Math.random() + 1);
188   resizeTarget(new Rectangle(targetX, targetY, myWidth, myWidth));
189
190   lblOutput.setText("New target width: " + myWidth);
191 }
192
193 //Java's log function is base e.  Fitt's Law uses logs base 2.
194 private double logBaseTwo(double myDouble)
195 {
196   return( Math.log(myDouble) /Math.log(2.0) );
197 }
198
199 /**
200  * Initializes the applet.
201  */
202 public void init() {
203   try {
204     setLayout(null);
205     setSize(500, 350);
206
207     lblTarget.setBounds(0,0,100,100);
208     lblTarget.setBackground(Color.red);
209     lblTarget.setAlignment(Label.CENTER);
210
211     lblOutput.setBounds(0,300, 500, 50);
212     lblOutput.setBackground(Color.white);
213
214     btnResize.setBounds(450, 0, 50, 30);
215
216     this.setBackground(Color.gray);
217
221
224
227
228     //This will set some global variables
229     resizeTarget(lblTarget.getBounds());
230
231     btnResize.setActionCommand("btnResize");
233       public void actionPerformed(java.awt.event.ActionEvent e)
234       {
235         doRandomResize();
236       }
237     });
238
239   } catch (java.lang.Throwable Exc) {
240     handleException(Exc);
241   }
242 }
243
244 /**
245  * Called whenever the part throws an exception.
246  * @param exception java.lang.Throwable
247  */
248 private void handleException(java.lang.Throwable exception) {
249   lblOutput.setText("Error: " + exception.toString() );
250 }
251
252
253 //Main function allows you to run this applet as an application
254 /**
255  * main entrypoint - starts the part when it is run as an application
256  * @param args java.lang.String[]
257  */
258 public static void main(java.lang.String[] args) {
259   try {
260     Frame frame = new java.awt.Frame();
261     FittsLawApplet aFittsLawApplet;
262     Class iiCls = Class.forName("FittsLawApplet");
266     frame.setSize(aFittsLawApplet.getSize());
268       public void windowClosing(java.awt.event.WindowEvent e) {
269         System.exit(0);
270       };
271     });
272     frame.show();
273     java.awt.Insets insets = frame.getInsets();
274     frame.setSize(frame.getWidth() + insets.left + insets.right, frame.getHeight() + insets.top + insets.bottom);
275     frame.setVisible(true);
276   } catch (Throwable exception) {
277     System.err.println("Exception occurred in main() of java.applet.Applet");
278     exception.printStackTrace(System.out);
279   }
280 }
281 }```