Текущий прогресс в неделях, мини-информер
Понадобилось сделать за 5 минут, но может потом пригодиться в других приложениях.
Это примерно то же самое, только без текстового вывода, который, впрочем, показывается в атрибуте title
, если подвести курсор мыши к элементу progress
(в листинге он не стилизован, а целый учебный "мини-фреймоворк" для замены элемента есть вот тут).
Скрипт умеет отсчитывать номер недели, начиная с недели, указанной при вызове вторым аргументом (нумерация недель по ISO, см. также номера недель в календаре) и включая количество недель, переданное третьим аргументом (нумерация производится с единицы).
Первым же аргументом безымянной самовызываемой функции передаётся идентификатор элемента progress
, показывающего, какая часть периода в неделях прошла. Впрочем, элемент не обязан быть именно полоской прогресса, ему достаточно иметь javascript-свойства max
и value
. Индикатор должен автообновляться раз в час.
Ниже показан скрипт в работе (период работы - 17 недель, начиная с 36-й недели 2023-го года) и код приложения.
<progress id="progressBar" value="0" max="100" title="init"></progress> <script> (function (id,startWeek,weeks) { Date.prototype.getWeek = function(year, month, day) { //Номер недели по ISO let date = new Date(year, month, day, 0, 0, 0, 0); date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); let week1 = new Date(date.getFullYear(), 0, 4); return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7); } let elem = document.getElementById(id); function doTimer() { let date = new Date(); let year = date.getFullYear(); let mon = date.getMonth(); let day = date.getDate(); let wday = date.getDay(); let wdays = ['Вс','Пн','Вт','Ср','Чт','Пт','Сб']; let wnum = date.getWeek(year, mon, day) - startWeek + 1; let dt = '' + wdays[wday] + ', ' + day.toString().padStart(2,'0') + '.' + (mon+1).toString().padStart(2,'0') + '.' + year.toString(); elem.title = dt; if (wnum < 1) { elem.value = 0; elem.title += ', до начала периода '+(Math.abs(wnum)+1)+' нед.'; } else if (wnum <= weeks) { let ps = Math.max(Math.min(Math.round(wnum*100/weeks),100),0); elem.value = ps; elem.title += ', '+ wnum+' нед. из '+weeks; } else { elem.value = 100; elem.title += ', период закончен '+(wnum-weeks)+' нед. назад'; } } doTimer(); setInterval(doTimer, 1000*60*60); //раз в час }('progressBar',36,17)); </script>
Конечно, код уже не будет столь простым, если за отсчитываемый период времени возможен переход через год. Я попытался обойтись без перебора дат в цикле, поэтому для расчётов мне пришлось добавить функций:
getWeek (year, month, day)
- Номер недели по ISO для указанной даты;getWeeks (startYear, startWeek, endYear, endWeek)
- Количество недель между неделямиstartWeek
годаstartYear
иendWeek
годаendYear
;datePlusWeeks (year, month, day, numberOfWeeks)
- Дата плюс количество недель;getDateOfWeek (year, week)
- Начало и конец недели номерweek
в годуyear
.
Скрипт ниже считает 100 недель с 8-й недели 2022 года, начавшейся 21 февраля. Можно посчитать вручную, что сегодня, 21.09.2023, идёт 83-я неделя, а 100 недель истекут с окончанием 21-го января 2024 года.
<progress id="progressBar2" value="0" max="100" title="init"></progress> <script> (function (id,startYear,startWeek,weeks) { let getWeek = function (year, month, day) { //Номер недели по ISO для указанной даты let date = new Date(year, month, day); date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); let week1 = new Date(date.getFullYear(), 0, 4); return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7); } let getWeeks = function (startYear, startWeek, endYear, endWeek) { //Количество недель между неделями startWeek года startYear и endWeek года endYear let isISOLeapYear = function (year) { const startsWithThursday = new Date(year, 0, 1).toString().split(' ')[0] === 'Thu' const endsWithThursday = new Date(year, 11, 31).toString().split(' ')[0] === 'Thu' return startsWithThursday || endsWithThursday ? true : false; } let diff = 0; for (let i = startYear; i < endYear; i++) diff += isISOLeapYear(i) ? 53 : 52; return (diff += endWeek - startWeek); } let datePlusWeeks = function (year, month, day, numberOfWeeks) { //Дата плюс количество недель let dateObj = new Date (year, month, day); dateObj.setDate(dateObj.getDate()+ numberOfWeeks * 7); return dateObj; } let getDateOfWeek = function (year, week) { //Начало и конец недели номер week в году year let d = new Date("Jan 01, " + year + " 00:00:00"); let dayMs = (24 * 60 * 60 * 1000); let offSetTimeStart = dayMs * (d.getDay() - 1); let off = d.getDay() > 4 ? 0 : 1; let w = d.getTime() + 604800000 * (week - off) - offSetTimeStart; let n1 = new Date(w); let n2 = new Date(w + 604800000); return { dateFrom: n1, dateTo: n2 }; } let elem = document.getElementById(id); function doTimer() { let date = new Date(), dateObj = getDateOfWeek(startYear,startWeek), dateFrom = dateObj.dateFrom, dateTo = datePlusWeeks (dateFrom.getFullYear(),dateFrom.getMonth(),dateFrom.getDate(),weeks), weekTo = getWeek(dateTo.getFullYear(),dateTo.getMonth(),dateTo.getDate()), allWeeks = getWeeks(startYear,startWeek, dateTo.getFullYear(),weekTo), year = date.getFullYear(), mon = date.getMonth(), day = date.getDate(), wday = date.getDay(), nowWeek = allWeeks - getWeeks(year,getWeek(year, mon, day),dateTo.getFullYear(),weekTo) + 1; let wdays = ['Вс','Пн','Вт','Ср','Чт','Пт','Сб']; let dt = '' + wdays[wday] + ', ' + day.toString().padStart(2,'0') + '.' + (mon+1).toString().padStart(2,'0') + '.' + year.toString(), dt1 = dateFrom.getDate().toString().padStart(2,'0') + '.' + (dateFrom.getMonth()+1).toString().padStart(2,'0') + '.' + dateFrom.getFullYear().toString(); dateTo.setDate(dateTo.getDate()-1); let dt2 = dateTo.getDate().toString().padStart(2,'0') + '.' + (dateTo.getMonth()+1).toString().padStart(2,'0') + '.' + dateTo.getFullYear().toString(), period = '('+dt1+'-'+dt2+')'; elem.title = dt; if (nowWeek < 1) { elem.value = 0; elem.title += ', период начнётся через '+(Math.abs(nowWeek)+1)+' нед. '+period; } else if (nowWeek <= allWeeks) { elem.title += ', '+ nowWeek+' нед. из '+allWeeks+ ' ' + period; let ps = Math.max(Math.min(Math.round(nowWeek*100/allWeeks),100),0); elem.value = ps; } else { elem.value = 100; elem.title += ', период закончен '+(nowWeek-allWeeks)+' нед. назад '+period; } } doTimer(); setInterval(doTimer, 1000*60*60); //раз в час }('progressBar2',2022,8,100)); </script>
20.09.2023, 17:51 [275 просмотров]