"Космические" часы вместо полярных
Разных часов на Яваскрипте тут уже много (только последние - раз, два и т.д.), но популярные в сети "полярные часы" всех разновидностей (пример) мне не нравятся своим "исчезающим сектором" при переходе к новой минуте, да ещё тем, что самая быстрая стрелка почему-то всегда двигается по самой большой окружности, что противоречит законам физики :)
Вместо этого мне кажутся приятней вот такие "космические часы" , приведённые ниже в работе и в виде заготовки-исходника (файл .html в кодировке Юникода utf-8 без обрамляющих тегов).
Все размеры относительны и зависят от размеров стороны канвы, возможно, код ещё будет дополняться, поэтому отдельным файлом не прилагаю.
В IE11 и ниже показанный на странице листинг работать не будет из-за аргумента функции по умолчанию вида signed = []
, в MS Edge и остальных современных браузерах (2015 год и новее) всё должно работать.
<div style="margin: 0 auto; text-align: center;"> <canvas id="spaceCanvas" style="background: #000; font-family: sans-serif;"></canvas> </div> <script> function spaceCanvas(id,size) { //Функция-обёртка для часов let canvas = document.getElementById(id); let ctx = canvas.getContext('2d'); canvas.style.width = canvas.style.height = size+'px'; canvas.width = canvas.height = size; //или window.innerWidth, window.innerHeight let centerX = canvas.width/2; let centerY = canvas.height/2; let fontSize = Math.max(Math.floor(size/30),8); let PI = Math.PI, cos = Math.cos, sin = Math.sin; function isLeapYear (y) { return (((y%4==0) && (y%100!=0) || (y%400==0)) ? true : false); } function getDaysInMonth (m,y) { let mondays = [31,28,31,30,31,30,31,31,30,31,30,31]; if (isLeapYear (y) == true) mondays[1]=29; return (mondays[m]); } function now () { let date = new Date(); let hour=date.getHours(); let minute=date.getMinutes(); let sec=date.getSeconds(); let day=date.getDate(); let month=date.getMonth(); //0-11 let year=date.getFullYear(); let weekday=date.getDay();//0-6, с Вс let daysInMonth = getDaysInMonth(month,year); return [hour, minute, sec, day, month, daysInMonth, weekday]; } function pad2 (i) { return String('0' + i).slice(-2); } function drawPlanet(radius, color, dat, all, dat1, all1, signed = []) { //Одна "планета" //Контур из точек по количеству позиций "планеты": ctx.beginPath(); ctx.strokeStyle = color; for (let i=0; i<all; i++) { let theta = (2*PI/all)*i; let cx = centerX + radius * cos((PI/2) - theta); let cy = centerY - radius * sin((PI/2) - theta); ctx.moveTo (cx,cy); ctx.arc(cx,cy,1,0,2*PI); } if (signed.length==0) signed = Array(all).fill(0).map(function(val,i){ return i; }); ctx.stroke(); ctx.closePath(); //Сама "планета": let theta = (2*PI/all1)*dat1; let cx = centerX + radius * cos((PI/2) - theta); let cy = centerY - radius * sin((PI/2) - theta); let alignedDat = isNaN(parseInt(signed[dat])) ? signed[dat] : pad2(signed[dat]); ctx.font = fontSize +'px monospace'; let textWid = ctx.measureText(alignedDat); let arrowRadius = Math.max(Math.floor(textWid.width*2/3),2); ctx.beginPath(); ctx.moveTo (cx,cy); ctx.arc (cx,cy,arrowRadius,0,2*PI); ctx.fillStyle = color; ctx.fill(); ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(alignedDat, cx, cy); ctx.closePath(); } function numberOfDay() { //Номер дня в текущем году let now = new Date(); let start = new Date(now.getFullYear(), 0, 0); let diff = now - start; let oneDay = 1000 * 60 * 60 * 24; let day = Math.floor(diff / oneDay); return day; } function numberOfDays() { //Количество дней в текущем году let now = new Date(); let year = now.getFullYear(); return (year%4==0) && (year%100!=0) || (year%400==0) ? 366 : 365; } function draw() { //Отрисовка всего let date = now(); //[hour, minute, sec, day, month, daysInMonth, weekday] clearScreen(); let minRadius = Math.max(fontSize*2,24), maxRadius = size / 2 - fontSize*2, d = Math.floor((maxRadius-minRadius)/5), hms = date[0]*60*60+date[1]*60+date[2], h24 = 24*60*60; drawPlanet(maxRadius, 'green',date[4]+1, 12, (numberOfDay()-1)*h24+hms, numberOfDays()*h24, ['','янв','фев','мар','апр','май','июн','июл','авг','сен','окт','ноя','дек']); //month let days = Array(date[5]+1).fill(0).map(function(val,i){ return i; }); drawPlanet(maxRadius - d, 'red',date[3], date[5], (date[3]-1)*h24+hms, date[5]*h24, days); //day drawPlanet(maxRadius - 2*d, 'gray',date[6], 7, date[6]*h24+hms,7*h24, ['Вс','Пн','Вт','Ср','Чт','Пт','Сб']); //weekday drawPlanet(minRadius + 2*d, 'blue',date[0], 24, hms, h24); //hours drawPlanet(minRadius + d, 'darkcyan',date[1], 60, date[1]*60+date[2], 60*60); //min drawPlanet(minRadius, 'magenta',date[2], 60, date[2], 60); //sec } function clearScreen() { ctx.clearRect(0, 0, canvas.width, canvas.height); } draw(); setInterval (draw, 1000); } //spaceCanvas window.addEventListener ('load', function (e) { spaceCanvas('spaceCanvas',600); //id канвы, размер её стороны }); </script> <noscript> <div style="margin: 0 auto; text-align: center;"> Включите в браузере JavaScript для работы приложения! </div> </noscript>
P.S. Ниже прикреплена версия скрипта, работающая в Internet Explorer 11 (исключено определение массивов как []
и методы массивов map
и fill
). Увидеть, что изменилось в исходнике, можно, открыв исходник прикреплённой страницы.
В самом новом на сегодня "Wordpress" этот код отлично добавился как виджет типа "HTML-код".
spaceClock_IE11.html, открыть в текущей вкладке (5 Кб)
Версия, которая также совместима с IE11 + дополнительно должна адаптироваться к изменениям размера окна браузера (особенно удобно нажать в браузере клавишу F11 для полноэкранного отображения):
spaceClock_fullScreen.html, открыть в текущей вкладке (5 Кб)
12.03.2020, 17:18 [1729 просмотров]