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 
   56 //Information about the target
   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 {
  110   //We only care about this if we are inside the label, and thus moving it
  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 
  218     add(lblTarget);
  219     add(lblOutput);
  220     add(btnResize);
  221 
  222     lblTarget.addMouseMotionListener(this);
  223     addMouseMotionListener(this);
  224 
  225     lblTarget.addMouseListener(this);
  226     addMouseListener(this);
  227 
  228     //This will set some global variables
  229     resizeTarget(lblTarget.getBounds());
  230 
  231     btnResize.setActionCommand("btnResize");
  232     btnResize.addActionListener(new java.awt.event.ActionListener(){
  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");
  263     ClassLoader iiClsLoader = iiCls.getClassLoader();
  264     aFittsLawApplet = (FittsLawApplet)java.beans.Beans.instantiate(iiClsLoader,"FittsLawApplet");
  265     frame.add("Center", aFittsLawApplet);
  266     frame.setSize(aFittsLawApplet.getSize());
  267     frame.addWindowListener(new java.awt.event.WindowAdapter() {
  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 }
HTML generated by Java2Html, © 2000 Think Tank Ltd, Douglas, Isle Of Man. All rights reserved