Реалізація годинникового таймеру із застосуванням бібліотеки jQuery та елементу HTML5 CANVAS

листопад 2015

Досить часто при побудові елементів веб-сайту необхідно прив'язати таймер. Наприклад, може бути така задумка як попередня затримка повторного повідомлення коментарів (щоб спамер не відправляв повідомлення кожні 2 секунди) чи скажімо реалізація таймеру для тесту (пройти максимальну кільrsсть питань тесту за відведений час) та й для реалізації будь-яких інших задумок веб-програміста.

Зразок таймеру

Особисто до вподоби ось такий таймер (900 секунд):

jQuery плагін можна переглянути, наприклад, тут

рис.1. jQuery плагін TimeCircles

Що ж давайте спробуємо розібратись, як таку штуку реалізувати....

Алгоритм роботи таймеру. Коротко.

Реалізувати таймер на веб-сторінці досить просто, використовуючи метод setInterval() мови програмування javascript.

Синтаксис:
setInterval(function,milliseconds)

SetInterval() постійно виконує функцію через вказаний проміжок часу. В нашому випадку можна оновлювати числа на веб-сторінці, що відповідають таймеру, через 1 секунду.
Якщо необхідно зупинити дію методу setInterval() використовується метод clearInterval().

Приклад зупинки методу SetInterval() ресурс w3schools


<p>A script on this page starts this clock:</p>
<p id="demo"></p>

<button onclick="myStopFunction()">Stop time</button>

<script>
var myVar = setInterval(function(){ myTimer() }, 1000);

function myTimer() {
    var d = new Date();
    var t = d.toLocaleTimeString();
    document.getElementById("demo").innerHTML = t;
}

function myStopFunction() {
    clearInterval(myVar);
}
</script>

Графіка таймеру. Елемент HTML5 CANVAS

рис.2. Шаблон кругового таймеру

Дещо детальніше про графічне зображення таймеру.
Як варіант можна застосувати елемент HTML5 CANVAS.
Елемент HTML5 <canvas> використовується для створення графічних зображень за допомогою мови програмування javascript.

Елемент HTML5 <canvas> лише контейнер для реалізації графічних зображень.

<canvas> має декілька методів, щоб створити лінії, дуги, текст та для роботи безпосередньо із малюнком.
HTML Canvas може малювати текстові повідомлення, кольорові, з чи без анімації.
Має можливість для створення графіків.
Є можливість рухати об'єкти, наприклад, зобразити анімований м'яч і більш складніші анімації.
А також реалізувати інтерактивну веб-сторінку із користувачем та об'єктом HTML Canvas.

Матеріали для опрацювання:

Навчальний матеріал HTML Canvas ресурсу w3schools

Довідник ресурсу w3schools тегів HTML Canvas

Реалізація контейнеру для графічних зображень <canvas> може виглядати слідуючим чином:

<canvas> id="myCanvas" width="200" height="100"></canvas>

Елемент <canvas> повинен мати id, з яким будуть працювати методи javascript.
Ширина та висота необхідна, щоб визначити розміри canvas.
На сторінці може бути декілька контейнерів canvas.
За замовчуванням canvas не має ні границь, ні атрибутів.

Створення шаблону таймеру

Щоб створити шаблон таймеру з круговою діаграмкою, що дещо вище зображений( рис.2), варто написати код javascript:


// контейнер для графічного зображення
<canvas id="Canvas_area" width="200" height="150" style="border:1px solid #d3d3d3;">
</canvas>

<script>
//розшукуємо на сторінці елемент з id=Canvas_area
var Canvas_area = document.getElementById("Canvas_area");

// створюємо HTML обєкт з яким будемо проводити графічні операції
var can = Canvas_area.getContext("2d");

// виводимо текст 10 sec за координатами 60,80
can.font='25px Arial';
can.fillText("10 sec",60,80);

// малюємо круг із сірим фоном
can.beginPath();
can.lineWidth = 20;// ширина кругу
can.strokeStyle = "#CDCDCD";

// круг із координатами 100,75 радіусом 50, початок та кінець дуги, 
can.arc(100,75,50,0*Math.PI,0.001*Math.PI,true);

// stroke - вказуємо промалювати все, що ми вище вказали
can.stroke();

// і ще промалюємо зелену частину півкола таймеру
can.beginPath();
can.lineWidth = 15;
can.strokeStyle = "#00E600";
can.arc(100,75,50,0.3*Math.PI,1.5*Math.PI,true);
can.stroke();

</script>

Проведемо невеличкі зміни в кодові скрипту та об'єднаємо скрипт таймеру і графіку...

Об'єднуємо скрипт таймеру та графіку

Пригадаємо математику, щодо створення дуги методом arc()...

створення дуги в канвас

рис.3. Позиція кута при зображенні дуги

Що не може не радувати справжнього програміста, так як годинник ж завжди розпочинається саме там де 0 радіан, та що казати, краще показати звідки розпочинається таймер в такому випадку:

рис.4. Початок відліку таймеру за умови кут 0 радіан (варіант "капець")



Але ж що то за "капець" такий, получився, цифри таймеру наклались один на одну???
Для аналізу можна переглянути код скрипту та помітити, тому що...


// контейнер для графічного зображення
<canvas id="Canvas_area" width="200" height="150" >
</canvas>
<button onclick="Start_Timer()" id="start_test_timer">Старт</button>

<script>
var timer;
var canvas = document.getElementById("Canvas_area");
var ctx = canvas.getContext("2d");

// сіра основа таймеру -->
ctx.beginPath();
ctx.lineWidth = 20;
ctx.strokeStyle = "#CDCDCD";
ctx.arc(75,75,50,0,2*Math.PI);
ctx.stroke();

// текст 10 
ctx.font='35px Arial';
ctx.fillText("10",60,90);

// визначаємо частинки круга
var Estimated_Time = 10;
var Timer_Element = 2/Estimated_Time;
var Clock_Estimated_Time = 0;

// малюємо таймер		
function Msg_Timer(){
  Estimated_Time--;
  if (Estimated_Time == 0){  	
   Stop_Timer();   	
  };
  Clock_Estimated_Time = Clock_Estimated_Time + Timer_Element;   
  ctx.beginPath();  
  
  ctx.beginPath();
  ctx.strokeStyle = "#00E600"; 
  ctx.lineWidth = 15;  
  ctx.arc(75,75,50,0,Clock_Estimated_Time*Math.PI);
  ctx.stroke();  
  ctx.font='35px Arial';
  ctx.fillText(Estimated_Time,60,90);    		
}; 
	
function Start_Timer() {    
  timer = setInterval(function(){ Msg_Timer() } , 1000);
  // деактивуємо кнопку старту
  $('#start_test_timer').prop('disabled', true);
};
 
function Stop_Timer() {
  clearInterval(timer);
}; 

</script>

Незнаю, хто там що помітив, але нам потрібно:
1. повернути таймер на -90°...
2. та реалізувати скрипт так, щоб цифри таймеру не накладувались одна на одну...

Щоб вирішити перше питання застосуємо метод rotate(), що повертає контейнер на вказаний кут angle

context.rotate(angle);

Правда тут виникла інша проблема цифри таймеру контейнеру анімації


ctx.font='35px Arial';
ctx.fillText("text",60,90);

де "text" - цифри таймеру,
також повернулись -90° , тому позиціювання цифр таймеру (розміщення в центрі круга) вирішив через div із style {position:absolute}

Що ж до другого питання, то проблема в тому, що необхідно з кожною секундою заново промальовувати контейнер, попередньо очистивши старе графічне зображення методом HTML canvas clearRect().

context.clearRect(x,y,width,height);

У всякому випадку я вирішив проблему таким чином, що ж тепер таймер виглядає таким чином:

рис.5. Кінцевий варіант таймеру



Кінцевий вигляд скрипту таймеру має вигляд:


// контейнер для цифри таймеру
<div id="for_time"></div>
// контейнер для графічного зображення
<canvas id="Canvas_area" width="200" height="150" >
</canvas>
<button onclick="Start_Timer()" id="start_button">Старт</button>

<script>
var canvas = document.getElementById("Canvas_area");
var ctx = canvas.getContext("2d");

// розпочинаємо малювати графіку
ctx.beginPath();

// повертаємо контейнер на -90°
ctx.rotate(-90 * Math.PI / 180);
    
//та дещо зміщуємо всторону контейнер;
ctx.translate(-150, 0);
ctx.lineWidth = 20;
ctx.strokeStyle = "#CDCDCD";
ctx.shadowBlur=20;
ctx.shadowColor="#CDCDCD";
ctx.arc(75, 75, 50, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();

//оголошуємо змінні таймеру
var Estimated_Time;
var Timer_Element;
var Clock_Estimated_Time;
var timer;

//ініціалізуємо
function init()
{
  Estimated_Time = 10;
  Timer_Element = 2 / Estimated_Time;
  Clock_Estimated_Time = 0;
}

init();
    
//позиціонуємо цифри
$( "#for_time" ).text( Estimated_Time );

// запускаємо та малюємо таймер		
function Msg_Timer(){
   Estimated_Time--;
   if (Estimated_Time == 0){
     Stop_Timer(); 
     // активуємо кнопку старту 
     // при слідуючому запуску таймеру   
     $('#start_button').prop('disabled', false);	
   };
   
   $( "#for_time" ).text(Estimated_Time);
   Clock_Estimated_Time = Clock_Estimated_Time + Timer_Element;   
   ctx.beginPath();
   ctx.clearRect(0, 0, 200, 150);   
   ctx.lineWidth = 20;
   ctx.strokeStyle = "#CDCDCD";
   ctx.shadowBlur=20;
   ctx.shadowColor="#CDCDCD";
   ctx.arc(75,75,50,0,2*Math.PI);
   ctx.stroke();
   ctx.beginPath();
   ctx.strokeStyle = "#2ade2a"; 
   ctx.lineWidth = 15; 
   ctx.shadowBlur = 18;
   ctx.shadowColor = "#079907"; 
   ctx.arc(75, 75, 50, 0, Clock_Estimated_Time * Math.PI);
   ctx.stroke();	
};	
 
function Start_Timer(){
     init();   
     timer = setInterval(Msg_Timer, 1000);
     // деактивуємо кнопку старту
     $('#start_button').prop('disabled', true);
};
  
 function Stop_Timer(){
   clearInterval(timer);   
 };

</script>



На цьому знайомство із реалізацією таймеру та HTML Canvas вважаю завершено.

- Успіхів в програмуванні.