UNPKG

@progress/kendo-angular-gantt

Version:
202 lines (201 loc) 8.42 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { orderBy } from '@progress/kendo-data-query'; import { isWorkDay, isWorkHour, lastDayOfWeek } from '../utils'; import { addDays, firstDayInWeek, getDate, firstDayOfMonth, lastDayOfMonth, addMonths, addWeeks, lastMonthOfYear, cloneDate } from '@progress/kendo-date-math'; const setTime = (origin, candidate) => { const date = cloneDate(origin); date.setHours(candidate.getHours(), candidate.getMinutes(), candidate.getSeconds(), candidate.getMilliseconds()); return date; }; /** * @hidden */ export const DAY_FORMAT = 'E d/MM'; /** * @hidden */ export const HOUR_FORMAT = 'HH:mm aa'; /** * @hidden */ export const MONTH_FORMAT = 'MMM'; /** * @hidden */ export const YEAR_FORMAT = 'yyyy'; const END_OF_DAY_DATE = new Date(1980, 0, 1, 23, 59, 59, 999); /** * @hidden */ export class TimelineBaseViewService { intlService; mapper; options; _viewStart = 0; constructor(intlService, mapper) { this.intlService = intlService; this.mapper = mapper; } get viewStart() { return this._viewStart; } /** * * @param tasks - The tasks which are going to be rendered in the table * @returns {Object} - An object containing the range start and end dates */ getRange(tasks) { if (!tasks || !tasks.length) { return { start: new Date(), end: new Date() }; } const startResult = orderBy(tasks, [{ field: this.mapper.taskFields.start, dir: 'asc' }]); const endResult = orderBy(tasks, [{ field: this.mapper.taskFields.end, dir: 'desc' }]); const rangeStart = new Date(this.mapper.extractFromTask(startResult[0], 'start')); const rangeEnd = new Date(this.mapper.extractFromTask(endResult[0], 'end')); const start = this.getStartOffset(rangeStart); const end = this.getEndOffset(rangeEnd); this._viewStart = Number(start); return { start: new Date(start), end: new Date(end) }; } /** * * @param start - The tasks' range start date * @param end - The tasks' range end date * @returns {Array<Object>} - A collection containing the hour slots */ getHours(start, end, customDateFormat) { const slots = []; const workDayStart = this.intlService.parseDate(this.options.workDayStart).getHours(); const workDayEnd = this.intlService.parseDate(this.options.workDayEnd).getHours(); // TODO: retrieve from option? const hourSpan = 1; let startDate = new Date(start); const hoursFormat = customDateFormat ? customDateFormat : HOUR_FORMAT; const endDate = new Date(end); while (startDate < endDate) { const slotEnd = new Date(startDate); const isWorkSlot = isWorkHour(slotEnd, workDayStart, workDayEnd); slotEnd.setHours(slotEnd.getHours() + hourSpan); slots.push({ start: startDate, end: slotEnd, isWorking: isWorkSlot, text: this.intlService.formatDate(startDate, hoursFormat, this.intlService.localeId), span: 1, slotWidth: this.options.slotWidth }); startDate = slotEnd; } return slots; } /** * * @param start - The tasks' range start date * @param end - The tasks' range end date * @returns {Array<Object>} - A collection containing the day slots */ getDays(start, end, customDateFormat) { const slots = []; let startDay = new Date(start); const dayFormat = customDateFormat ? customDateFormat : DAY_FORMAT; const endDay = new Date(end); while (startDay <= endDay) { // Get the days with cleared time values (except for start and end day) const nextDay = getDate(addDays(startDay, 1)); const isWorking = isWorkDay(startDay, this.options.workWeekStart, this.options.workWeekEnd); // Need to get the end date with correct hours (important for day view) const slotEnd = endDay < nextDay ? endDay : nextDay; slots.push({ start: startDay, end: slotEnd, isWorking: isWorking, text: this.intlService.formatDate(startDay, dayFormat, this.intlService.localeId), span: 1, slotWidth: this.options.slotWidth }); startDay = nextDay; } return slots; } getWeeks(start, end, customDateFormat) { const weekStart = this.intlService.firstDay(); const slots = []; let startDay = new Date(start); const dayFormat = customDateFormat ? customDateFormat : DAY_FORMAT; const endDay = new Date(end); while (startDay <= endDay) { const lastWeekDay = lastDayOfWeek(startDay, weekStart); const slotEnd = lastWeekDay > endDay ? endDay : lastWeekDay; const daySlots = this.getDays(startDay, slotEnd); const span = daySlots.length; const firstDay = this.intlService.formatDate(firstDayInWeek(getDate(startDay), weekStart), dayFormat, this.intlService.localeId); const lastDay = this.intlService.formatDate(slotEnd, dayFormat, this.intlService.localeId); if (span > 0) { slots.push({ start: daySlots[0].start, end: setTime(daySlots[span - 1].end, END_OF_DAY_DATE), text: `${firstDay} - ${lastDay}`, span: span, slotWidth: this.options.slotWidth }); } startDay = firstDayInWeek(addWeeks(slotEnd, 1), weekStart); } return slots; } getMonths(start, end, isMainViewType, customDateFormat) { const slots = []; let startDay = new Date(start); const monthFormat = customDateFormat ? customDateFormat : MONTH_FORMAT; const endDay = new Date(end); while (startDay < endDay) { const endMonth = lastDayOfMonth(startDay); const slotEnd = endDay < endMonth ? endDay : endMonth; const daySlots = this.getDays(startDay, slotEnd); const weekSlots = this.getWeeks(startDay, slotEnd); const span = isMainViewType ? daySlots.length : weekSlots.length; const monthStart = firstDayOfMonth(getDate(startDay)); const shortText = this.intlService.formatDate(monthStart, monthFormat, this.intlService.localeId); if (span > 0) { slots.push({ start: isMainViewType ? daySlots[0].start : weekSlots[0].start, end: isMainViewType ? daySlots[span - 1] : setTime(weekSlots[span - 1].end, END_OF_DAY_DATE), span: span, text: shortText, slotWidth: this.options.slotWidth }); } startDay = firstDayOfMonth(addMonths(slotEnd, 1)); } return slots; } getYears(start, end, customDateFormat) { const slots = []; let startDay = new Date(start); const endDay = new Date(end); const yearFormat = customDateFormat ? customDateFormat : YEAR_FORMAT; while (startDay < endDay) { const yearEnd = lastDayOfMonth(lastMonthOfYear(startDay)); const slotEnd = endDay < yearEnd ? endDay : yearEnd; const monthSlots = this.getMonths(startDay, slotEnd); const span = monthSlots.length; if (span > 0) { slots.push({ start: monthSlots[0].start, end: setTime(monthSlots[span - 1].end, END_OF_DAY_DATE), span: span, text: this.intlService.formatDate(slotEnd, yearFormat), slotWidth: this.options.slotWidth }); } startDay = addDays(slotEnd, 1); } return slots; } }