Qualtrics & Javascript Precise Timer Using Time Spend on a Page - javascript

I am doing research with an experiment using qualtrics and unfortunately I am completely new to coding. In my experiment a block of questions should be ended after a certain time (in this case 50 seconds). So far I have been using a solution (which I found here: https://research-it.wharton.upenn.edu/uncategorized/qualtrics-loop-merge-tips/) that appeared rather neat using a blank embedded variable "test_time", display logic and the following javascript code which I copied to every page of the block:
Qualtrics.SurveyEngine.addOnload(function()
{
var elapsed = Date.now() - Number("${e://Field/test_time}");
if (elapsed >= 50000){
Qualtrics.SurveyEngine.setEmbeddedData("test_time", 0);
}
});
However, in the exported data when summing up information from timing questions that I included, I see that people have extremely varying time they actually can spend on the questions of the block (from 30 to almost 50 seconds). I am guessing this is due to the fact that the script uses the time of the clock, irrespective of lag caused by a bad internet connection or slow browser.
However, for my project it is important that people actually have the same time for the task. I suspect I could use the information of the timing questions, but somehow I can't access them in Javascript. Another idea is to record the difference between the page appearing and the click on the next button.
I appreciated any of your ideas and inputs!

Use the built-in embedded variable Q_TotalDuration, which is the elapsed survey time in seconds. Set the start time of the block in the survey flow just before the block:
startBlock = ${e://Field/Q_TotalDuration}
Then your JavaScript becomes:
var elapsed = parseInt("${e://Field/Q_TotalDuration}") - parseInt("${e://Field/startBlock}");
if(elapsed >= 50) {
//do something here
}
I don't understand what happens when the time limit is reached and time_test is set to zero in your original code. It wouldn't have any impact on the current page. It seems like you should be setting up a timeout function to click the Next button when the time threshold is reached.

Related

How to update a web page javascript counter live when the browser doesn't have focus?

I am making a browser game in html, css, and javascript, written in perl. Health and stamina are kept in the server and I use javascript to show the user a live updated count of these stats while the current page is loaded. This works fine, however if the user switches tabs or switches away from the browser and leaves it running in the background, the count value you see when you return does not keep up properly. So when you switch back to the browser, your counter might say 50/100 stamina when you actually have 100/100. So when you do something in the game (loads a new page) the server updates the counter to the true amount because the javascript is just keeping time to show the user a "live" rolling view in the browser.
Is there a way to ensure the javascript counter will continue to function even if the page/tab isn't active or on the forefront? Aside from completely re-writing my game to include continuous live server pushes in what is displayed on the browser to the user?
Say you are playing the game. You see your health and stamina regenerating. You switch to another program for a minute, then return to the game in the browser. You notice your health and stamina have not updated while you were away. But when you perform an action in the game, this value is updated to what it should be because it is tracked internally on the server. This is what I would like to fix. Hope that makes sense!
I have not tried anything to fix this issue yet besides searching the web and ending up on this site without a really "good" answer in sight, so I decided to ask the question.
Continuous server pushes wouldn't work either. Anything in the main event loop like a timer, or events happening when it's out of focus, gets slowed down by the browser to conserve resources. Some mobile browsers will stop it together.
The answer to the question is to change how your app keeps track of these stats.
Now some will say to use WebWorkers to run the timer in a separate thread but this won't solve all your issues. You'd still have a different version of the issue, like if someone restored your webpage from sleep or something along those lines. No background task can survive that.
You mention that you track these stats also on the server. That's convenient, so the most obvious thing you should do is detect when the tab comes back into focus using the Window focus event. You would then make all the calls to the server to fetch the most up-to-date stats and reset the timers based on that fresh data. To stop it from showing stale data while the request is in flight, you might choose to show a loading spinner or something during that period.
Another common way of fixing this is you keep around on each timer increment a var which says when the data last came back (a timestamp). When you leave focus, you detect this with the blur event and store that last timestamp somewhere. Then they come back into focus, you handle the focus event and calculate the difference between the current time and the last recorded time before defocus (blur). You may be able to recalculate from this period what the values should be.
But if your server has this info, it'd be far less error-prone and easy to just ask the server when they refocus.

Making Date/Time auto-update on Javascript within proprietary software

I'm using proprietary software to create a page that I need to display (among other things, mainly HVAC controls) date and time. The software has a block for "custom html" (with the note "This content will be saved in a separate HTML file within <html> and <body> tags"), into which I place my code.
After some research (I'm not a coder and have mainly been copy-pasting), the code I have pasted into said block is as follows:
<script language="javascript">
var t = new Date();
document.write(t.toDateString()+""+t.getHours()+":"+t.getMinutes());
</script>
And this gets me pretty close to what I want (day, month, date, year, time). I'd prefer if I could get AM/PM but mainly what I want is for the date/time to auto-update so the user doesn't need to refresh the page before getting an accurate printout.
While I've seen many threads on this site devoted to auto-updating time/date, I'm not sure how to integrate any of them with the system I'm working with (I've been at this for some time now), so I thought I'd ask the question with the context I'm working with.
This is not the exact format you want, but gives different way to achieve what you need. with some string manipulation you can achieve the same. if you could share the exact format you want to display, I could modify the solution.
Using setTimeout() or setInterval() to continuously make changes to the user's screen often induces "layout thrashing", the browser version of cardiac arrest where it is forced to perform unnecessary reflows of the page before the user's screen is physically able to display the changes. This is very bad due to the taxing nature of page reflows, especially on mobile devices where the problem is most apparent, with junky page loads and battery drains.
It is for the above reasons requestAnimationFrame() was introduced. The method in a nutshell allows you to execute code on the next available screen repaint, taking the guess work out of getting in sync with the user's browser and hardware readiness to make changes to the screen. When we call requestAnimationFrame() repeatedly to create a screen update, we are assured that our update code is called when the user's computer is actually ready to make changes to the screen each time, resulting in a smoother, more efficient update. Furthermore, code called via requestAnimationFrame() and running inside background tabs in your browser are either paused or slowed down significantly (to 2 frames per second or less) automatically to further save user system resources- there's no point in running the screen update that isn't being seen.
(function updateTime() {
var time = (new Date()).toLocaleString({
hour12: true,
});
document.getElementById('current_time').innerHTML = time;
requestAnimationFrame(updateTime);
})();
<div id="current_time"></div>
setInterval(function(){
var t = new Date();
document.write(t.toDateString()+""+t.getHours()+":"+t.getMinutes());
}, 1000);
Will run your script once every second, unfortunately this doesn't get rid of old times, so I would suggest having a placeholder you can update like an html span element.
<span id="time"></span>
<script>
setInterval(function(){
var t = new Date();
document.getElementById("time").innerHTML =
(t.toDateString()+""+t.getHours()+":"+t.getMinutes());
}, 1000);
</script>
Now, your clock is going to need some formatting, because right now, if, say, the time is 11:05, it displays 11:5. I would check that out here
Hopefully this works in your system.

Javascript Animation and Recursion

I have written a Javascript program that solves a puzzle game using a recessive technique.
That is, function solvePuzzle() calls function solvePuzzle() for a simpler puzzle until the solution is found. It alters the data in the board object.
I also have a function board.draw() that can display the state of the puzzle
It draws the initial game board as I expect and once I click on a button (triggering execution of solvePuzzle()) it draws the solved game board again as I expect.
However, I would like to show the intermediate puzzle states.
Initially, I inserted calls to board.draw() in the solvePuzzle() function but this does not do anything.
Researching Javascript animation has led me to create and execute this function
function animationLoop(timestamp) {
// 1 - Clear
ctx.clearRect(0, 0, c.width, c.height);
// 2 Draw
board.draw();
pieces.draw();
// call again mainloop after 16.6 ms (60 frames/s)
requestId = requestAnimationFrame(animationLoop);
}
requestId = requestAnimationFrame(animationLoop);
I am confident this is working as this only place I now call board.draw() and it show the initial state and switches to show the solved state after I press the solve button but... still no intermediate states are shown.
I then hypothesised the issue was that solution was so quick that it happens between frames but discounted this by placing this 'delay' in solvePuzzle
if (solutionCount%1000 == 0) {
confirm("Are you sure you wish to continue?");
};
I am now hypothesising solvePuzzle must run to completion before animationLoop can progress.
Is this hypothesis correct?
If so, how can I resolve my issue?
I am thinking I sort of need to continually end and resume my reclusive function at each state but cannot get my head around how I might do this.
Note: another reason I am confident the animation is working is that if I alter board from the console with say a statement like
board.layout[7].available = true;
the expected change is made to the display
JavaScript is single-threaded, and shares this thread with UI updates. Thus, when a function is started from top level, the browser does not do anything else until that function exits. This includes animation frame - animation is happening any time the page's thread is idle and an animation can be scheduled, but while your code is executing it can't.
If your calculation takes time, you need to split it into discrete pieces and let the browser breathe in between if you want UI updated (normally using setTimeout(f, 0), or inside requestAnimationFrame handler).
Another possibility is using Web Workers. They are a way to launch JavaScript in a separate thread. However, they cannot interact with the DOM at all, and can only communicate with messages. So, you can launch your calculation in a Web Worker, then from the worker periodically send messages to your main JS code in order to make it update the DOM in accordance to the results (both interim and final).
Thanks Alexander O'Mara and Kaiido for making me cover cases I forget.

Chrome setInterval crashes at 10000 ms

I'm working on a Javascript stopwatch application, and it works in every browser but Chrome.
Here is a fiddle:
http://jsfiddle.net/djwelsh/Sxyy8/
In theory it is very simple. Clicking the Start button records the epoch time in milliseconds, and starts a setInterval. On each interval, that starting epoch time is subtracted from the current epoch time. This leaves us with a value in milliseconds, which is converted to h:m:s:cs and displayed on the page.
The problem
My problem is with Chrome. Every time the timer reaches 10000 ms, the tab crashes with the "Aw, snap" message.
One bizarre aspect is that the crash still happens if you hit Stop, wait a few seconds, and then hit Start again. This would seem to indicate that it's a memory issue - something is filling up to the point where it cannot hold any more, and overflowing. But inspecting memory in both dev tools and the resource monitor shows nothing at all unusual.
Possible solutions
The problem can be averted by changing the interval value to a number larger than 100 ms (the default I want to use is 50). It can also be averted by logging the timer values in the console, for some reason.
The trouble is, unless I know why it is happening, I can't be confident that these quick-fixes are actually resolving the problem. I don't want to publish the page until I know it will work in all current browsers.
I know this seems like a fairly narrow-scope problem, but I'm hoping the solution will reveal something larger in scope that might help other people (an idiosyncrasy of Chrome's timer functions or something).
EDIT
By the way, I know that stopping and restarting the timer doesn't work the way it ought to in a real stopwatch; I haven't finished implementing that part yet. I thought it would be better to keep it as simple as possible for SO.
For reference (and great justice), here is the updated version. Still crashes at 10000:
http://jsfiddle.net/djwelsh/Sxyy8/7/
SOLUTION
Based on the answer from #Akhlesh, I updated the fiddle. It now runs properly and acts like a stopwatch: http://jsfiddle.net/djwelsh/Sxyy8/18/
In case you're wondering, I need to use the epoch-based technique (as opposed to just incrementing a base value) because sometimes memory usage issues cause the interval not to be called every second - if the tab is moved to the background while the timer is still running, for example.
You can avoid crashing of tab by making time and now variable as global instead of creating those variable again n again inside Update function.
var uTime,uNow;
//Update function will use same variable to initialize time and now
updateTime: function () {
uNow = Date.now();
oO.milliseconds = uNow - oO.epoch;
uTime = oO.getTimeObject(oO.milliseconds);
oO.el.testClock.text('' + uTime.h + ':' + uTime.m + ':' + uTime.s + ':' + uTime.ms + '');
}
Fiddle Demo
I am not sure about the reason but i think GC is not able to deallocate those variable and same time it allocating new variable and that is causing crash.

Can someone debug a progress bar issue in my Javascript applet?

Here is the applet
You can leave all the settings as they are, then hit "Calculate". After a few seconds, you should see some plots show up, then the progress bar below the "Calculate" button will fill up to 100%.
The problem is that I'd like the progress bar to increment while the code is running, not after it has completed as the plots are made. I know the code is long, but you can search for the following progress bar code:
setTimeout( update(count++, L.length, f.length, phi.length) );
It accesses the function update(s,x,y,z) which is defined directly before the main calculate() function.
I'm just confused as to why the progress bar doesn't update until all the processing is complete.
Thanks in advance!
The problem you observe is caused by javascript's single-threaded nature. Timeouts do not get executed while existing code is being executed. Web workers were introduced to deal with just that type of restriction. If you are unable to use web workers(e.g. due to IE limitations), using timeouts is the only way to emulate multythreading.
To check that, you may replace your line with update(count++, L.length, f.length, phi.length)() and change update to log values into console.
As for current update implementation, I suppose either there are some any mini timers inside jquery, causing the issue, or browser rendering capabilities are just not available for some reason:).
The reason is that your calculations and drawings take far less time than timeout. Therefore by the time timeout functions are executed, everything has already been drawn.
You could verify that by replacing your line with update(count++, L.length, f.length, phi.length)() - it will lead to instant update up to 100%.
To get progress bar work more precise you should review your calculation code and try rewriting it in a chunk-friendly manner. I mean having a possibility to execute calculations chunk by chunk and updating progress bar at the end of each chunk. Having that done, you could use timer to evaluate everything.
Sample:
(function(){
var arr = [1,2,3,4];
(function popLog(){
console.log(arr.pop());
if (arr.length > 0){
setTimeout(popLog, 100);
}
})();
})()
Another approach is using web workers, querying the status from time to time and updating progress bar appropriately. However, IE does not support them.

Categories

Resources