Створіть аналоговий годинник за допомогою полотна

від IQAndreas | 26 лютого 2014 року

Сьогодні ми виготовимо класичний аналоговий годинник, використовуючи функції полотна, знайдені в HTML5. Годинник, який ви будете створювати, виглядатиме наступним чином:

Цей годинник насправді живе! Він повинен відображати ваш поточний системний час та оновлення, коли проходить кожна секунда. У цьому підручнику ви дізнаєтеся все про те, як це зробити. Давайте розпочнемо.

Дуже важлива примітка

У рамках створення нашого годинника ви отримаєте бонусні бали, якщо будете слухати будь-яку музику відповідної тематики!

Починаємо

Ми збираємось поступово додавати HTML, CSS та JavaScript, щоб врешті-решт створити наш чудовий аналоговий годинник. Почнемо спочатку з базового HTML. Створіть новий документ HTML і додайте такий код:

Якщо ви переглянете те, що ми маємо на даний момент, насправді не так багато для побачення. Давайте частково це виправимо, додавши наступний CSS між тегами стилю:

І нарешті, давайте додамо трохи JavaScript, щоб все почало рухатися! Додайте такий код всередину тегів сценарію:

На цьому етапі перегляньте свою сторінку. Якщо ваша сторінка виглядає не так, перевірте, чи правильно ви завантажили JavaScript:

аналоговий

Тепер, коли ми маємо основи і працюємо, настав час перейти до цього.

Виготовлення цифрових годинників

Отже, ви хочете зробити аналоговий годинник? Поволі там, приятелю!

Спочатку ми додамо цифровий годинник. Причина в тому, що це допоможе нам навчитися використовувати клас Date - клас, який містить багато функціональних можливостей, які ми будемо використовувати для відображення правильного часу. По-друге, починаючи з цифрового годинника, значно полегшить налагодження нашого аналогового годинника (повірте мені на цьому).

Отримання дати

Якщо ви хочете отримати поточний час у JavaScript, це можна зробити, просто викликавши new Date (). Відредагуйте свій існуючий код JavaScript усередині функції displayTime, додавши два виділені рядки:

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

Хоча це не годинник ні в цифровому, ні в аналоговому сенсі, принаймні ми рухаємось у напрямку, який здається правильним. З урахуванням сказаного, вказана дата БАГАТО більше інформації, ніж нам насправді потрібно. Нам доведеться написати власний код для відображення часу, а не покладатися на toString () для правильного форматування.

Щоб допомогти нам трохи спростити дані, клас Date має кілька методів. Зараз все, про що нам потрібно турбуватися, це часові функції:

Оскільки всі ці значення є числами, хоча це може бути не завжди потрібно, нам справді слід перетворити їх за допомогою String (num), перш ніж намагатися відобразити їх:

Ваш повний код усередині функції displayTime тепер виглядатиме так:

Якщо ви переглянете те, що у вас є зараз, ви побачите щось таке, що виглядає наступним чином:

Ну це працює, але це виглядає трохи «смішно». По-перше (якщо ви проігноруєте годинну частину), ви помітите, що з’являється незвичний час 18: 54: 1. Більшість цифрових годинників додають додаткові нулі до хвилини та другої частини, щоб забезпечити двозначне значення, тож годинник насправді повинен відображатись 18:54:01 .

Додамо функцію з назвою padZero який додає нуль до початку числа, якщо потрібно:

Ця функція padZero приймає число як аргумент. Якщо число має менше двох цифр (тобто менше 10), ми додаємо нуль на початку числа, щоб воно відображалося як дві цифри з 0, що становить першу цифру. Якщо число вже є двоцифровим, ми нічого не робимо, а просто розшифровуємо його як частину повернення.

Давайте використаємо цю функцію в нашому прикладі. Замініть рядок змінної timeString такою зміненою версією:

Наш повний JavaScipt на даний момент буде виглядати так:

На цьому етапі ваш час тепер відображатиметься більш правильно, без однозначних чисел, що не відображаються без нуля перед ними. Однак є одна річ, яка буде виглядати дивно.

Але це армійський час!

Якщо ви країна, яка не використовує цілодобовий годинник (кашель, кашель, Америка), вас може заплутати або, принаймні, дратувати той факт, що годинне значення на нашому годиннику перевищує 12. Хоча цілодобовий годинник зрозуміліше і менш двозначне, ми могли б також перетворити його на 12-годинний годинник, щоб усі люди по всьому світу могли це зрозуміти.

Ми напишемо функцію, яка перетворює годину на 12-годинну. По-перше, ми будемо використовувати оператор модуля, щоб переконатися, що година є значенням між 0 і 11. Але оскільки немає 0-й години в 12-годинному годиннику, ми переконуємось, що значення ніколи не відображається, змінюючи його на 12 замість цього.

Для цього виконайте функцію formatHour:

Крім того, нам все ще потрібен спосіб визначити, чи використовувати AM або PM. Спосіб його налаштування дещо хитрий (замовлення - 11 ранку, 12 вечора, 13 вечора, коли насправді, було б більш розумно називати це 12 ранку). Ви можете написати функцію, яка робить це ретельно, але ми скористаємось ярликом, який може бути не дуже зрозумілим. але це працює:

Після того, як ви додали до коду функції formatHour і getTimePeriod, продовжуйте і знову модифікуйте свою змінну timeString усередині displayTime наступним чином:

Якщо ви переглянете свою сторінку ще раз, тепер ваш час відображатиметься наступним чином:

Тадааа! Тепер у вас є цифровий годинник. Він не оновлюється щосекунди, але наразі це нормально. Ми розглянемо цю деталь в рамках створення нашого аналогового годинника найближчим часом.

Малювання аналогового годинника

Тут починається найцікавіше! Пам’ятаєте той елемент, який так терпляче чекав нас? Трохи складно зрозуміти, де знаходиться сторінка, тож давайте «просунемо», перенісши наш контур з цифрового годинника на наше полотно.

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

Якщо ви попередньо переглядаєте свою сторінку, тепер ви побачите окреслене полотно на відміну від самого часу:

Тестування полотна

Давайте переконаємося, що наше полотно працює належним чином, намалювавши на ньому кілька ліній. Буде зручно залишити там цифровий годинник (таким чином ми бачимо поточний час над аналоговим годинником), тому просто залиште старий JavaScript всередині функції displayTime там, де він є, і додайте код для аналогового годинника відразу після нього.

Спочатку ми проведемо червону лінію від центру годинника праворуч (3 години). Додайте такі виділені рядки до функції displayTime:

При попередньому перегляді ви побачите суцільну червону лінію, що відображається посередині вашого аналогового годинника. Зробимо ще одну зміну. Додамо чорну лінію від центру до верху (12 годин). Зверніть увагу, що нам не потрібно повторно створювати змінні canvas або контекст, ми можемо просто повторно використовувати ті, які ми створили для червоного рядка.

Додайте цей код відразу після рядка context.stroke ():

Якщо ви попередньо переглядаєте документ зараз, ви побачите чорну лінію на додаток до червоної:

Вуху, зараз щодня 3 години; ніякої школи!

Хоча цей годинник гарантовано буде правильним двічі на день, він все ще недостатньо практичний для наших цілей. Нам потрібен більший контроль над тим, куди спрямована ця зброя.

Попередження: математика попереду!

На жаль, ця частина вимагає певної тригонометрії. Знання лише основ повинно завести вас далеко, але одне, що ви, можливо, не використовували - це Тау постійний. Подумайте про це як про кращу версію Пі коли справа стосується речей у колах. Ви можете дізнатись більше про Тау (та Пі) з наступного відео Академії Хана.

Так. в рамках пояснення того, що ми будемо робити, давайте поки що подумки видалимо чорну стрілку і просто зосередимось на правильному обертанні червоної годинникової стрілки. Коли годинна стрілка вказує на 2 години, вона зникла 2/12-й цілодобово. Отже, о 2 годині наша годинна стрілка вказує на те, що є TAU * (2/12) радіан.

Якщо ми хочемо отримати це значення автоматично за допомогою коду, ми зробимо щось на зразок наступного:

Далі нам потрібно знати довжину руки; наразі ми зробимо стрілку довжиною радіуса годинника так, щоб вона вказувала на крайній край годинника. Все, що нам потрібно зробити, це просто підключити ці цифри до існуючого коду. Знайдіть коментар, який говорить Покладіть сюди математику, і замінити його такими рядками коду:

А тепер ми його малюємо. Знайдіть такі рядки:

Тепер замініть два виділені рядки наступними двома рядками:

Якщо все правильно, під час попереднього перегляду сторінки ви побачите стрілку годинника, яка вказує на ту годину, яку вона наразі для вас:

Ми добираємось туди. повільно.

Додавання Іншої зброї

Зараз ми просто правильно налаштували годинну стрілку. Тепер ми могли б просто скопіювати та вставити код для відображення стрілки годин, але відредагувати його на хвилини та секунди. Недоліком цього блискучого плану є те, що він потребує багато коду, і це не зробить нас дуже хорошими розробниками. Натомість ми можемо поставити все це у функцію, яка залучає руки до нас.

Для цього потрібно буде видалити та замінити деякий код. Усередині функції displayTime видаліть все після декларації Math.TAU. Ваша функція displayTime повинна виглядати наступним чином:

Тепер, після декларації Math.TAU, додайте наступні рядки коду:

Тепер ваша повна функція displayTime повинна виглядати наступним чином:

Якщо ви попередньо переглянете документ зараз, ви побачите щось таке:

Тепер ви повинні побачити суцільні червоні лінії, що представляють годину, хвилину та друге значення вашого часу.

Витратьте кілька хвилин, щоб переглянути код і побачити, як все, здається, працює разом. Коли ви це зробите, є одна важлива річ, яку ми повинні пам’ятати. Скажімо, зараз час 3:10; відповідно до нашого коду, значення години становить 3, так воно подорожувало 3/12 цілодобово (TAU * (3/12) радіан). Хвилинне значення 10, але воно ще не подорожувало 10/12 цілодобово! Він лише подорожував 10/60 цілодобово (TAU * (10/60) радіан).

Ось чому замість передачі поточного значення (як у прикладі, 3 для години та 10 для хвилини) ми передаємо змінну з іменем progress функції drawArm, яка представляє, як далеко за годинник пройшла стрілка. Значення 0 означає, що ви опівдні, і 0,5 означає, що ви вказуєте прямо о 6 годині, і значення 0,25 означає, що стрілка спрямована вправо на трійку годинника.

Тепер, коли ви краще уявляєте, як працює наш код, давайте виправимо щось, що зараз дратує годинник. Ну, ми можемо бачити зброю, але всі вони виглядають однаково. Давайте додамо ще кілька параметрів до нашої функції drawArm (), щоб ми могли визначити різницю між ними.

Змініть (або замініть) функцію drawArm наступним чином:

Подібно до того, що ми зробили вище з прогресом, параметром armLength може бути значення від 0 до 1. Значення 1 означає, що воно доходить до краю годинника, тоді як значення 0,5 означає, що вперта дрібниця проходить лише половину шляху. Таким чином, навіть якщо ми змінимо розмір годинника, він не зіпсує нам руки.

Тепер ви можете налаштувати свої руки до душі! Місце, де ви вказуєте ці параметри, - це виклик drawArm, і це робиться в наступних трьох рядках:

Я хотів залишитися настільки ж вірним «класичному» зовнішньому вигляду годин, тож продовжуйте і замінюйте ці рядки наступними параметрами для вибраного кольору та розміру:

Якщо ви попередньо переглядаєте документ зараз, годинник повинен виглядати так:

Додатковий кредит

Спробуйте встановити параметри вашої руки на від’ємні значення або значення, більші за 1, і подивіться, яке задоволення може з цього вийти.

Здійснення руху годинникових стрілок

Годинник виглядає чудово, але це якось так. не рухається. Зараз ще не 22:10:55, це 10 секунд тому. Не було б чудово, якби стрілки годинника рухались самі по собі?

Чому ніщо не рухається

Замість того, щоб спершу занурити голову, щоб зробити аналоговий годинник, ми спершу відвідаємо наш оригінальний цифровий годинник. Давайте подивимось на першу частину нашого коду (на самому початку, який говорить нам не малювати годинник, поки не завантажиться вся сторінка):

Цей код викликається один раз, оскільки сторінка завантажується лише один раз. Щоб повернути цю точку справді додому, це означає, що функція displayTime () запускається лише один раз. Як би ми запустили його знову і знову і знову. і знову?

Представляємо setInterval ()

Зручна функція setInterval () запускатиме функцію знову і знову з пробілом між кожним викликом. Ця функція має два параметри:

  1. Функція, яку потрібно запустити
  2. Кількість мілісекунд між кожним запуском

Одна мілісекунда - це 1/1000 секунди. Якщо ви хочете запустити функцію (наприклад, фіктивну функцію checkEmail) кожні 5 секунд (5000 мілісекунд), ви використовуєте такий код:

Це змусить JavaScript діяти так (зауважте, що це починається з очікування):

Якщо ви хочете зупинити запуск setInterval, вам потрібно відстежувати значення, яке повертає setInterval при першому його запуску, а потім передайте це саме значення clearInterval. Це, мабуть, звучить заплутано, тому наступний приклад показує, як це працює:

Тепер, коли ви побачили основи setInterval, давайте використаємо його магічні сили з нашими годинниками.

Оновлення нашого годинника

Зараз у нас є прослуховувач подій, який прослуховує подію DOMContentLoaded/span> і викликає функцію displayTime:

Давайте змінимо це. Замість того, щоб наш прослуховувач подій викликав displayTime, давайте змінимо його, щоб викликати функцію, яка називається startTimer. Поки ми це робимо, давайте також додамо функцію startTimer:

Що ми зробили, так це, щоб наша сторінка викликала функцію startTimer, як тільки вона завантажиться. Ця функція містить функцію setInterval, яка кожного разу викликає displayTime 1000 мілісекунд (так само 1 секунда). Крім того, слід зауважити одне. Оскільки ми хочемо відображати час відразу після завантаження сторінки, а не чекати 1 секунди, поки виклик setInterval активує displayTime, ми одночасно явно викликаємо displayTime на додаток до нашого виклику setInterval:

Попередньо перегляньте документ зараз і подивіться, як все виглядає. Через кілька секунд ви побачите щось таке:

Очевидно, щось не так. Що відбувається просто. Щосекунди ви малюєте лінії на полотні. Проблема в тому, що ви ніколи не кажете полотну видалити будь-яку зі старих ліній, тому воно просто тримає їх там. Ви можете очистити область полотна за допомогою функції clearRect (). Якщо ви хочете очистити все полотно (що ми робимо в цьому випадку), просто додайте наступний виділений рядок перед вашим дзвінком до функцій drawArm:

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

Висновок

Тепер, коли наш аналоговий годинник закінчений, цифровий нам більше не знадобиться. Ви можете видалити його та відповідний код, або ви можете просто приховати його за допомогою CSS:

Хоча наші аналогові годинники зараз функціональні, вони все ще не дуже гарні; з цим можна зробити ще багато речей! Це та частина, коли ви починаєте займатися творчістю. Додайте свої власні штрихи до годинника та розкажіть нам, що ви робили у цій темі.