====== LatencyTimer ====== The JavaScript class LatencyTimer is designed to help you measure response times in the questionnaire. **Tip:** Take a look at the question types beforehand [[:en:create:questions:selclick]] and [[:en:create:questions:assignment]]. These automatically record the response time. The measurement of reaction times is based on [[:en:create:javascript]], that is, program code that runs in the respondent's browser. This program code can react to input from the respondents, for example, mouse clicks or keyboard strokes. These trigger so-called JavaScript events. DThe goal of the //LatencyTimer// class is now to measure the difference between such events. You can expect an accuracy <100 ms when measuring reaction times using JavaScript. For the difference between two events accordingly with an accuracy <200 ms. ===== Preparation ==== Make the library available on the corresponding page in the questionnaire using ''[[:en:create:functions:library]]''. library('LatencyTimer'); Furthermore, you require [[:en:create:questions:internal]] on the questionnaire page. In fact, as many as you want to measure different reaction times. Drag the corresponding question of type "internal variables" to the questionnaire page. ===== Reference ===== ==== Timer-Instanz ==== The following methods are available for an instance of the //LatencyTimer// class. Some parameters are used here again and again: * //storage//\\ An internal variable, specified by its identifier (e.g. ''"IV01_01"''), by the HTML element or by the ''SoSciTools.QuestionItem'' of the internal variable. * //storeFirst//\\ Specifies whether the reaction time should also be recorded if it is the first click on the page. By default, the code ''-7'' is saved for the first click on the page instead of a reaction time. * //multiStore//\\ This variable is used to define another internal variable that counts the reaction time for further clicks on the element. If it is used, then the individual reaction times are added and stored in this variable. By default, the reaction time is only counted for the first click on an element. Further clicks either do not change the value (if the response remains unchanged) or result in storing the code ''-6'' if another selection element within the item or question is clicked (e.g. another selection option of a selection question). ''void **latencyTimer.registerElement**(Element //element//, mixed //storage//, boolean //storeFirst//)'' With ''registerElement()'' the reaction time to click on an HTML-element ''//element//'' is recorded. ''void **latencyTimer.registerItem**(SoSciTools.QuestionItem|Question //item//, mixed //storage//, boolean //storeFirst//, mixed //multiStore//)'' With ''registerItem()'' the reaction time to answer a (selection) question or an item in a set of questions is recorded. ''void **latencyTimer.registerRadio**(String //prefix//, mixed //storage//, boolean //storeFirst//)'' With ''registerRadio()'' the reaction time to click on radio buttons is distinguished, which use the given prefix and a serial number. For example, the prefix ''"SK01_01"'' would monitor the radio buttons ''"SK01_011"'', ''"SK01_012"'' and so on. Most of the time it is easier to use ''latencyTimer.registerItem()''. ''void **latencyTimer.registerSelection**(String //auswahlID//, mixed //storage//, boolean //storeFirst//)'' With ''registerSelection()'' the reaction time to click on a simple selection question with the identifier ''//selectionID//'' is recorded. Most of the time it is easier to use ''latencyTimer.registerItem()''. ''void **latencyTimer.registerSlider**(String //sliderID//, mixed //storage//, boolean //storeFirst//, mixed //multiStore//)'' With ''registerSlider()'' the reaction time for selecting a value on a slider is recorded. Since the value on a slider may be changed again, it is necessary to specify in ''//multiStore//'' where further changes to the value are to be stored. ''Function **latencyTimer.eventHandler**(mixed //storage//, boolean //storeFirst//, mixed //multiStore//)'' The method ''eventHandler()'' returns a function which can be used directly in ''Element.addEventListener()''. This way reaction times can also be stored for events that are not clicks. ==== Static Methods ==== The following methods are available regardless of the instance. ''Element **LatencyTimer.getInternal**(string //FrageKennung//, int //VariablenNummer//)'' By means of ''getInternal()'' an internal variable can be accessed. In most cases it is easier to use ''s2.//FrageKennung//.item(//VariablenNummer//)'' . ===== Application===== The //LatencyTimer// library is based on forming pairs of (1) items, questions or choice fields and (2) internal variables. Whenever an item etc. is clicked, the //LatencyTimer// then stores the time (in milliseconds) that has passed since the last click on another item. The crux of this is that you need a preceding click as a reference. **Hint:** Optionally, you can also allow the time since the page was loaded to be used as a reference. However, your first measurement then includes reading the question, etc., so it is significantly distorted compared to the other measurements. The actual use now is to create an instance of //LatencyTimer// using ''new LatencyTimer()'' and then define pairs of input option and internal variable. The functions available for this are listed below. For a scale "SK01" with 10 items, and storing the reaction times into the 10 variables of the internal variable question "IV01" the code could look like this: By ''%%window.addEventListener("load", ...)%%'' this code is executed only when the page is fully loaded. At this point the scale can be addressed via ''s2.SK01'' and the internal variables ''s2.IV01''. This example uses the ''LatencyTimer.registerItem()'' method, which uses the internal representation of the items in SoSci Survey ([[:en:create:soscitools]]). This way you don't have to search for the selection fields of the scale one by one. Instead of counting in the FOR loop, you can also query the items directly from the object representing the scale. window.addEventListener("load", function() { var timer = new LatencyTimer(); for (var key in s2.SK01.items) { var item = s2.SK01.items[key]; var itemID = item.id var internal = s2.IV01.item(item.id); timer.registerItem(item, internal); } } ===== Selection Questions===== In this example, the clicks on three selection questions (simple selection) "AF01", "AF02" and "AF03" are to be saved. window.addEventListener("load", function() { var timer = new LatencyTimer(); timer.registerItem(s2.AF01, "IV01_01"); timer.registerItem(s2.AF02, "IV01_02"); timer.registerItem(s2.AF03, "IV01_03"); } Here the internal variables are addressed by their identifier -- of course ''s2.IV01.item(1)'' would be just as possible. If reaction time is also to be recorded when respondents change their mind, two internal variables are required per choice question. window.addEventListener("load", function() { var timer = new LatencyTimer(); timer.registerItem(s2.AF01, "IV01_01", false, "IV01_02"); timer.registerItem(s2.AF02, "IV01_03", false, "IV01_04"); timer.registerItem(s2.AF03, "IV01_05", false, "IV01_06"); } In the first variable the reaction time for the first click is stored. In the second variable the total reaction time (incl. that for the first click) is stored. ===== Record other events ===== The ''eventHandler()'' method allows storing reaction times for arbitrary events.
The method ''eventHandler()'' can also be used to record the reaction times of an open text input field (in the example "OT01_01") until the first and until the last keystroke. window.addEventListener("load", function() { var timer = new LatencyTimer(); document.getElementById("OT01_01").addEventListener( "keydown", timer.eventHandler("IV01_01", false, "IV01_02") ); }); If you want to realize this recording for a larger number of input fields, it is useful to create two questions of the type "internal variables", one (in the example "IV01") for the first, one for the last keystroke ("IV02"). window.addEventListener("load", function() { var timer = new LatencyTimer(); for (var key in s2.OT01.items) { var item = s2.OT01.items[key]; var itemID = item.id; var internalA = s2.IV01.item(itemID); var internalB = s2.IV02.item(itemID); item.input.addEventListener( "keydown", timer.eventHandler(internalA, false, internalB) ); } });