Trying to get timer to start once arrived on the page - javascript

I made the following fiddle of what I have right now..
https://jsfiddle.net/r5yj99bs/1/
I'm trying to start right when I get onto a page, but allowing the option to leave the pause/resume option. Then is there anyway to display the remaining time as '5 minutes' instead of '300 seconds' and then count down that way rather than only seconds.
<button class="start-pause">Start</button>
<h2 class="time-left"></h2>
var times = [];
var counter_interval;
var $time_left = $('.time-left');
var $button = $('.start-pause');
// timer length in seconds
var timer_length = 300;
$('body').on('click', '.start-pause', function() {
// are we starting or stopping?
var starting = times.length % 2 == 0;
times.push(Date.now());
if (starting) {
$button.html('Pause');
counter_interval = setInterval(function() {
var time_left = Math.floor(timer_length - sum_elapsed());
if (time_left < 1) {
clearInterval(counter_interval);
return finished();
}
$time_left.html(time_left);
}, 100);
} else {
$button.html('Resume');
clearInterval(counter_interval);
}
});
var sum_elapsed = function() {
sum = 0;
for (var i=0; i<times.length; i++) {
if (i % 2 == 1) {
sum += (times[i] - times[i-1]);
}
if (i == (times.length - 1)) {
sum += (Date.now() - times[i]);
}
}
// convert milliseconds to seconds
return sum / 1000;
};
var finished = function() {
$button.attr('disabled','disabled').html('Finished');
$time_left.html("Time's Up");
};

There is a good time module called moment. You can get it through npm or from moments.com
That can format relative time to human readable strings.
If you want to do it yourself, take the seconds modulus 60 to get the minutes. Using modulus you can extract all info about hours and so on.

You may change the following line:
$time_left.html(time_left);
to:
$time_left.html(secToMinTxt(time_left));
and add the following functions:
function pad(num) {
var str = "" + num;
var pad = "00";
return pad.substring(0, pad.length - str.length) + str;
}
function secToMinTxt(seconds) {
var min = Math.floor(seconds / 60);
var sec = seconds % 60;
return pad(min) + ":" + pad(sec);
}
JSFiddle reference : https://jsfiddle.net/r5yj99bs/2/

If interpret Question correctly, try using Math.round with argument existing time_left variable divided by 60
var time_left = Math.round(Math.floor(timer_length - sum_elapsed()) / 60);
jsfiddle https://jsfiddle.net/r5yj99bs/3/

Related

HTML 5 Audio Player remaining time show delay

I have a problem with an audio player, when users press play the start-time timer is showing instantly, but remaining-time timer shows with a delay. I'm relatively new to JS, so I can not identify the problem on my own.
Can someone can help me with synching timers (start and remaining) show on play event?
CodePen
var isSeeking = false;
var seek = document.getElementById("seekObj");
var player = document.getElementById("player");
SetSeekColor();
function calculateTotalValue(length) {
var minutes = Math.floor(length / 60),
seconds_int = length - minutes * 60,
seconds_str = seconds_int.toString(),
seconds = seconds_str.split(".")[0],
temp_min = minutes.toString().length === 1 ? "0" + minutes : minutes,
temp_sec = seconds.toString().length === 1 ? "0" + seconds : seconds;
return temp_min + ":" + temp_sec;
}
function calculateCurrentValue(_seconds) {
function padTime(t) {
return t < 10 ? "0" + t : t;
}
if (typeof _seconds !== "number") return "";
if (_seconds < 0) {
_seconds = Math.abs(_seconds);
//console.log(_seconds);
}
var hours = Math.floor(_seconds / 3600),
minutes = Math.floor((_seconds % 3600) / 60),
seconds = Math.floor(_seconds % 60);
var hour = hours > 0 ? padTime(hours) + ":" : "";
return hour + padTime(minutes) + ":" + padTime(seconds);
}
function setupSeek() {
seek.max = player.duration;
}
function seekAudio() {
isSeeking = true;
player.currentTime = seek.value;
isSeeking = false;
}
var prevcurrentime = 0;
function initProgressBar() {
if (!isSeeking) {
seek.value = player.currentTime;
}
var length = player.duration;
var current_time = player.currentTime;
// calculate total length of value
var totalLength = calculateTotalValue(length);
// calculate current value time
var currentTime = calculateCurrentValue(current_time);
if (player.readyState === 4) {
jQuery(".end-time").html(totalLength);
jQuery(".start-time").html(currentTime);
}
//checking if the current time is bigger than the previous or else there will be sync different between remaining and current
if (currentTime > prevcurrentime) {
//calculate the remaining time
var rem_time = length - current_time;
jQuery(".rem-time").html(calculateCurrentValue(rem_time));
}
//setting the previouscurrent time to this current time
prevcurrentime = currentTime;
if (player.currentTime == player.duration) {
$("#play-btn").removeClass("pause");
}
}
function initPlayers(num) {
// pass num in if there are multiple audio players e.g 'player' + i
for (var i = 0; i < num; i++) {
(function() {
// Variables
// ----------------------------------------------------------
// audio embed object
var playerContainer = document.getElementById("player-container"),
player = document.getElementById("player"),
isPlaying = false,
playBtn = document.getElementById("play-btn");
// Controls Listeners
// ----------------------------------------------------------
if (playBtn != null) {
playBtn.addEventListener("click", function() {
togglePlay();
});
}
// Controls & Sounds Methods
// ----------------------------------------------------------
function togglePlay() {
if (player.paused === false) {
player.pause();
isPlaying = false;
$("#play-btn").removeClass("pause");
} else {
$(".start-time").html("");
player.play();
$("#play-btn").addClass("pause");
isPlaying = true;
}
}
})();
}
}
looking good, this is an error in the html. In this piece of code just replace the class rem-time by end-time.
<small style="float: right; position: relative; right: 21px;" class="end-time" onclick="showhideRemaining(this)"></small>
I think the root of your problem lies within the performance of your code. I can't see a big time difference between the two counters, but here are some suggested improvements:
You have the padTime function, so use it (see point 2)!
function padTime(t) {
return t < 10 ? "0" + t : t;
}
no unnecessary or early conversion to strings:
function calculateTotalValue(length) {
var minutes = Math.floor(length / 60);
var seconds = Math.floor(length - minutes * 60);
// use the padTime function here with numbers
return padTime(minutes) + ":" + padTime(seconds);
}
do not query the elements over and over again:
if (player.readyState === 4) {
jQuery(".end-time").html(totalLength);
jQuery(".start-time").html(currentTime);
}
Here, instead of querying the elements (jQuery(".end-time")) every time in your ontimeupdate callback, save the references in variables outside of the callback function.
limit color updates.
setInterval(function() {
SetSeekColor();
}, 34);
Updating the color every millisecond is just overkill. 34 milliseconds should equal something around 30fps.
I noticed you have are planning to have multiple players on one page (initPlayers(num)). Here a few thoughts:
When you initialise the players, save each single player with its UI elements in an Object
initPlayers(jQuery("#player-container").length);: IDs are (must be) unique in an entire HTML Document. This wont work, change it to a class.

How to pause and resume timer object

I am making a timer, well I am making timers...basically you can start one timer for something but then the idea is that in the middle of that you might want to start something else so you can pause it and start another one and then when that is done, you can resume the initial timer.
The timer object is working fine and I can get multiple timers going at the same time...my problem is that when i go to resume the first timer it waits for the amount of time that the other timer has been going before resuming.
I have a basic fiddle of it here: https://jsfiddle.net/1ea07uv9/19/
My apologies for the code...I have been messing around with it trying to get it to work it has become quite the mess...it doesnt work exactly the way I have it in my local environment but it illustrates my problem....in the fiddle if you click begin first timer...wait about ten seconds or so and then click on timer one it stops...for about 10 seconds and then continues...I need it to just continue straight away.
Im pretty sure that it has to do with the lines:
var diff = (new Date().getTime() - currentObj.start) - currentObj.time;
currentObj.timerInit = window.setTimeout(instance, (1000 - diff));
where currentObj.start is now however long you waited behind?
EDIT: It was requested I post my code in this post instead of just a fiddle so here it is
//Array where jobs will be stored
var jobs = [],
begin = false;
//Job object
function Job(name, active, s, m, h, elapsed){
var currentObj = this;
this.name = name;
this.seconds = s;
this.minutes = m;
this.hours = h;
this.time = 0;
this.elapsed = elapsed;
this.timeLimit = 28800;
this.completePercent = 0;
this.jobNumber = 0;
this.timer = function(begin){
var secondStr = '00',
minuteStr = '00',
hourStr = '00';
currentObj.start = new Date().getTime();
function instance(){
currentObj.time += 1000;
currentObj.elapsed = Math.floor(currentObj.time / 1000);
secondStr = currentObj.seconds.toString();
if(secondStr.length == 1){
secondStr = '0' + currentObj.seconds.toString();
}
minuteStr = currentObj.minutes.toString();
if(minuteStr.length == 1){
minuteStr = '0' + currentObj.minutes.toString();
}
hourStr = currentObj.hours.toString();
if(currentObj.seconds <= 58){
currentObj.seconds++;
}else{
currentObj.seconds = 0;
if(currentObj.minutes <= 58){
currentObj.minutes++;
}else{
currentObj.minutes = 0;
currentObj.hours++;
}
}
$('[data-job-id="'+currentObj.jobNumber+'"]').html(hourStr + ':' + minuteStr + ':' + secondStr);
var diff = (new Date().getTime() - currentObj.start) - currentObj.time;
currentObj.timerInit = window.setTimeout(instance, (1000 - diff));
}
if(begin){
currentObj.timerInit = window.setTimeout(instance, 1000);
}
}
this.pause = function(){
clearTimeout(this.timerInit);
}
}
//Create the snooze timer object and chuck it into the array
jobs.push(new Job('snooze', false, 0, 0, 0, 0));
//Begin specific timer
$('#timer_start').click(function(e){
e.preventDefault();
if(jobs.length <= 3){
//Create new job object and push it into the array
jobs.push(new Job('jobNameInput', true, 0, 0, 0, 0));
//Loop through all of the jobs and give it a number (according to its array position)
for(var i=0; i < jobs.length; i++){
jobs[i].jobNumber = i;
//Give the jobs their names but check we arent changing the snooze button!
if(i == jobs.length - 1){
jobs[i].timer(true);
}
}
}else{
alert('sorry mate...you can only have 3 jobs!');
}
});
//Switch timer
$('.start').click(function(){
var thisTimer = $(this).next('.time').attr('data-job-id');
for(var i=0; i < jobs.length; i++){
jobs[i].pause();
}
jobs[thisTimer].timer(true);
});

TimeConvert JavaScript function on Coderbyte

I am doing a challenge on Coderbyte and I would be grateful for any advice on my question:
I know there is an easier way to solve this(which I found later):
function TimeConvert(num) {
var hours = Math.floor(num / 60);
var minutes = num % 60;
return hours + ":" + minutes;
}
...so TimeConvert(123); would be 2:3
I know my answer is more complicated but why is the way I attempted to answer this question not working? What am I missing? It just returns 0:00 for any number entered:
function TimeConvert(num) {
var hours=0;
var minutes=0;
for(var i=0; i<=num; i+=60) {//loop through number every 60
if(num[i]>=60) { //for every 60 add 1 hour
hours+=1;
}else if(num[i]<60){
minutes=num[i];
}
}
var newMinute=0;
if (minutes<10){
newMinutes="0"+minutes;
}else if(minutes>10){
newMinutes=minutes;
}
return(hours + ":" + newMinutes);
}
Thanks guys!^^
Why you doin num[i]>=60? All you need to check is num>=60 and num<60. num[i] will always be an undefined value and num is not a string. (If it would have been a string it num[i] will print the character corresponding to that index.) So you need to compare num and not num[i].
function TimeConvert(num) {
var hours=0;
var minutes=0;
var times = num;
for(var i=0; i<times; i+=60) {//loop through number every 60
if(num>=60) { //for every 60 add 1 hour
hours+=1;
num -= 60;
}else if(num<60){
minutes=num;
}
}
var newMinute=0;
if (minutes<10){
newMinutes="0"+minutes;
}else if(minutes>10){
newMinutes=minutes;
}
return(hours + ":" + newMinutes);
}
console.log(TimeConvert(123));
Updated Fiddle
Thank you! I actually figured out two ways to solve this. First, I should iterate by 1, not 60, and in the first if statement I need to subtract by 60 for every iteration as so:
function TimeConvert(num) {
var hours=0;
var minutes=0;
for(var i=0; i<=num; i++) {
if(num>=60) { //for every 60 add 1 hour
hours+=1;
num-=60;//makes sure that the loop goes every 60
}else if(num<60){
minutes=num;
}
}
//below not necessary for Coderbyte, added for styling reasons. Same for second answer
var newMinute=0;
if (minutes<10){
newMinutes="0"+minutes;
}else if(minutes>10){
newMinutes=minutes;
}
//write minutes not newMinutes(for Coderbyte). Same for second answer.
return(hours + ":" + newMinutes);
}
And I figured how to do this with a while loop:
function TimeConvert(num) {
var hours=0;
var minutes=0;
var newMinutes=0;
while(num>=60) {
hours+=1;
num-=60;
}
if(num<60){
minutes=num;
}
if (minutes<10){
newMinutes="0"+minutes;
}else if(minutes>10){
newMinutes=minutes;
}
return(hours + ":" + newMinutes);
}
You can also include ES6 Template Literals in addition to Math.floor() for a one-line return statement.
function TimeConvert(num) {
return `${Math.floor(num/60)}:${num%60}`;
}

Howto run function every few seconds that has return values?

How can I run this every few second , without blocking the rest of the pagefrom loading.
function Create() {
var SomeArray = [];
for ( var i=0; i<=1 ; i ++) {
SomeArray[i] = (Math.random() * 10) + 1;
//alert(arr[0]);
}
return SomeArray;
}
var x = Create();
alert(x[0] + x[1]);
I was trying this var timer = setInterval(Create, 5000); it prevent loading rest of the page.
i want to get new values every few seconds
A basic example would be:
var counter = 0;
var timerRef;
var increment = function() {
counter += 1;
console.log(counter);
timerRef = setTimeout(increment, 1000);
}
setTimeout(increment, 1000);
// clearTimeout(timerRef);
Please avoid document.write refer the screencast for further details.
setInterval() can be configured to repeatedly call any function you designate at whatever time interval you request. But, you can't retrieve a return value from that function. Instead, you need to process the results from within the callback that you pass to setInterval() or call some other function and pass the results you generate inside the callback. This is how asynchronous functions work in JavaScript. I've provided several examples below of your options:
If you just want to generate two random decimal values between 1 and 10 (inclusive) every 5 seconds, you can do that like this:
var interval = setInterval(function() {
var rand1 = (Math.random() * 10) + 1;
var rand2 = (Math.random() * 10) + 1;
// now insert code here to do something with the two random numbers
}, 5000);
If you wanted the random values to be integers (which is more common), then you would do this:
var interval = setInterval(function() {
var rand1 = Math.floor(Math.random() * 10) + 1;
var rand2 = Math.floor(Math.random() * 10) + 1;
// now insert code here to do something with the two random numbers
}, 5000);
If you want to call a function and pass it those two random numbers, you can do this:
function processRandoms(r1, r2) {
// code here to do something with the two random numbers
}
var interval = setInterval(function() {
var rand1 = Math.floor(Math.random() * 10) + 1;
var rand2 = Math.floor(Math.random() * 10) + 1;
processRandoms(rand1, rand2);
}, 5000);
You can then stop the recurring interval at any time with this:
clearInterval(interval);

Countdown Timer Objects - Javascript

I would like to create a simple timer in Javascript that counts down from a given time until it hits 0. I found this tutorial which worked perfectly. My problem is that I need to place multiple timers on the same page. This tutorial obviously won't do that because it uses global variables (I'm new to JS/Programming so I might not be using the right terms). I tried to re-create the same thing only creating each timer as it's own Object so that they don't interfere with eachother. This is what I have.
function taskTimer(name, startTime) {
this.timer = name;
this.totalSeconds = startTime;
this.tick = function() {
if (this.totalSeconds <= 0) {
return;
}
this.totalSeconds -= 1;
this.updateTimer();
// window.setTimeout("this.tick()", 1000);
};
this.updateTimer = function(){
this.seconds = this.totalSeconds;
this.hours = Math.floor(this.seconds / 3600);
this.seconds -= this.hours * (3600);
this.minutes = Math.floor(this.seconds / 60);
this.seconds -= this.minutes * (60);
this.timeString = this.leadingZero(this.hours) + ":" + this.leadingZero(this.minutes) + ":" + this.leadingZero(this.seconds);
return this.timeString;
};
this.leadingZero = function(time){
return (time < 10) ? "0" + time : + time;
};
}
var testTimer = new taskTimer("timer", 30);
testTimer.tick();
I created one at the end there. Running
testTimer.updateTimer(); returns 00:00:30 which is correct, but running testTimer.tick(); returns no value. There is obviously something wrong with that part of the code I just can't figure it out.
You've got a few problems.
You're calling updateTimer() inside of your tick method, so it
won't ever reach outside of there unless you return it.
With your current setup, you'd have to call tick manually every time you wanted to update the clock, and if you don't do that precisely every one second the timer will be inaccurate.
To go with #2, you shouldn't decrement totalSeconds like you are because it isn't guaranteed that it will be exactly one second between triggers of your timeout. Use dates instead.
Here's what I would do: http://jsfiddle.net/R4hnE/3/
// I added optional callbacks. This could be setup better, but the details of that are negligible.
function TaskTimer(name, durationInSeconds, onEnd, onTick) {
var endTime,
self = this, // store a reference to this since the context of window.setTimeout is always window
running = false;
this.name = name;
this.totalSeconds = durationInSeconds;
var go = (function tick() {
var now = new Date().getTime();
if (now >= endTime) {
if (typeof onEnd === "function") onEnd.call(self);
return;
}
self.totalSeconds = Math.round((endTime - now) / 1000); // update totalSeconds placeholder
if (typeof onTick === "function") onTick.call(self);
window.setTimeout(tick, 1000 / 12); // you can increase the denominator for greater accuracy.
});
// this is an instance method to start the timer
this.start = function() {
if (running) return; // prevent multiple calls to start
running = true;
endTime = new Date().getTime() + durationInSeconds * 1000; // this is when the timer should be done (with current functionality. If you want the ability to pause the timer, the logic would need to be updated)
go();
};
}
// no reason to make this an instance method :)
TaskTimer.prototype.toTimeString = function() {
var hrs = Math.floor(this.totalSeconds / 60 / 60),
min = Math.floor(this.totalSeconds / 60 - hrs * 60),
sec = this.totalSeconds % 60;
return [hrs.padLeft("0", 2), min.padLeft("0", 2), sec.padLeft("0", 2)].join(" : ");
};
var task = new TaskTimer("task1", 30, function() {
document.body.innerHTML = this.toTimeString();
alert('done');
}, function() {
document.body.innerHTML = this.toTimeString();
});
I always have problems with this and in one instance, within the function, I had to redefine it:
this.tick = function() {
self=this;
if (self.totalSeconds <= 0) {
return;
}
self.totalSeconds -= 1;
self.updateTimer();
// window.setTimeout("self.tick()", 1000);
};
Here is another post about that: var self = this?
My version, you can see at:
http://fiddle.jshell.net/hmariod/N7haK/4/
var tmArray = new Array();
var timerRef, timerId=0;
function newTimer(){
try{
if(tmArray.length > 4) throw "Too much timers";
var countDown = parseInt(document.getElementById("tCountown").value,10);
if(isNaN(countDown)) throw "tCountown is NaN";
var tmName = document.getElementById("tName").value;
var nt = new taskTimer(++timerId, tmName, countDown);
createTmElement(timerId, tmName);
tmArray.push(nt);
if(!timerRef) timerRef = setInterval(timerFn, 1000);
showTimers();
}catch(er){
alert("newTimer:" + er);
}
}
function taskTimer(id, name, tCountown) {
this.id = id;
this.tName = name;
this.tCountown = tCountown;
}
function timerFn(){
try{
var i;
killTimer = true;
for(i = 0; i < tmArray.length; i++){
tmArray[i].tCountown--;
if(tmArray[i].tCountown < 0){
tmArray[i].tCountown = 0;
}else{
killTimer = false;
}
}
if(killTimer) clearInterval(timerRef);
showTimers();
}catch(er){
clearInterval(timerRef);
aler("timerFn: " + er);
}
}

Categories

Resources