Qualtrics Survey中的鼠标跟踪

时间:2011-07-29 17:53:09

标签: java javascript mouse analytics tracking

我编写了一个Java小程序来记录用户鼠标的位置,并计算每个时间步的速度和加速度。我想将其转换为Javascript。这可能吗?

编辑2:我现在公开发布了代码并编写了一个关于如何实现它的简短教程。

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

随意使用和分享!

编辑1:以下是Javascript代码:

<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>

这是Java代码:

主类:

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;
    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;
    }
}

实用程序类:

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;
    }
}

1 个答案:

答案 0 :(得分:1)

这可能有点晚了,但我已经使用了许多鼠标&amp;具有Qualtrics的眼动追踪系统。主要问题是在Qualtrics域中访问托管小会话文件。有一些现成的程序,如MouseFlow,做得很好,包括热图,完整的视频和其他参数。我的大多数研究都是在我们控制整个过程的实验室里进行的,但是你的JavaScript想法听起来真的很棒。我很想知道你是怎么过的。