Agent-readable demo data

Title
Progressive Time Headers (JavaScript Scheduler) | DayPilot Pro for JavaScript Demo
Tree
DayPilot JavaScript Demo
Catalog root
Default
Description
Choose a timeline, then scroll or take an animated jump to the end. Try switching progressive time header rendering off and on with a longer timeline. Progressive rendering Timeline Month · days (31 cells) Year · hours (8,760 cells) Week · minutes (10,080 cells) Month · minutes (44,640 cells) 10 years · hours (87,648 cells) Header content Plain text Rich content Interactive content Scroll to Start Middle End

Inline demo script 1

// Scheduler configuration: an hourly year with progressive time headers.
        // The same configuration is reused when the demo creates a fresh Scheduler.
        const schedulerConfig = {
            startDate: "2026-01-01",
            days: 365,
            scale: "Hour",
            cellWidth: 44,
            timeHeaders: [
                {groupBy: "Month", format: "MMMM yyyy", height: 32},
                {groupBy: "Day", format: "ddd d", height: 52},
                {groupBy: "Hour", format: "h tt", height: 28}
            ],
            progressiveTimeHeaderRendering: true,
            rowHeaderWidth: 140,
            rowHeaderWidthAutoFit: false,
            heightSpec: "Auto",
            rowMinHeight: 42,
            timeRangeSelectedHandling: "Disabled",
            resources: [
                {name: "Room A", id: "A"},
                {name: "Room B", id: "B"},
                {name: "Room C", id: "C"}
            ],
            onBeforeTimeHeaderRender: args => {
                const groupBy = args.control.timeHeaders[args.header.level].groupBy;
                if (groupBy !== "Day") {
                    return;
                }

                const dayOfWeek = args.header.start.getDayOfWeek();
                if (dayOfWeek === 0 || dayOfWeek === 6) {
                    args.header.cssClass = "weekend";
                }
                if (app.elements.content.value === "html") {
                    args.header.html = app.dateLabel(args.header.start);
                }
            }
        };
        let dp = new DayPilot.Scheduler("dp", schedulerConfig);

        // Demo controls: timeline presets, content selection and animated navigation.
        const app = {
            elements: {
                enabled: document.getElementById("enabled"),
                preset: document.getElementById("preset"),
                content: document.getElementById("contentMode"),
                initTime: document.getElementById("initTime"),
                contentHint: document.getElementById("contentHint")
            },
            presets: {
                month: {
                    days: 31,
                    scale: "Day",
                    cellDuration: 1440,
                    cellWidth: 84
                },
                year: {
                    days: 365,
                    scale: "Hour",
                    cellDuration: 60,
                    cellWidth: 44
                },
                week: {
                    days: 7,
                    scale: "CellDuration",
                    cellDuration: 1,
                    cellWidth: 40
                },
                minuteMonth: {
                    days: 31,
                    scale: "CellDuration",
                    cellDuration: 1,
                    cellWidth: 40
                },
                decade: {
                    days: 3652,
                    scale: "Hour",
                    cellDuration: 60,
                    cellWidth: 44
                }
            },
            timeHeaders: {
                Day: [
                    {groupBy: "Month", format: "MMMM yyyy", height: 32},
                    {groupBy: "Day", format: "ddd d", height: 52}
                ],
                Hour: [
                    {groupBy: "Month", format: "MMMM yyyy", height: 32},
                    {groupBy: "Day", format: "ddd d", height: 52},
                    {groupBy: "Hour", format: "h tt", height: 28}
                ],
                CellDuration: [
                    {groupBy: "Day", format: "ddd d MMM", height: 52},
                    {groupBy: "Hour", format: "h tt", height: 28},
                    {groupBy: "Cell", format: "mm", height: 28}
                ]
            },
            contentHints: {
                text: "Simple date labels keep the focus on scrolling through the timeline.",
                html: "Calendar labels pair the weekday with the date. Weekends have a subtle gray background.",
                dom: "Click a bookmark to mark a date, then scroll away and back. Your marked dates stay selected."
            },
            // Keep application state outside header elements, which can be evicted.
            markedDates: new Set(),
            activePreset: "year",

            init(initializationTime) {
                this.showInitializationTime(initializationTime);
                this.updateContentHint();
                this.addEventHandlers();
            },
            addEventHandlers() {
                this.elements.enabled.addEventListener("change", () => this.applySettings());
                this.elements.preset.addEventListener("change", () => this.applySettings());
                this.elements.content.addEventListener("change", () => this.applySettings());

                document.querySelectorAll("[data-jump]").forEach(button => {
                    button.addEventListener("click", () => {
                        const fraction = Number(button.dataset.jump);
                        const date = dp.startDate.addDays(Math.floor(dp.days * fraction));
                        dp.scrollTo(date, "fast");
                    });
                });
            },
            applySettings() {
                const presetName = this.elements.preset.value;
                const preset = this.presets[presetName];
                // Preserve the position when comparing content or rendering modes.
                const scrollX = presetName === this.activePreset ? dp.getScrollX() : 0;
                dp.dispose();

                const options = {
                    ...schedulerConfig,
                    days: preset.days,
                    scale: preset.scale,
                    cellDuration: preset.cellDuration,
                    cellWidth: preset.cellWidth,
                    timeHeaders: this.timeHeaders[preset.scale],
                    progressiveTimeHeaderRendering: this.elements.enabled.checked
                };
                if (this.elements.content.value === "dom") {
                    options.onBeforeTimeHeaderDomAdd = args => {
                        const groupBy = args.control.timeHeaders[args.header.level].groupBy;
                        if (groupBy === "Day") {
                            args.element = this.createDateButton(args.header.start);
                        }
                    };
                }
                dp = new DayPilot.Scheduler("dp", options);
                dp.scrollTo(scrollX);

                // Recreate the Scheduler so every reading measures a fresh init().
                const started = performance.now();
                dp.init();
                this.showInitializationTime(performance.now() - started);
                this.activePreset = presetName;
                this.updateContentHint();
            },
            showInitializationTime(milliseconds) {
                this.elements.initTime.textContent = "Initialization: " + milliseconds.toFixed(0) + " ms";
                this.elements.initTime.title = "Time spent in init(); browser painting follows.";
            },
            updateContentHint() {
                this.elements.contentHint.textContent = this.contentHints[this.elements.content.value];
            },
            dateLabel(date) {
                return `<span class="date-label">
                    <span class="date-weekday">${date.toString("ddd")}</span>
                    <span class="date-number">${date.toString("d MMM")}</span>
                </span>`;
            },
            createDateButton(date) {
                const key = date.toString("yyyy-MM-dd");
                const button = document.createElement("button");
                button.type = "button";
                button.className = "mark-date";
                button.dataset.date = key;
                button.setAttribute("aria-label", "Mark " + date.toString("dddd, MMMM d, yyyy"));
                button.setAttribute("aria-pressed", String(this.markedDates.has(key)));
                button.title = "Mark this date";
                button.innerHTML = `<svg class="mark-icon" viewBox="0 0 16 20" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
                    <path d="M3 2h10v16l-5-3-5 3z"/>
                </svg>` + this.dateLabel(date);
                button.addEventListener("click", event => {
                    event.stopPropagation();
                    if (this.markedDates.has(key)) {
                        this.markedDates.delete(key);
                    }
                    else {
                        this.markedDates.add(key);
                    }
                    button.setAttribute("aria-pressed", String(this.markedDates.has(key)));
                });
                return button;
            }
        };

        // Initialize after app is available to the header-content callbacks.
        const initializationStart = performance.now();
        dp.init();
        app.init(performance.now() - initializationStart);