开发者

Mouse Tracking within a Qualtrics Survey

开发者 https://www.devze.com 2023-03-24 09:26 出处:网络
I\'ve written a Java applet to record the position of a user\'s mouse and calculate the velocity and acceleration at each time step. I\'d like to convert it to Javascript. Is this possible?

I've written a Java applet to record the position of a user's mouse and calculate the velocity and acceleration at each time step. I'd like to convert it to Javascript. Is this possible?

EDIT 2: I have now posted the code publicly and written a short tutorial on how to implement it.

http://math.bu.edu/people/jackwalt/qualtrics-mousetracking/

Feel free to use and share!

EDIT 1: Here's the Javascript code:

<input type="hidden" id="xPos" name="ED~xPos" value="" />
<input type="hidden" id="yPos" name="ED~yPos" value="" />
<input type="hidden" id="time" name="ED~time" value="" />

<script type="text/javascript">

var initTime = new Date().getTime();

document.onmousemove = getMousePosition;

function getMousePosition(mp) {
   var divPos = getPosition(document.getElementById("mousearea"));

var event = [mp.pageX - divPos[0], mp.pageY - divPos[1], new Date().getTime() - initTime];

document.getElementById("xPos").value += event[0] + ", ";
document.getElementById("yPos").value += event[1] + ", ";
document.getElementById("time").value += event[2] + ", ";

return true;
 }


function getPosition(obj){

var topValue= 0,leftValue= 0;

while(obj){
    leftValue+= obj.offsetLeft;
    topValue+= obj.offsetTop;
    obj= obj.offsetParent;
    }

return [leftValue, topValue];
}

</script>

Here's the Java code:

Main Class:

package com.jackson.allgood;

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * This is a simple applet to record the position, velocity, and acceleration of a
 * mouse pointer as it moves relative to names positioned in the window. Metadata is
 * written to a text file and raw data to a .csv file.
 * 
 * @author Jackson Walters
 *
 */
public class Main extends Applet {

    private static final long serialVersionUID = 1L;

    private List<Data> dataList;
    private MouseListenerThread testThread;
    private long startTime;
    private long endTime;
   开发者_StackOverflow社区 private static long DT = 10L;

    private static final String[] NAMES = {"Name 1","Name 2","Name 3","Name 4"};
    private static final String METADATA_FILENAME = "metadata";
    private static final String DATA_FILENAME = "data";

    /**
     * Initializes the applet by creating an ArrayList to hold the data
     * and starts a thread to begin collecting data.
     */
    public void init() {
        dataList = new ArrayList<Data>();

        testThread = new MouseListenerThread();
        testThread.start();
    }

    /**
     * Stops the applet. Asks the thread to stop and waits until it does, then prints
     * the metadata and data.
     */
    public void stop(){
        testThread.requestStop();
        try {
            testThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        printData();
        printMetaData();
    }

    public void paint(Graphics g) 
    {  
        g.drawString(NAMES[0],getSize().width/2,20); 
        g.drawString(NAMES[1],getSize().width/2,getSize().height-20);
        g.drawString(NAMES[2],10,getSize().height/2); 
        g.drawString(NAMES[3],getSize().width-100,getSize().height/2);
    }

    /**
     * Thread that records the time and position of the mouse, calculates velocity and acceleration,
     * then stores the data into the data list. Sleeps for the time interval specified by DT. Able to
     * be stopped by setting a flag then waiting one time interval for the loop to exit.
     *
     */
    private class MouseListenerThread extends Thread{

        private boolean running = true;

        @Override
        public void run(){

            //initialize time and first data point
            startTime = System.currentTimeMillis();
            dataList.add(new Data(
                    0L,
                    MouseInfo.getPointerInfo().getLocation().getX(),
                    MouseInfo.getPointerInfo().getLocation().getY(),
                    0.,0.,0.,0.)
                    );

            while(running){

                long currentTime = System.currentTimeMillis()-startTime;

                Point mousePos = MouseInfo.getPointerInfo().getLocation();

                double xPos = mousePos.getX();
                double yPos = mousePos.getY();

                double xVel = (xPos-dataList.get(dataList.size()-1).getXPos())/DT;
                double yVel = (yPos-dataList.get(dataList.size()-1).getYPos())/DT;

                double xAcc = (xVel-dataList.get(dataList.size()-1).getXVel())/DT;
                double yAcc = (yVel-dataList.get(dataList.size()-1).getYVel())/DT;

                dataList.add(new Data(currentTime, xPos, yPos, xVel, yVel, xAcc, yAcc));

                try {
                    sleep(DT);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            endTime = System.currentTimeMillis();
        }

        public void requestStop(){
            running = false;
        }
    }

    /**
     * Prints the raw data generated by the program to a .csv file.
     */
    private void printData(){

        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(DATA_FILENAME + ".csv"));
            out.write(Data.DATA_HEADER_STRING);
            for(Data data : dataList){
                out.write(data.toString());
            }
            out.close();
        } catch (Exception e){
            System.err.println("Error: " + e.getMessage());
        }
    }

    /**
     * Prints general information about what the program did to a text file.
     */
    private void printMetaData(){

        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(METADATA_FILENAME + ".txt"));

            out.write("Start time: " + DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(startTime))); out.newLine();
            out.write("End time: " + DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(endTime))); out.newLine();
            out.write("Elapsed time: " + formatElapsedTime(endTime-startTime)); out.newLine();
            out.write("Number of measurments: " + dataList.size()); out.newLine();
            out.write("Measurement interval: " + DT + "ms"); out.newLine(); out.newLine();
            out.write("Names:"); out.newLine();
            for(String name : NAMES){
                out.write(name); out.newLine();
            } out.newLine(); out.newLine();

            out.close();
        } catch (Exception e){
            System.err.println("Error: " + e.getMessage());
        }
    }

    /**
     * Converts milliseconds in the format min:sec.
     * @param ms
     * @return Time as min:sec.
     */
    private static String formatElapsedTime(long ms){

        int seconds = (int) (ms/1000.);
        int minutes = seconds/60;
        seconds %= 60;

        if(seconds < 10) return minutes + ":0" + seconds;
        else return minutes + ":" + seconds;
    }
}

Utility Class:

package com.jackson.allgood;

/**
 * Simple class to store data such as time, position, velocity, and acceleration.
 * @author Jackson Walters
 *
 */
public class Data {

    protected static final String DATA_HEADER_STRING = "Time, " +
                                                       "x position, " +
                                                       "y position, " +
                                                       "x velocity, " +
                                                       "y velocity, " +
                                                       "x acceleration, " +
                                                       "y acceleration" + 
                                                       "\n";

    private long time;

    private double xPos;
    private double yPos;

    private double xVel;
    private double yVel;

    private double xAcc;
    private double yAcc;

    public Data(){}

    public Data(long time, double xPos, double yPos, double xVel, double yVel, double xAcc, double yAcc){
        this.time = time;

        this.xPos = xPos;
        this.yPos = yPos;

        this.xVel = xVel;
        this.yVel = yVel;

        this.xAcc = xAcc;
        this.yAcc = yAcc;
    }

    //getters and setters for time, pos, vel, and acc

    public long getTime(){return time;}
    public void setTime(long time){this.time = time;}

    public double getXPos(){return xPos;}
    public void setXPos(double xPos){this.xPos = xPos;}
    public double getYPos(){return yPos;}
    public void setYPos(double yPos){this.yPos = yPos;}

    public double getXVel(){return xVel;}
    public void setXVel(double xVel){this.xVel = xVel;}
    public double getYVel(){return yVel;}
    public void setYVel(double yVel){this.yVel = yVel;}

    public double getXAcc(){return xAcc;}
    public void setXAcc(double xAcc){this.xAcc = xAcc;}
    public double getYAcc(){return yAcc;}
    public void setYAcc(double yAcc){this.yAcc = yAcc;}

    /**
     * Formats the data as a string of comma separated values.
     */
    @Override
    public String toString(){
        String toReturn = "";

        toReturn += time + ", ";

        toReturn += xPos + ", ";
        toReturn += yPos + ", ";

        toReturn += xVel + ", ";
        toReturn += yVel + ", ";

        toReturn += xAcc + ", ";
        toReturn += yAcc + ", ";

        toReturn += "\n";

        return toReturn;
    }
}


This may be a little late but I have used a number of mouse & eye-tracking systems with Qualtrics. The main problem is getting access to host a small session file at the Qualtrics domain. There are a few off the shelf programs like MouseFlow that do a good job and include heat map, full video and other parameters. Most of my research has been in labs where we have controlled the whole process, but your JavaScript idea sounds really good. I would be very interested to hear how you get on.

0

精彩评论

暂无评论...
验证码 换一张
取 消