Agent-readable demo data

Title
Links with Frozen Rows (JavaScript Scheduler) | DayPilot Pro for JavaScript Demo
Tree
DayPilot JavaScript Demo
Catalog root
Default
Description
Keep the broadcast program in a frozen row while scrolling through crew bookings. Select a show to display its four assignment links. Colors connect the show to its crew; the arrows describe assignments, not task dependencies.

Inline demo script 1

/* global DayPilot */
    /* eslint-disable no-use-before-define -- Callbacks run after app initialization. */
    const dp = new DayPilot.Scheduler("dp", {
        startDate: "2027-10-18",
        days: 1,
        scale: "Hour",
        showNonBusiness: false,
        businessBeginsHour: 8,
        businessEndsHour: 20,
        businessWeekends: true,
        timeHeaders: [{groupBy: "Day", format: "dddd, MMMM d, yyyy"}, {groupBy: "Hour", format: "H:mm"}],
        cellWidthSpec: "Auto",
        cellWidthMin: 65,
        rowHeaderWidth: 215,
        heightSpec: "Fixed",
        height: 370,
        eventHeight: 52,
        useEventBoxes: "Never",
        rowMarginTop: 2,
        rowMarginBottom: 2,
        durationBarVisible: false,
        linkCrossGridEnabled: true,
        linkShape: "RightAngled",
        timeRangeSelectedHandling: "Disabled",
        eventDeleteHandling: "Disabled",
        onEventClick: args => app.select(args.e.data.tags.show),
        onLinkClick: args => {
            const booking = dp.events.find(args.link.data.to);
            document.querySelector("#relation").textContent = `${booking.data.tags.role}: ${booking.data.tags.person}, assigned to ${booking.data.tags.showName}.`;
        },
        onBeforeEventRender: args => {
            const show = app.shows.find(item => item.id === args.data.tags.show);
            const focused = app.selected === show.id;
            args.data.backColor = focused ? show.pale : "#f2f4f7";
            args.data.borderColor = focused ? show.color : "#c4cbd4";
            args.data.fontColor = focused ? "#1d3448" : "#687888";
            if (args.data.resource === "program") {
                args.data.backColor = focused ? show.color : "#e8edf2";
                args.data.fontColor = focused ? "#ffffff" : "#4f647a";
            }
        }
    });
    const app = {
        selected: "morning",
        shows: [
            {id: "morning", name: "Morning live", start: 9, end: 10.5, color: "#286aa6", pale: "#e4effa"},
            {id: "midday", name: "Market report", start: 11.5, end: 13, color: "#168075", pale: "#e1f2ef"},
            {id: "afternoon", name: "Studio guests", start: 14, end: 15.5, color: "#a66520", pale: "#fbefdf"},
            {id: "evening", name: "Evening live", start: 17, end: 18.5, color: "#7a59a5", pale: "#f0eafa"}
        ],
        roles: [
            {name: "Producer", people: ["Maya Chen", "Owen Reed", "Sara Khan", "Leo Costa"], setup: 0.5, wrap: 0.25},
            {name: "Camera", people: ["Nina Bell", "Arun Shah", "Eva Novak", "Sam Ortiz"], setup: 0.25, wrap: 0},
            {name: "Sound", people: ["Alex Park", "Lina Berg", "Tom Ellis", "Noor Ali"], setup: 0.75, wrap: 0.5},
            {name: "Captions", people: ["Zoe Martin", "Ben Lee", "Iris Wang", "Adam Brooks"], setup: 0, wrap: 0.75}
        ],
        init() {
            this.buildData();
            dp.init();
            this.render();
            this.shows.forEach(show => {
                const button = document.createElement("button");
                button.type = "button";
                button.dataset.show = show.id;
                button.textContent = show.name;
                button.addEventListener("click", () => this.select(show.id));
                document.querySelector("#programs").appendChild(button);
            });
            this.select(this.selected);
            document.querySelector("#shape").addEventListener("change", ev => dp.update({linkShape: ev.target.value}));
            document.querySelector("#pin").addEventListener("change", () => this.render());
            document.querySelector("#colors").addEventListener("change", () => this.render());
        },
        at(hours) {
            return new DayPilot.Date("2027-10-18").addMinutes(hours * 60);
        },
        buildData() {
            this.resources = [{id: "program", name: "Broadcast program", frozen: "top"}];
            this.events = this.shows.map(show => ({id: show.id, resource: "program", text: show.name,
                start: this.at(show.start), end: this.at(show.end), tags: {show: show.id}}));
            this.links = [];
            this.roles.forEach((role, roleIndex) => {
                this.shows.forEach((show, showIndex) => {
                    const id = `crew-${roleIndex}-${showIndex}`;
                    const person = role.people[showIndex];
                    this.resources.push({id, name: `${person} · ${role.name}`});
                    this.events.push({id, resource: id, text: show.name, start: this.at(show.start - role.setup), end: this.at(show.end + role.wrap),
                        tags: {show: show.id, showName: show.name, role: role.name, person}});
                    this.links.push({id: `assignment-${id}`, from: show.id, to: id, type: "FinishToFinish", color: show.color, width: 2, tags: {show: show.id}});
                });
            });
        },
        select(id) {
            this.selected = id;
            this.render();
            document.querySelectorAll("[data-show]").forEach(button => button.setAttribute("aria-pressed", String(button.dataset.show === id)));
            const show = this.shows.find(item => item.id === id);
            document.querySelector("#relation").textContent = `${show.name}: producer, camera, sound and captions. Other bookings stay visible as availability context.`;
        },
        render() {
            const resources = this.resources.map(row => row.id === "program" ? {...row, frozen: document.querySelector("#pin").value} : row);
            const links = this.links.filter(link => link.tags.show === this.selected)
                .map(link => ({...link, color: document.querySelector("#colors").checked ? link.color : "#697787"}));
            dp.update({resources, events: this.events, links});
        }
    };
    app.init();