简体   繁体   English

Qualtrics调查中的鼠标跟踪

[英]Mouse Tracking within a Qualtrics Survey

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. 我编写了一个Java小程序来记录用户鼠标的位置,并计算每个时间步的速度和加速度。 I'd like to convert it to Javascript. 我想将其转换为Javascript。 Is this possible? 这可能吗?

EDIT 2: I have now posted the code publicly and written a short tutorial on how to implement it. 编辑2:我现在已经公开发布了代码,并编写了有关如何实现它的简短教程。

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

Feel free to use and share! 随时使用和分享!

EDIT 1: Here's the Javascript code: 编辑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>

Here's the Java code: 这是Java代码:

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;
    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 . 这可能有点晚了,但是我在Qualtrics中使用了许多鼠标和眼动跟踪系统。 The main problem is getting access to host a small session file at the Qualtrics domain. 主要问题是无法访问在Qualtrics域中托管小型会话文件。 There are a few off the shelf programs like MouseFlow that do a good job and include heat map, full video and other parameters. 有一些像MouseFlow这样的现成程序可以很好地完成工作,其中包括热图,完整视频和其他参数。 Most of my research has been in labs where we have controlled the whole process, but your JavaScript idea sounds really good. 我的大部分研究工作都在实验室进行,我们控制了整个过程,但是您的JavaScript想法听起来确实不错。 I would be very interested to hear how you get on. 听到您的相处,我会很感兴趣。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM