Working Time

This sample demonstrates the FlexScheduler workDays, workHours, and nonworkingTime properties. Select a scenario to compare recurring schedules and date-specific exceptions.

FlexScheduler API Reference | SchedulerDefinition API Reference

import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; import { CollectionView } from '@mescius/wijmo'; import { createSchedulerDefinitionPreset, FlexScheduler, SchedulerBuiltInViewItem, SchedulerAxisBindingType, SchedulerTimeUnit, } from '@mescius/wijmo.scheduler'; import { createDate, getEvents, getTeams } from './data'; const splitWeekdays = [ [], [{ start: '13:00', end: '17:00' }], [{ start: '13:00', end: '17:00' }], [{ start: '13:00', end: '16:00' }], [{ start: '13:00', end: '17:00' }], [{ start: '13:00', end: '15:00' }], [], ]; const compressedWeek = [ [], [{ start: '08:00', end: '16:00' }], [{ start: '08:00', end: '16:00' }], [{ start: '08:00', end: '16:00' }], [{ start: '08:00', end: '16:00' }], [], [], ]; const lunchClosures = [11, 12, 13, 14, 15].map((day) => ({ start: createDate(day, 12), end: createDate(day, 13) })); const scenarios = { split: { workHours: [{ start: '09:00', end: '12:00' }], workDays: splitWeekdays, nonworkingTime: [], primary: 'Shared 09:00-12:00', secondary: 'Different afternoon hours', summary: 'Shared morning hours are combined with weekday-specific afternoon shifts.', }, standard: { workHours: [{ start: '09:00', end: '17:00' }], workDays: null, nonworkingTime: [], primary: '09:00-17:00', secondary: 'Monday-Friday', summary: 'A single workHours rule marks the same office hours across the work week.', }, lunch: { workHours: [{ start: '08:00', end: '18:00' }], workDays: null, nonworkingTime: lunchClosures, primary: '08:00-18:00', secondary: 'Lunch 12:00-13:00', exception: '5 recurring closures', summary: 'Concrete non-working ranges close lunch each day inside otherwise open hours.', }, maintenance: { workHours: [{ start: '08:00', end: '18:00' }], workDays: null, nonworkingTime: [ { start: createDate(12, 10), end: createDate(12, 12) }, { start: createDate(14, 14), end: createDate(14, 17) }, ], primary: '08:00-18:00', secondary: 'Normal weekday coverage', exception: 'Tue + Thu maintenance', summary: 'Two date-specific maintenance windows override normal working hours.', }, compressed: { workHours: null, workDays: compressedWeek, nonworkingTime: [], primary: '08:00-16:00', secondary: 'Monday-Thursday', exception: 'Friday closed', summary: 'workDays defines a four-day compressed schedule with Friday fully unavailable.', }, }; document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', init) : init(); function init() { const preset = createSchedulerDefinitionPreset(SchedulerBuiltInViewItem.WorkWeek); const scheduler = new FlexScheduler('#theScheduler', { itemsSource: new CollectionView(getEvents()), resources: [ { fieldExpr: 'teamId', label: 'team', dataSource: getTeams(), valueExpr: 'id', displayExpr: 'name', backgroundColorExpr: 'backgroundColor', foreColorExpr: 'foreColor', }, ], definition: Object.assign(Object.assign({}, preset), { rows: { bindings: [ { type: SchedulerAxisBindingType.Time, unit: SchedulerTimeUnit.Hour, visible: (args) => args.hour >= 8 && args.hour < 18, }, ], } }), toolbarViewItems: [{ name: 'Work Week', key: SchedulerBuiltInViewItem.WorkWeek }], displayDate: createDate(13, 9), }); const scenario = document.querySelector('#scenario'); const status = document.querySelector('#scenarioStatus'); const primaryFact = document.getElementById('primaryFact'); const secondaryFact = document.getElementById('secondaryFact'); const exceptionFact = document.getElementById('exceptionFact'); const applyScenario = () => { const config = scenarios[scenario.value]; scheduler.workHours = config.workHours; scheduler.workDays = config.workDays; scheduler.nonworkingTime = config.nonworkingTime; primaryFact.textContent = config.primary; secondaryFact.textContent = config.secondary; exceptionFact.textContent = config.exception || ''; exceptionFact.hidden = !config.exception; status.value = config.summary; status.title = config.summary; }; scenario.addEventListener('change', applyScenario); applyScenario(); }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS Wijmo Scheduler Working Time</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet"> <!-- SystemJS --> <script src="https://cdn.jsdelivr.net/npm/systemjs@0.21.5/dist/system.src.js" integrity="sha512-skZbMyvYdNoZfLmiGn5ii6KmklM82rYX2uWctBhzaXPxJgiv4XBwJnFGr5k8s+6tE1pcR1nuTKghozJHyzMcoA==" crossorigin="anonymous"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <main class="container-fluid"> <div class="working-time-toolbar"> <div class="scenario-control"> <label for="scenario"><i class="bi bi-clock-history" aria-hidden="true"></i> Scenario</label> <select id="scenario" class="form-select form-select-sm" aria-describedby="scenarioStatus"> <option value="split">Split shifts</option> <option value="standard">Standard office hours</option> <option value="lunch">Daily lunch closure</option> <option value="maintenance">Maintenance exceptions</option> <option value="compressed">Compressed Monday-Thursday</option> </select> </div> <div class="scenario-facts" aria-label="Active working-time rules"> <span id="primaryFact" class="scenario-fact shared-fact">Shared 09:00-12:00</span> <span id="secondaryFact" class="scenario-fact weekday-fact">Weekday afternoons</span> <span id="exceptionFact" class="scenario-fact exception-fact" hidden></span> </div> <output id="scenarioStatus" for="scenario" aria-live="polite"></output> </div> <div id="theScheduler"></div> </main> </body> </html>
export function createDate(day, hour, minute = 0) { return new Date(2026, 4, day, hour, minute); } export function getTeams() { return [ { id: 'operations', name: 'Operations', backgroundColor: '#2563eb', foreColor: '#ffffff' }, { id: 'design', name: 'Design', backgroundColor: '#7c3aed', foreColor: '#ffffff' }, { id: 'support', name: 'Support', backgroundColor: '#047857', foreColor: '#ffffff' }, { id: 'facilities', name: 'Facilities', backgroundColor: '#b45309', foreColor: '#ffffff' }, ]; } export function getEvents() { return [ { id: 1, subject: 'Shift Handoff', start: createDate(11, 9, 30), end: createDate(11, 10, 30), teamId: 'operations', }, { id: 2, subject: 'Studio Review', start: createDate(11, 14), end: createDate(11, 15, 30), teamId: 'design' }, { id: 3, subject: 'Customer Clinic', start: createDate(12, 13), end: createDate(12, 14), teamId: 'support' }, { id: 4, subject: 'Safety Walk', start: createDate(12, 15), end: createDate(12, 16), teamId: 'facilities' }, { id: 5, subject: 'Service Planning', start: createDate(13, 13, 30), end: createDate(13, 15), teamId: 'operations', }, { id: 6, subject: 'Prototype Review', start: createDate(14, 9), end: createDate(14, 10, 30), teamId: 'design' }, { id: 7, subject: 'Coverage Review', start: createDate(14, 15), end: createDate(14, 16), teamId: 'support' }, { id: 8, subject: 'Weekly Inspection', start: createDate(15, 13), end: createDate(15, 14), teamId: 'facilities', }, ]; }
body { color: #1f2937; font-size: 15px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; user-select: none; margin: 0; } .container-fluid { box-sizing: border-box; margin: 0; padding: 5px; } .working-time-toolbar { display: grid; grid-template-columns: minmax(240px, 290px) auto minmax(200px, 1fr); min-height: 46px; align-items: center; gap: 8px 14px; margin-bottom: 6px; padding: 5px 10px; border: 1px solid #dbe2ea; background: #f8fafc; } .scenario-control { display: flex; align-items: center; gap: 8px; } .scenario-control label { display: inline-flex; align-items: center; gap: 5px; margin: 0; font-size: 13px; font-weight: 650; } .scenario-control select { min-width: 0; } .scenario-facts { display: flex; flex-wrap: wrap; gap: 5px; } .scenario-fact { padding: 3px 7px; border: 1px solid #cbd5e1; border-radius: 3px; background: #ffffff; color: #334155; font-size: 12px; font-weight: 600; } .shared-fact { border-left: 3px solid #16803c; } .weekday-fact { border-left: 3px solid #0f6cbd; } .exception-fact { border-left: 3px solid #b42318; } .working-time-toolbar output { overflow: hidden; min-width: 0; color: #475569; font-size: 12px; line-height: 1.35; text-overflow: ellipsis; white-space: nowrap; } .scenario-control select:focus-visible { outline: 2px solid #0f6cbd; outline-offset: 1px; } #theScheduler { height: calc(100vh - 52px); min-height: 560px; } @media (max-width: 1050px) { .working-time-toolbar { grid-template-columns: minmax(240px, 1fr) minmax(300px, 1fr); } .working-time-toolbar output { grid-column: 1 / -1; white-space: normal; } } @media (max-width: 640px) { .working-time-toolbar { grid-template-columns: 1fr; } .scenario-control { align-items: stretch; flex-direction: column; gap: 4px; } .working-time-toolbar output { grid-column: auto; } #theScheduler { height: 680px; min-height: 680px; } } input, textarea, [contenteditable="true"] { user-select: text; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true, }, meta: { '*.css': { loader: 'css' }, }, paths: { // paths serve as alias 'npm:': 'node_modules/', 'cdn:': 'https://cdn.mescius.io/demoapps/packages/wijmojs/5.20262.60-rc/', 'pcdn:': 'https://cdn.jsdelivr.net/npm/', }, // map tells the System loader where to look for things map: { '@mescius/wijmo': 'cdn:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'cdn:@mescius/wijmo.input/index.js', '@mescius/wijmo.scheduler': 'cdn:@mescius/wijmo.scheduler/index.js', '@mescius/wijmo.styles': 'cdn:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'cdn:@mescius/wijmo.cultures', jszip: 'pcdn:jszip@3.8.0/dist/jszip.js', 'bootstrap.css': 'pcdn:bootstrap@5.3.8/dist/css/bootstrap.min.css', css: 'pcdn:systemjs-plugin-css@0.1.37/css.js', 'plugin-babel': 'pcdn:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'pcdn:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', }, packages: { src: { defaultExtension: 'js', }, node_modules: { defaultExtension: 'js', }, }, }); })(this);