Order bars show the fulfilment window. Click a link to see its booking.
/* global DayPilot */
/* eslint-disable no-use-before-define -- Callbacks run after app initialization. */
const dp = new DayPilot.Scheduler("dp", {
startDate: "2027-10-17",
days: 15,
scale: "Day",
timeHeaders: [{groupBy: "Month", format: "MMMM yyyy"}, {groupBy: "Day", format: "ddd d"}],
cellWidthSpec: "Auto",
cellWidthMin: 65,
rowHeaderWidth: 215,
heightSpec: "Fixed",
height: 370,
eventHeight: 56,
rowMarginTop: 2,
rowMarginBottom: 2,
durationBarVisible: false,
treeEnabled: true,
treePreventParentUsage: false,
stickyParents: true,
linkStickyParentsEnabled: true,
linkShape: "RightAngled",
timeRangeSelectedHandling: "Disabled",
eventDeleteHandling: "Disabled",
onBeforeEventRender: args => {
const order = app.orders.find(item => item.id === args.data.tags.order);
const parent = args.data.resource === order.id;
args.data.backColor = parent ? order.color : order.pale;
args.data.borderColor = order.color;
args.data.fontColor = parent ? "#ffffff" : "#20384d";
},
onLinkClick: args => {
const booking = dp.events.find(args.link.data.to);
const order = app.orders.find(item => item.id === booking.data.tags.order);
document.querySelector("#relation").textContent = `${booking.text()} fulfils ${order.name}: ${order.product}.`;
}
});
const app = {
orders: [
{id: "n204", name: "N204 · North Library", product: "24 reading desks", start: 0, end: 9, color: "#286aa6", pale: "#e4effa",
jobs: [{name: "Panel cutting", text: "24 desktops", start: 1, end: 3}, {name: "Frame welding", text: "24 frames", start: 3, end: 5}, {name: "Assembly", text: "24 desks", start: 6, end: 9}]},
{id: "r118", name: "R118 · Riverside Hotel", product: "18 café tables", start: 1, end: 11, color: "#168075", pale: "#e1f2ef",
jobs: [{name: "Panel cutting", text: "18 tabletops", start: 3, end: 5}, {name: "Metalwork", text: "18 table bases", start: 4, end: 7}, {name: "Assembly", text: "18 café tables", start: 8, end: 11}]},
{id: "s306", name: "S306 · South School", product: "32 study chairs", start: 2, end: 12, color: "#a66520", pale: "#fbefdf",
jobs: [{name: "Seat shaping", text: "32 seats", start: 3, end: 5}, {name: "Frame welding", text: "32 chair frames", start: 6, end: 8}, {name: "Upholstery", text: "32 study chairs", start: 9, end: 12}]},
{id: "w072", name: "W072 · West Gallery", product: "12 display benches", start: 0, end: 13, color: "#7a59a5", pale: "#f0eafa",
jobs: [{name: "Timber preparation", text: "12 bench tops", start: 2, end: 5}, {name: "Joinery", text: "12 bases", start: 7, end: 10}, {name: "Finishing", text: "12 display benches", start: 10, end: 13}]},
{id: "e510", name: "E510 · East Clinic", product: "16 storage cabinets", start: 1, end: 12, color: "#587437", pale: "#edf3e4",
jobs: [{name: "Panel cutting", text: "16 cabinet kits", start: 2, end: 4}, {name: "Case assembly", text: "16 cabinets", start: 5, end: 8}, {name: "Fitting", text: "Doors and hardware", start: 9, end: 12}]},
{id: "c091", name: "C091 · City Hall", product: "8 reception units", start: 2, end: 13, color: "#9b5570", pale: "#f7e9ef",
jobs: [{name: "Timber preparation", text: "8 unit kits", start: 3, end: 6}, {name: "Joinery", text: "8 reception units", start: 7, end: 10}, {name: "Finishing", text: "Finish and inspect", start: 11, end: 13}]}
],
init() {
this.buildData();
dp.init();
dp.update({resources: this.resources, events: this.events, links: this.links});
document.querySelector("#shape").addEventListener("change", ev => dp.update({linkShape: ev.target.value}));
document.querySelector("#colors").addEventListener("change", ev => dp.update({links: this.links.map(link => ({...link, color: ev.target.checked ? link.color : "#697787"}))}));
document.querySelector("#follow").addEventListener("change", ev => dp.update({linkStickyParentsEnabled: ev.target.checked}));
},
at(days) {
return new DayPilot.Date("2027-10-18").addDays(days);
},
buildData() {
this.resources = [];
this.events = [];
this.links = [];
this.orders.forEach(order => {
const children = order.jobs.map((job, index) => ({id: `${order.id}-${index}`, name: job.name}));
this.resources.push({id: order.id, name: order.name, expanded: true, children});
this.events.push({id: order.id, resource: order.id, text: `${order.name} · ${order.product}`, start: this.at(order.start), end: this.at(order.end), tags: {order: order.id}});
order.jobs.forEach((job, index) => {
const id = `${order.id}-${index}`;
this.events.push({id, resource: id, text: job.text, start: this.at(job.start), end: this.at(job.end), tags: {order: order.id}});
this.links.push({id: `fulfil-${id}`, from: order.id, to: id, type: "StartToStart", color: order.color, width: 2});
});
});
}
};
app.init();