Scheduler weeks in year view on timeline

10 posts, 0 answers
  1. Rami
    Rami avatar
    19 posts
    Member since:
    Sep 2017

    Posted 10 Nov 2017 Link to this post

    Hello,

     

    There doesn't seem to currently be a year view for the scheduler that would display time in weeks in a timeline, am I correct in this? On the other hand, is there any detailed documentation for implementing your own views. I mean documentation on what functions to overwrite in TimelineMonthView / what they do exactly and what the different timeslots and groups are.

  2. Ivan Danchev
    Admin
    Ivan Danchev avatar
    1579 posts

    Posted 13 Nov 2017 Link to this post

    Hello Rami,

    An year view as the one you described is not included among the built-in Scheduler views. See the following demo, which demonstrates the available Timeline views.
    As for creating a custom view we do not have a tutorial article that explains in detail the functions in a specific view, instead the documentation shows different examples of building custom views:
    Regards,
    Ivan Danchev
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  3. Rami
    Rami avatar
    19 posts
    Member since:
    Sep 2017

    Posted 15 Nov 2017 in reply to Ivan Danchev Link to this post

    Hello,

     

    I have made minor progress and the layout is starting to form as you can see in the attached picture. I haven't quite gotten to grips with the different slots that there are in the scheduler source code, day- and timeslots and the collections that can be formed from either type of slot. Could you give me a pointer on how I would accomplish the goal of having weeks in the scheduler with these slots and still have use of the dragging and rendering capabilities of the scheduler? Should every week be a timeslot and the year a collection of them?

  4. Rami
    Rami avatar
    19 posts
    Member since:
    Sep 2017

    Posted 16 Nov 2017 in reply to Rami Link to this post

    I can't edit my post(?), so I'll post here. For anyone stumbling on this, I mostly got it working, some details to work out still. I made sure to set the layout how I wanted it, and then the timeslots to be a week long and that seems to work.
  5. Ivan Danchev
    Admin
    Ivan Danchev avatar
    1579 posts

    Posted 17 Nov 2017 Link to this post

    Hello Rami,

    We are glad you've managed to implement the desired view layout.

    Regards,
    Ivan Danchev
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  6. Oliver
    Oliver avatar
    2 posts
    Member since:
    Aug 2017

    Posted 16 Jan in reply to Rami Link to this post

    Hello Rami

    This is exactly what I need to do for a project, would you be able to share the method and implementation please?

    It would really help?

    Ollie

  7. Rami
    Rami avatar
    19 posts
    Member since:
    Sep 2017

    Posted 16 Jan in reply to Oliver Link to this post

    Sure thing Oliver. Just remember that this solution is cobbled together from reading the Telerik source codes and seems to just about work for what I intend to use it for. And as such, I'm sure it'll break in interesting ways and might even not work at all for you.

    Below is the sourcecode for the "weeks in year with grouped resources view". I saved it as WeekYearView.js and then included it in my Index.cshtml. It works (if I remember correctly) by making the "slots" the scheduler uses to be week long and then using those with the default implementation.

     

    var WeeksTimelineGroupedView = kendo.ui.scheduler.TimelineGroupedView.extend({
        _addContent: function (dates, columnCount, groupsCount, rowCount, start, end, slotTemplate, isVerticalGrouped) {
            //      console.log('_addContent');
     
            var view = this._view;
            var html = '';
     
            for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
                html += '<tr>';
                for (var groupIdx = 0; groupIdx < groupsCount; groupIdx++) {
                    for (idx = 0; idx < dates.length; idx += 7) {
                        html += '<td> </td>';
                    }
                }
                html += '</tr>';
            }
            return html;
        },
        _addTimeSlotsCollections: function (groupCount, tableRows) {
            //      console.log("_addTimeSlotsCollections");
     
            var view = this._view;
     
            for (var groupIndex = 0; groupIndex < groupCount; groupIndex++) {
                var cells = tableRows[groupIndex].children;
                var day = view._startDate;
                var ci = 0;
                var collection = view.groups[groupIndex].getTimeSlotCollection(0);
     
                while (day < view._endDate) {
                    cells[ci].setAttribute('role', 'gridcell');
                    cells[ci].setAttribute('aria-selected', false);
     
                    collection.addTimeSlot(cells[ci], day, kendo.date.addDays(day, 7), true);
                    day = kendo.date.addDays(day, 7);
                    ci++;
                }
            }
        },
        // don't hide headers
        _hideHeaders: function () {
            //      var view = this._view;
            //      view.timesHeader.find('table tr:last').hide();
            //      view.datesHeader.find('table tr:last').hide();
        }
    });
     
    // because kendo.date.weekInYear is returning invalid results
    function getWeekInfo(d) {
        // Copy date so don't modify original
        d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
        // Set to nearest Thursday: current date + 4 - current day number
        // Make Sunday's day number 7
        d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
        // Get first day of year
        var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
        // Calculate full weeks to nearest Thursday
        var weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
     
        // Return week number, month and year
        return {
            week: weekNo,
            month: d.getMonth(),
            year: d.getUTCFullYear()
        };
    };
     
    var WeekYearView = kendo.ui.TimelineView.extend({
        _getGroupedView: function () {
            //      console.log('_getGroupedView');
     
            return new WeeksTimelineGroupedView(this);
        },
     
        name: "WeekYearView",
     
        options: {
            columnWidth: 35,
            currentTimeMarker: false,
            height: 700
        },
     
        previousDate: function () {
            var s = this.startDate();
            return kendo.date.dayOfWeek(kendo.date.addDays(s, -30), 1, -1);
        },
     
        // advance by.... one month?
        nextDate: function () {
            var s = this.startDate();
            return kendo.date.dayOfWeek(kendo.date.addDays(s, 30), 1, -1);
        },
     
        // make it one year, from the monday starting with selected date
        calculateDateRange: function () {
            //      console.log('calculateDateRange');
     
            var selectedDate = this.options.date,
                start = kendo.date.dayOfWeek(selectedDate, 1, -1),
                end = kendo.date.dayOfWeek(new Date(selectedDate.getFullYear() + 2, selectedDate.getMonth()), 1, 1), dates = [];
            //          end = kendo.date.dayOfWeek(new Date(selectedDate.getFullYear(), selectedDate.getMonth() + 4), 1, 1), dates = [];
     
            while (start < end) {
                dates.push(start);
                start = kendo.date.nextDay(start);
            }
     
            this._render(dates);
        },
     
        // make proper slots
        _calculateSlotRanges: function () {
            //      console.log('_calculateSlotRanges');
     
            var dates = this._dates;
            var slotStartTime = this.startTime();
            var slotEndTime = this.endTime();
     
            slotEndTime = kendo.date.getMilliseconds(slotEndTime);
            slotStartTime = kendo.date.getMilliseconds(slotStartTime);
     
            if (slotEndTime === slotStartTime) {
                slotEndTime += kendo.date.MS_PER_DAY - 1;
            } else if (slotEndTime < slotStartTime) {
                slotEndTime += kendo.date.MS_PER_DAY;
            }
     
            var slotRanges = [];
     
            // week long slots?
            for (var i = 0; i < dates.length; i += 7) {
                var rangeStart = kendo.date.getDate(dates[i]);
                kendo.date.setTime(rangeStart, slotStartTime);
                var rangeEnd = kendo.date.getDate(dates[i]);
                kendo.date.setTime(rangeEnd, slotEndTime);
     
                slotRanges.push({
                    start: kendo.date.toUtcTime(rangeStart),
                    end: kendo.date.toUtcTime(rangeEnd)
                });
            }
     
            this._slotRanges = slotRanges;
        },
     
        _layout: function (dates) {
            //      console.log('_layout');
     
            var columns = [];
            var that = this;
            var rows = [{ text: that.options.messages.defaultRowText }];
            var groupedView = that._groupedView;
     
            /*      var weekNumTemplate = kendo.template('<span class=\'k-link k-nav-day\'>#=kendo.date.weekInYear(date)#</span>');
            var monthNumTemplate = kendo.template('<span class=\'k-link k-nav-day\'>#=kendo.format(\'{0:MMM}\', date)#</span>');
            var yearNumTemplate = kendo.template('<span class=\'k-link k-nav-day\'>#=kendo.format(\'{0:yyyy}\', date)#</span>');
            var weekNumTemplate = kendo.template('<span class=\'k-link k-nav-day\'>#=getWeekInfo(date).week#</span>');
            var monthNumTemplate = kendo.template('<span class=\'k-link k-nav-day\'>#=getWeekInfo(date).month#</span>');
            var yearNumTemplate = kendo.template('<span class=\'k-link k-nav-day\'>#=getWeekInfo(date).year#</span>');*/
     
            // loop months over weeks
            for (var idx = 0; idx < dates.length; idx++) {
                var info = getWeekInfo(dates[idx]);
     
                // has year column already?
                for (var yIdx = 0; yIdx < columns.length; yIdx++) {
                    if (columns[yIdx].yearNum == info.year) break;
                }
     
                if (yIdx >= columns.length) {
                    var yr = {
                        //                  text: yearNumTemplate({ date: dates[idx] }),
                        text: info.year,
                        className: 'k-slot-cell',
                        columns: [],
                        weeks: [],
                        yearNum: info.year,
                        colspan: 1
                    };
     
                    columns.push(yr);
                    yIdx = columns.length - 1;
                } else {
                    columns[yIdx].colspan++;
                }
     
                // has month column already?
                for (var mIdx = 0; mIdx < columns[yIdx].columns.length; mIdx++) {
                    if (columns[yIdx].columns[mIdx].monthNum == info.month) break;
                }
     
                if (mIdx >= columns[yIdx].columns.length) {
                    var mn = {
                        //get some localization here please
                        text: new Date(2018, info.month, 1).toLocaleString("en-us", { month: "short" }),
                        className: 'k-slot-cell',
                        columns: [],
                        monthNum: info.month,
                        colspan: 1
                    };
     
                    columns[yIdx].columns.push(mn);
                    mIdx = columns[yIdx].columns.length - 1;
                } else {
                    columns[yIdx].columns[mIdx].colspan++;
                }
     
                // has timeslot already?
                for (var wIdx = 0; wIdx < columns[yIdx].weeks.length; wIdx++) {
                    if (columns[yIdx].weeks[wIdx] == info.week) break;
                }
     
                if (wIdx >= columns[yIdx].weeks.length) {
                    var ts = {
                        //text: weekNumTemplate({ date: dates[idx] }),
                        text: info.week,
                        className: 'k-slot-cell',
                        colspan: 1,
                        weekNum: info.week
                    }
     
                    columns[yIdx].weeks.push(info.week);
                    columns[yIdx].columns[mIdx].columns.push(ts);
                    weekColumn = ts;
                } else {
                    weekColumn.colspan++;
                }
            }
     
            var resources = this.groupedResources;
     
            if (resources.length) {
                if (this._groupOrientation() === 'vertical') {
                    rows = groupedView._createRowsLayout(resources, null, this.groupHeaderTemplate, columns);
                    columns = groupedView._createVerticalColumnsLayout(resources, null, this.groupHeaderTemplate, columns);
                } else {
                    columns = groupedView._createColumnsLayout(resources, columns, this.groupHeaderTemplate, columns);
                }
            }
            return {
                columns: columns,
                rows: rows
            };
        },
        _groups: function () {
            //      console.log('_groups');
     
            var groupCount = this._groupCount();
            var dates = this._dates;
            this.groups = [];
     
            for (var idx = 0; idx < groupCount; idx++) {
                var view = this._addResourceView(idx);
                var start = dates[0];
                var end = dates[dates.length - 1 || 0];
                var startTime = kendo.date.getMilliseconds(this.startTime());
                var endTime = kendo.date.getMilliseconds(this.endTime());
     
                if (startTime !== 0 && endTime <= startTime) {
                    start = kendo.date.getDate(start);
                    kendo.date.setTime(start, startTime);
                    end = kendo.date.getDate(end);
                    kendo.date.setTime(end, endTime);
                }
     
                view.addTimeSlotCollection(start, kendo.date.addDays(end, 1));
            }
     
            this._timeSlotGroups(groupCount);
        },
        _timeSlotGroups: function (groupCount) {
            //      console.log('_timeSlotGroups');
     
            var tableRows = this.content.find('tr');
            tableRows.attr('role', 'row');
            this._groupedView._addTimeSlotsCollections(groupCount, tableRows);
        }
    });

     

    And then I use the C# helpers to actually add the Scheduler to my .cshtml with the custom view defined above:

    @(Html.Kendo().Scheduler<SchedulerReservationViewModel>()
                    .Name("scheduler")
                    .Height(900)
                    .Timezone("Etc/UTC")
                    .Views(v => {
                        v.TimelineWeekView(wv => wv.ColumnWidth(40));
                        v.TimelineWorkWeekView(wwv => wwv.Groups(gr => gr.Date(true)));
                        v.TimelineMonthView(mv => { mv.ColumnWidth(40); });
                        v.CustomView("WeekYearView", mv => mv.Selected(true));
                    })

     

    Oh, and I should mention, I've only used this with grouped resources and with the orientation being vertical: (.Group(gr => gr.Resources("Resource").Orientation(SchedulerGroupOrientation.Vertical))

     

    Hope this helps,

    Rami

  8. Rami
    Rami avatar
    19 posts
    Member since:
    Sep 2017

    Posted 16 Jan Link to this post

    Oh, and I forgot. The result should be something like this:

     

     

  9. Oliver
    Oliver avatar
    2 posts
    Member since:
    Aug 2017

    Posted 17 Jan in reply to Rami Link to this post

    Rami,

    Thank you so much for this.

    This has really saved me about 2 weeks of work and of course works perfectly. If our paths ever cross, ill buy you a beer!

    Oliver.

  10. Rami
    Rami avatar
    19 posts
    Member since:
    Sep 2017

    Posted 17 Jan in reply to Oliver Link to this post

    Okay, good to hear. As a last warning, there might be a bug where if the dates (or atleast the startdate?) are not mondays, the grid gets misaligned visually because some slots have fewer days etc.

     

    Rami

Back to Top