Here I come, there I am.

 

В процеса на работа ми се наложи да напиша един обратен таймер за отчитане на време при правене на електронен тест. Чудех се как да го реализирам, а не открих подходящо готово решение на проблема, в следствие на което си написах прост скрип за целта.

Изцяло сървърно решение не ми вършеше работа - всяка секунда трябва да се отброява намаляване на брояча с единица. Очевидно, за целта беше необходимо да се добави JavaScript. От друга страна, броячът за времето можеше да се изманипулира от часовника на потребителската машина, затова предпочетох да го взимам от сървъра.

Имаше и още едно условие: всеки въпрос е на отделна страница, т.е. броячът е персистентен между страниците.

Workaround

Компромисното ми решение бе следното: взима се текущото време от сървъра и се изчислява крайното време, след което трябва да свърши теста (примерно след 30мин, 90мин и т.н.). Извличат се час, минути и секунди, след което се подават на JavaScript. Той стартира таймер и на всяка секунда отмерва оставащото време в намаляващ ред.

Началният и крайният час се записват в сесията при инициализацията. След това единствено се отмерва diff - разликата между текущото време и крайното време, което са оставащите минути до края на теста.

Със сигурност има по-оптимално решение, но това работи в този случай. Ето и логиката в модела от даннитe: test.php (скелета на проектите ми приблизително описан тук):

	date_default_timezone_set('GMT');
 
	if(!isset($_SESSION['startTime'])) {
		$startTime = time();
		$_SESSION['startTime'] = $startTime; // startDate is already used
		$_SESSION['endTime'] = time() + (1.5 * 60 * 60);
	}
	$diffDate = date("H:i:s", ($_SESSION['endTime'] - time()));
	$diff = ($_SESSION['endTime'] - time());
 
	$hours = date('H', $diff);
	$mins = date('i', $diff);
	$secs = date('s', $diff);
 

Важно е в началото да се отбележи timezone, в противен случай се получава непредсказуем ефект в изпълнението на скрипта в различни часови зони. Затова съм го сетнал на GMT, да не мърда излишно.

Във view-то добавяме следното:

<script>
	var time = new Date();
	time.setHours(<?php echo $hours ?>);
	time.setMinutes(<?php echo $mins ?>);
	time.setSeconds(<?php echo $secs ?>);
</script>
...
<div><script>countdown_clock(time.getHours(), time.getMinutes(), time.getSeconds());</script></div>

Създавам JavaScript таймер, на който задавам стойностите от времето на сървъра (оставащите часове, минути и секунди до края на теста). След това викам функцията, която ще отборява стойностите.

Таймерът дори не е необходим, тъй като JS функцията поема единствено числа и работи с часове, минути и секунди.

А ето и самият скрипт: countdown.js

function countdown_clock(hours, minutes, seconds)
{
         html_code = '<div id="countdown"></div>';
 
         document.write(html_code);
 
	if(seconds == 59) {
		seconds = 0;
		if(minutes == 59) {
			minutes = 0;
			hours++;
		}
		else {
			minutes++;
		}
	}
	else {
		seconds++;
	}
         countdown(hours, minutes, seconds);
}
 
function countdown(hours, minutes, seconds)
{
	if(seconds == 0) {
		if(minutes == 0) {
			if(hours == 0) {
				document.getElementById('countdown').innerHTML = "0:00:00";
				return;
			}
			else {
				hours--;
				minutes = 59;
				seconds = 59;
			}
		}
		else {
			minutes--;
			seconds = 59;
		}
	}
	else {
		seconds--;
	}
 
	if(minutes < 10) {
		minutes = "0" + minutes;
	}	
	if(seconds < 10) {
		seconds = "0" + seconds;
	}
 
	document.getElementById('countdown').innerHTML = hours + ':' + minutes + ':' + seconds;
        setTimeout('countdown(' + hours + ',' + minutes + ',' + seconds + ');', 1000);
}

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • MySpace
  • Slashdot
  • Technorati
  • TwitThis
del.icio.us Digg DZone Facebook Google Google Reader Magnolia reddit SlashDot Technorati ReadMe.ru Dobavi.com Dao.bg Lubimi.com Ping.bg Pipe.bg Svejo.net Web-bg.com

Безподобния пост.

Related posts brought to you by Yet Another Related Posts Plugin.

Comments

Leave a Reply