БлогNot. Годовой круг со стрелкой на JavaScript

Годовой круг со стрелкой на JavaScript

Мне кажется симпатичной идея визуализировать не примитивно отдельную неделю, а целый год как круг времени, по которому движется стрелка, показывающая текущий день.

В этом скрипте мне нужно было сделать следующее:

  • создать элемент div, у которого фоном наложена картинка с годовым кругом. Центрировать картинку можно с помощью стилевого указания, её фон вне круга прозрачен;
  • при первом вызове функции yearCycle создать канву и разместить её в div;
  • написать функцию (img.onload) для вывода рисунка .png (или .gif) с прозрачным фоном, размещённого в центре канвы и повёрнутого относительно этого центра на нужный угол (желательно, чтобы расчёт не зависел от размеров рисунка); также есть код для проведения линии из центра канвы под нужным углом (закомментирован в листинге);
  • рассчитать угол поворота рисунка со стрелкой, исходя из номера текущего дня в году и общего количества дней в нём;
  • вывести немного ниже центра канвы текущую дату в текстовом виде;
  • обеспечить вызов основной функции один раз в час для обновления информации.

Углы считаются как на циферблате аналоговых часов со стрелками - то есть, по часовой стрелке и угол, равный нулю градусов (и 360 градусам) находится вверху в положении цифры "12".

Ниже показан скрипт в работе и полный исходник на момент написания.

Возможно, вам придётся поменять пути к картинкам url(back.gif) и img.src = 'arrow.png'; (см. в исходнике).

Предполагается, что исходник будет добавлен к файлу типа .html в кодировке Юникода utf-8, но это не обязательно.

Скрипт в работе:

фоновая картинка скрипта back.gif для указания в стиле раздела div
фоновая картинка скрипта back.gif для указания в стиле раздела div
стрелка с прозрачным фоном arrow.png для указания в операторе img.src = '...'
стрелка с прозрачным фоном arrow.png для указания в операторе img.src = '...'
<div id="clockDiv" 
 style="margin: 0 auto; text-align: center; background: url(back.gif) center no-repeat;">
</div>
<script>
function yearCycle (id,createCanvas) {
 let container = document.getElementById (id);
 let canvas;
 if (createCanvas) { //В первый раз создать канву
  canvas = document.createElement('canvas');
  canvas.id = id + '_canvas';
  container.appendChild (canvas);
 }
 else canvas = document.getElementById (id + '_canvas'); //Затем получать id готовой
 let ctx = canvas.getContext('2d');
 let w = canvas.width = 450;
 let h = canvas.height = 450; //Размеры канвы - по фоновой картинке контейнера
 let cx = w/2, cy=h/2; //Центр канвы

 //Нарисовать белую окружность по центру канвы:
 let radius = 74;
 ctx.beginPath();
 ctx.fillStyle='#fff';
 ctx.arc(cx, cy, radius, 0, Math.PI * 2, true); 
 ctx.fill();

 let toRadians = function (degree,addition) { return (degree + addition) * Math.PI / 180.0; }

 //Рассчитать угол поворота стрелки:
 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;
 }

 let num = numberOfDay();
 let nums = numberOfDays();
 let degree = num * 360 / nums; //Угол пока задан в градусах

/*
 //Так можно нарисовать линию с тем же углом (блок закомментирован):
 ctx.beginPath();
 ctx.moveTo (cx, cy);
 ctx.strokeStyle = '#07f';
 let radians = toRadians(degree,-90);
 let x1 = cx + radius * Math.cos(radians);
 let y1 = cy + radius * Math.sin(radians);
 ctx.lineTo(x1,y1);
 ctx.stroke();
*/
 //Вместо этого нарисуем "прицел"
 ctx.strokeStyle = '#ccc';
 ctx.setLineDash([2,5]);
 ctx.beginPath();
 for (let deg=0; deg<=360; deg+=90) {
  let rad = toRadians(deg,-90);
  let x1 = cx + radius * Math.cos(rad);
  let y1 = cy + radius * Math.sin(rad);
  ctx.moveTo (cx,cy);
  ctx.lineTo (x1,y1);
 }
 ctx.stroke();

 //Вывести рисунок-стрелку с поворотом на угол degree градусов относительно центра канвы:
 let img = new Image();
 img.src = 'arrow.png';
 img.onload = function() {
  let cache = this; //кэшируем копию рисунка
  let iw = cache.width;
  let ih = cache.height; //не будем зависеть от размеров рисунка при расчёте координат
  ctx.save();
  ctx.translate(cx ,cy);
  ctx.rotate(toRadians(degree,0));
  ctx.translate(-(w/2), -(h/2));
  ctx.drawImage(img, w/2 - iw/2, h/2 - ih/2, iw, ih);
  ctx.restore();
 }

 //Вывести дату:
 function strDate() { //дата в формате "Четверг, 31 декабря 2020, день 366"
  let dt = new Date();
  let monthes = [ 'января','февраля','марта','апреля','мая','июня',
   'июля','августа','сентября','октября','ноября','декабря' ];
  let weekdays = ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'];
  return weekdays[dt.getDay()]+', '+dt.getDate()+' '+
   monthes[dt.getMonth()]+' '+dt.getFullYear()+', день '+numberOfDay();
 }

 ctx.fillStyle='#111'; 
 let fontSize = 14; //размер шрифта в пикселях
 ctx.font = fontSize+"px sans-serif";
 ctx.textAlign = "center";
 ctx.textBaseline="middle";
 ctx.fillText(strDate(),cx,cy+fontSize);
}

window.addEventListener ('load', function (e) {
 yearCycle ('clockDiv',true);
 setInterval (yearCycle, 1000*60*60, 'clockDiv', false); //Вызываем раз в час
}); 
</script>
<noscript>
 <div style="margin: 0 auto; text-align: center;">
  Включите в браузере JavaScript для работы приложения!
 </div>
</noscript>

теги: программирование дата javascript время графика

показать комментарии (1)

26.02.2020, 22:31; рейтинг: 391