v7.3.0
SupportExamplesFree Trial

What's new in Scheduler v5.0.0+

Scheduler v5.0.0

New JavaScript bundles for combining products

Each product now has a new ES module based JavaScript bundle that only contains the product specific code, called a thin bundle. They are intended to be used when combining multiple products on page, to avoid having shared code loaded multiple times. Previously if you combined for example Grid and TaskBoard on a single page you would import from these bundles (minified size):

  • grid.module.min.js (~993 kB)
  • taskboard.module.min.js (~1100 kB)

Both products are built upon Bryntum's core library and hence both of them include the core JavaScript (buttons, toolbars, helpers etc.). With thin bundles you would instead import what you need from each product in the hierarchy separately:

  • core.module.thin.min.js (~643 kB)
  • grid.module.thin.min.js (~268 kB)
  • taskboard.module.thin.min.js (~88 kB)

This way the shared code (from core) is only included once. With the old approach, about 2 MB of JavaScript was loaded, with the new about 1 MB.

The gain (loss actually) will be greater if you combine products that share even more code, like Gantt and Calendar. Calendar builds upon Scheduler > Grid > Core, while Gantt builds upon Scheduler Pro > Scheduler > Grid > Core. When not using thin bundles:

  • gantt.module.min.js (~1978 kB)
  • calendar.module.min.js (~1833 kB)

With thin bundles (many since these products build upon others):

  • core.module.thin.min.js (~643 kB)
  • grid.module.thin.min.js (~268 kB)
  • scheduler.module.thin.min.js (~466 kB)
  • schedulerpro.module.thin.min.js (~119 kB)
  • engine.module.thin.min.js (~266 kB)
  • gantt.module.thin.min.js (~122 kB)
  • calendar.module.thin.min.js (~164 kB)

Total ~ 3811 kB vs 2048 kB (1763 kB less).

You import from the thin bundles in the same way as with any other ES modules bundle. The difference compared to using the full bundles is that you have to import from the correct bundle. For example to use the StringHelper class from Core and GridRowModel from Grid, previously you would have something similar to this:

import { StringHelper, GridRowModel } from 'grid.module.js';

Now you have to import them separately (since they are from different bundles):

import { StringHelper } from 'core.module.thin.js';
import { GridRowModel } from 'grid.module.thin.js';

New CSS bundles for combining products

Each theme now has a new CSS bundle that only contains product specific styling, called a thin bundle. They are intended to be used when combining multiple products on page, to avoid having shared styling loaded multiple times. Previously if you combined for example Grid and TaskBoard on a single page, using the Stockholm theme, you would load:

  • grid.stockholm.css (~244 kB)
  • taskboard.stockholm.css (~243 kB)

Both products are built upon Bryntum's core library and hence both of them include the core CSS (buttons, toolbars, icons etc.). With thin bundles you would instead load each product in the hierarchy separately:

  • core.stockholm.thin.css (~203 kB)
  • grid.stockholm.thin.css (~40 kB)
  • taskboard.stockholm.thin.css (~40 kB)

This way the shared CSS (from core) is only included once. With the old approach, about 487 kB of CSS was loaded, with the new about 283 kB (204 kB less).

The gain (loss actually) will be greater if you combine products that share even more styling, like Gantt and Calendar. Calendar builds upon Scheduler > Grid > Core, while Gantt builds upon Scheduler Pro > Scheduler > Grid > Core. When not using thin bundles:

  • gantt.stockholm.css (~659 kB)
  • calendar.stockholm.css (~655 kB)

With thin bundles (many since these products build upon others):

  • core.stockholm.thin.css (~203 kB)
  • grid.stockholm.thin.css (~40 kB)
  • scheduler.stockholm.thin.css (~363 kB)
  • schedulerpro.stockholm.thin.css (~10 kB)
  • gantt.stockholm.thin.css (~27 kB)
  • calendar.stockholm.thin.css (~47 kB)

Total ~ 1314 kB vs 690 kB (624 kB less).

In your html file, you would for the Gantt + Calendar scenario have something similar to:

<link rel="stylesheet" href="core.stockholm.thin.css" data-bryntum-theme>  
<link rel="stylesheet" href="grid.stockholm.thin.css" data-bryntum-theme>  
<link rel="stylesheet" href="scheduler.stockholm.thin.css" data-bryntum-theme>  
<link rel="stylesheet" href="schedulerpro.stockholm.thin.css" data-bryntum-theme>  
<link rel="stylesheet" href="gantt.stockholm.thin.css" data-bryntum-theme>  
<link rel="stylesheet" href="calendar.stockholm.thin.css" data-bryntum-theme>  
Note the usage of the data-bryntum-theme attribute above, it is required if the app will be switching theme at runtime using DomHelper.setTheme().

Simplified test case creation

When reporting a hard to reproduce issue on Bryntum's support forum we often request a test case showing the issue. Getting a good test case greatly reduces the time it takes from reporting the bug until a fix can be released. Worst case we won't be able to find and fix the bug at all without one.

We understand that for complex apps it is not always trivial to produce a standalone test case. The app might be using a lot of different configs and the issue might only appear with a certain dataset etc. To simplify the process of creating a test case we have added a new function called downloadTestCase() to all Bryntum products. Running it collects the current value for the configs your app is using, inlines the current dataset and compiles configs and data into a JavaScript app that is then downloaded.

The app will most likely require manual tweaking before you can submit it to us, but we are hoping it will make creating a test case easier for you. Run scheduler.downloadTestCase() on the console in a demo to try it. Any feedback on how this could be improved further is welcome on the forums!

Scheduler v5.1.0

Dependencies in vertical mode

The Dependencies feature can now be used in vertical mode (see the new vertical-dependencies demo):

const scheduler = new Scheduler({ appendTo : targetElement, height : '22em', startDate : new Date(2022, 4, 1), endDate : new Date(2022, 4, 7), mode : 'vertical', resources : [ { id : 1, name : 'Greta' }, { id : 2, name : 'Ingrid' } ], events : [ { id : 1, resourceId : 1, name : 'Interview', startDate : '2022-05-02', endDate : '2022-05-03' }, { id : 2, resourceId : 1, name : 'Press meeting', startDate : '2022-05-04', endDate : '2022-05-05' }, { id : 3, resourceId : 2, name : 'Audition', startDate : '2022-05-03', endDate : '2022-05-05' } ], features : { dependencies : true, dependencyEdit : true }, dependencies : [ { id : 1, from : 1, to : 2 }, { id : 2, from : 1, to : 3, fromSide : 'right' } ] });

Dependency lines with rounded corners

By configuring a radius you can round the corners on the dependency lines for a less boxy look:

const scheduler = new Scheduler({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, startDate : new Date(2018, 4, 6), endDate : new Date(2018, 4, 13), columns : [ { field : 'name', text : 'Name', width : 100 } ], resources : [ { id : 1, name : 'Bernard' }, { id : 2, name : 'Bianca' } ], events : [ { id : 1, resourceId : 1, name : 'Interview', startDate : '2018-05-06', endDate : '2018-05-07', style : 'border-radius:5px' }, { id : 2, resourceId : 1, name : 'Press meeting', startDate : '2018-05-08', endDate : '2018-05-09', style : 'border-radius:5px' }, { id : 3, resourceId : 2, name : 'Audition', startDate : '2018-05-07', endDate : '2018-05-09', style : 'border-radius:5px' }, { id : 4, resourceId : 2, name : 'Script deadline', startDate : '2018-05-11', endDate : '2018-05-11', style : 'border-radius:5px' } ], features : { dependencies : { radius : 15 } }, dependencies : [ { id : 1, from : 1, to : 3 }, { id : 2, from : 2, to : 4 } ] });

Customize dependency arrow heads (markers)

The SVG path definition used for dependency line arrows (SVG markers) can now be easily replaced using the new markerDef config:

CSSHelper.insertRule(`.b-sch-dependency.b-sch-dependency-special { stroke-dasharray: 5, 5; stroke : orange; }`, targetElement.getRootNode()); const scheduler = new Scheduler({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, startDate : new Date(2018, 4, 6), endDate : new Date(2018, 4, 13), columns : [ { field : 'name', text : 'Name', width : 100 } ], features : { dependencies : { // Circular arrow heads (marker) markerDef : 'M 2,3 a 3,3 0 1,0 6,0 a 3,3 0 1,0 -6,0' } }, resources : [ { id : 1, name : 'Bernard' }, { id : 2, name : 'Bianca' } ], events : [ { id : 1, resourceId : 1, name : 'Interview', startDate : '2018-05-06', endDate : '2018-05-07' }, { id : 2, resourceId : 1, name : 'Press meeting', startDate : '2018-05-08', endDate : '2018-05-09' }, { id : 3, resourceId : 2, name : 'Audition', startDate : '2018-05-07', endDate : '2018-05-09' }, { id : 4, resourceId : 2, name : 'Script deadline', startDate : '2018-05-11', endDate : '2018-05-11' } ], dependencies : [ { id : 1, from : 1, to : 2, cls : 'b-sch-dependency-special' }, { id : 2, from : 2, to : 4 } ] });

Introducing Create React App templates

Create React App script templates are now available in the public npm repository.

If you are using javascript only, just type:

npx create-react-app my-app --template @bryntum/cra-template-javascript-scheduler

or if you prefer using typescript:

npx create-react-app my-app --template @bryntum/cra-template-typescript-scheduler

Note: Please feel free to change my-app to your preferred application name

Check the React integration guide for more information.

Simplified url configuration on CrudManager

Configuring CrudManager was made a little easier by introducing shortcuts for setting load and sync urls using the new loadUrl and syncUrl configs. When your application does not need to supply any additional configs to the transport layer you can use them in favor of having to nest the urls. Old code like this:

const scheduler = new Scheduler({
    crudManager : {
        transport : {
            load : {
                url : 'load.aspx'
            }
        }
    }
})

Can now be written more conveniently like this:

const scheduler = new Scheduler({
    crudManager : {
        loadUrl : 'load.aspx'
    }
})

New module bundle for Angular

Bryntum Scheduler is now delivered with new ES Module bundle without WebComponents. This was done to avoid conflicts with Angular which also uses WebComponents for applications.

Angular wrappers use scheduler.module.js bundle in favor of removed scheduler.lite.umd.js one.

Check the upgrading guide for the details.

New module bundle with WebComponents

Bryntum Scheduler is now delivered with new scheduler.wc.module.js ES Module bundle with WebComponents.

Check the upgrading guide for the details.

New keyboard shortcuts functionality

KeyMap is a mixin that allows for standardized and customizable keyboard shortcuts functionality. KeyMap is mixed in to Widget by default and therefore available to all Widget child classes. There is a new guide describing how to customize currently integrated keyboard shortcuts.

Scheduler v5.2.0

New widget for switching views

The ViewPresetCombo is an easy-to-setup preset picker which can be added to the Scheduler's toolbar and provides a simple UI for switching between different "views". It's based on ViewPreset which is built-in to the Scheduler.

Try it out in the live demo here:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL was not found on this server.</p> </body></html>

Selecting time spans in the timeline header

Scheduler has a new feature called TimeSelection, which allows you to select custom time spans in the timeline header. Can for example be used to select events intersecting that time span or to highlight resources available during the time span. Try it out in the new time-selection demo, or in the live demo below:

const scheduler = new Scheduler({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, features : { timeSelection : { headerRenderer({ timeRange }) { return `<span>${DateHelper.format(timeRange.startDate, 'LST')}</span> <span>${DateHelper.format(timeRange.endDate, 'LST')}</span> <i class='fa fa-close' data-btip="Close"></i>`; } } }, viewPreset : 'hourAndDay', startDate : new Date(2022, 4, 8, 8), endDate : new Date(2022, 4, 8, 16), columns : [ { field : 'name', text : 'Name', width : 100 } ], resources : [ { id : 1, name : 'Bernard' }, { id : 2, name : 'Bianca' }, { id : 3, name : 'Rolf' }, { id : 4, name : 'Bengt' }, { id : 5, name : 'Penny' } ], events : [ { id : 1, resourceId : 1, name : 'Interview', startDate : '2022-05-08T09:00:00', endDate : '2022-05-08T10:00:00' }, { id : 2, resourceId : 2, name : 'Meeting', startDate : '2022-05-08T13:00:00', endDate : '2022-05-08T15:00:00' }, { id : 3, resourceId : 3, name : 'Future task', startDate : '2022-05-08T09:00:00', endDate : '2022-05-08T11:30:00' } ], bbar : [ { ref : 'selectionLabel', type : 'widget' } ], getAvailableResources(startDate, endDate) { return this.resourceStore.query(resource => this.isDateRangeAvailable(startDate, endDate, null, resource)); }, onTimeSelectionChange({ startDate, endDate }) { const availableResources = startDate ? this.getAvailableResources(startDate, endDate).length : this.resourceStore.count; this.widgetMap.selectionLabel.html = `${availableResources} resources available`; } }); scheduler.features.timeSelection.selectedTimeSpan = { startDate : new Date(2022, 4, 8, 10), endDate : new Date(2022, 4, 8, 13) };

Virtualized time range rendering

The TimeRanges feature was refactored to support virtualization, it now only renders lines and ranges in view. This also applies to the NonWorkingTime feature, and will boost rendering performance on long time axes when either feature is used.

The demo below spans 50 years. Previously it would render 50 * 52 = 2600 non-working-time elements to the DOM, but now it renders much fewer:

const scheduler = new Scheduler({ appendTo : targetElement, autoHeight : true, startDate : new Date(2022, 0, 1), endDate : new Date(2042, 0, 1), columns : [ { field : 'name', text : 'Name', width : 100 } ], resources : [ { id : 1, name : 'Meeting room #1' }, { id : 2, name : 'Meeting room #2' } ], project : { // Allow calendars to encompass ~ 100 years maxCalendarRange : 100 * 53 * 7 * 24 * 60 * 60 * 1000 }, features : { nonWorkingTime : true }, tbar : [ { ref : 'count', type : 'widget' } ] }); function updateCount() { scheduler.widgetMap.count.html = `${document.querySelectorAll('.b-sch-foreground-canvas .b-sch-non-working-time').length} non-working time elements in DOM`; } scheduler.on({ horizontalScroll() { updateCount(); } }); updateCount();

EventNonWorkingTime feature

The NonWorkingTime feature has a new sibling feature called EventNonWorkingTime, that renders the non-working time ranges (weekends) as shaded parts of the event bars.

const scheduler = new Scheduler({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, features : { eventNonWorkingTime : true }, startDate : new Date(2018, 4, 6), endDate : new Date(2018, 4, 13), eventStyle : 'filled', columns : [ { field : 'name', text : 'Name', width : 100 } ], resources : [ { id : 1, name : 'Bernard' }, { id : 2, name : 'Bianca' } ], events : [ { id : 1, resourceId : 1, name : 'Sunday', startDate : '2018-05-06', endDate : '2018-05-08' }, { id : 2, resourceId : 2, name : 'Saturday', startDate : '2018-05-11', endDate : '2018-05-13' } ] });

While the feature works well in Scheduler, it is even more useful in Scheduler Pro where events and resources can have different calendars.

Support for tree grouping

The TreeGroup feature was added in 5.0. It can transform a tree structure to give another view on the data, based on a set of fields or functions. In the initial release it did not work for Scheduler, it was specifically tailored for Grid and Gant. In this release it has been reworked to improve its functionality in Gantt, and as a bonus the changes also allows it to be used in Scheduler. There is a new tree-grouping demo showing how it works.

const scheduler = new Scheduler({ appendTo : targetElement, autoHeight : true, startDate : new Date(2023, 0, 1), endDate : new Date(2023, 0, 8), columns : [ { field : 'name', text : 'Name', width : 170, type : 'tree' }, { field : 'strength', text : 'Strength', width : 70 }, { field : 'gender', text : 'Gender', width : 70 } ], resourceStore : { fields : ['strength', 'gender'], tree : true, data : [ { id : 100, name : 'Younglings', expanded : true, children : [ { id : 1, name : 'Jennifer Walters', strength : 80, gender : 'Female' }, { id : 2, name : 'Peter Parker', strength : 60, gender : 'Male' }, { id : 3, name : 'Natasha Romanova', strength : 20, gender : 'Female' } ] }, { id : 101, name : 'Elders', expanded : true, children : [ { id : 4, name : 'Bruce Banner', strength : 100, gender : 'Male' }, { id : 5, name : 'Tony Stark', strength : 10, gender : 'Male' }, { id : 6, name : 'Steve Rogers', strength : 50, gender : 'Male' } ] } ] }, events : [ { id : 1, name : 'Court', startDate : '2023-01-02', duration : 3, resourceId : 1 }, { id : 2, name : 'Do Science', startDate : '2023-01-04', duration : 3, resourceId : 2 }, { id : 3, name : 'Parkour', startDate : '2023-01-03', duration : 4, resourceId : 3 }, { id : 4, name : 'Anger management', startDate : '2023-01-02', duration : 5, resourceId : 4 }, { id : 5, name : 'Investment meetings', startDate : '2023-01-03', duration : 3, resourceId : 5 }, { id : 6, name : 'Catch up', startDate : '2023-01-02', duration : 2, resourceId : 6 }, { id : 7, name : 'Inspire', startDate : '2023-01-05', duration : 2, resourceId : 6 } ], features : { tree : true, treeGroup : true, group : false }, tbar : [ { type : 'buttonGroup', toggleGroup : true, items : [ { text : 'No grouping', pressed : true, onClick() { scheduler.clearGroups(); } }, { text : 'Gender', onClick() { scheduler.group(['gender']); } }, { text : 'Strength', onClick() { scheduler.group([r => r.strength >= 50 ? 'Strong' : 'Weak']); } }, { text : 'Gender & Strength', onClick() { scheduler.group(['gender', r => r.strength >= 50 ? 'Strong' : 'Weak']); } } ] } ] });

Improved PDF Export feature

Pdf Export feature now renders exported content directly and does not scroll the view anymore. This significantly improves performance (by an order of magnitude) and robustness of the export process. You can enable old behavior by setting enableDirectRendering config on the export feature to false. Old behavior is deprecated and will be removed in the next major release. Please report issues that make you disable direct rendering.

Scheduler v5.2.5

Enlarged clickable area for dependency lines

The Dependencies feature has a new clickWidth config, that lets you enlarge the clickable area for dependency lines. By specifying a value > 1, a second invisible line will be drawn along the same path but with a wider stroke. This makes the line appear thin, but it will be easier to reach with the mouse. Since two lines are drawn instead of one, the tradeoff is slightly reduced drawing performance.

The dependencies demo has been updated with a slider for adjusting it.

Scheduler v5.2.6

Support for React Components in tooltips and widgets

React components are now supported in tooltips and widgets. Tooltips have renderer or template function that can now return valid JSX that represents a React component. Widgets can now supply JSX as their html property. For example:

Cell tooltip:

cellTooltipFeature: {
    tooltipRenderer: ({ record }) => (
        <React.StrictMode>
            <DemoTooltip record={record} />
        </React.StrictMode>
    )
},

Event tooltip:

eventTooltipFeature: {
    template: data => (
        <React.StrictMode>
            <DemoEventTip data={data} />
        </React.StrictMode>
    )
},

React component in widget:

bbar : {
    items:[{
        type:'widget',
        html:<DemoWidget />
    }]
},

See the React guide for details.

Scheduler v5.3.0

AjaxHelper.fetch now supports passing parameters in request body

Since this release AjaxHelper.fetch method can pass provided queryParams in the request body instead of query string. This happens for application/x-www-form-urlencoded and multipart/form-data content types when addQueryParamsToBody option is set to true:

AjaxHelper.fetch('url', {
    headers : {
        'Content-Type' : 'application/x-www-form-urlencoded'
    },
    addQueryParamsToBody : true
});

Please check addQueryParamsToBody in FetchOptions

Please note that this behavior is disabled by default so if you need to enable it globally please use AjaxHelper.DEFAULTFETCHOPTIONS:

// enable addQueryParamsToBody by default
AjaxHelper.DEFAULT_FETCH_OPTIONS = {
    addQueryParamsToBody : true
}

Time zone support

Support for Time zone conversion has been added to all Bryntum scheduling products. Simply set a IANA time zone identifier as value for the timeZone config and that's it.

But since time zones is not natively supported in JavaScript we strongly recommend to read our Time zone guide.

Also, please check out the new Time zone demo.

new Scheduler({
    timeZone : 'America/Chicago'
});

New locales

New locales for 31 languages have been added. Currently available languages are listed in the localization guide.

Scheduler v5.3.3

Angular IVY and View Engine wrappers

Bryntum Scheduler now ships with two npm Angular wrappers packages to support different versions of Angular framework.

@bryntum/scheduler-angular is designed to work with Angular 12 and newer versions, which use the IVY rendering engine.

@bryntum/scheduler-angular-view is designed to work with Angular 11 and older versions, which use the View Engine for rendering.

Please check Angular integration guide for the additional information.

Scheduler v5.4.0

New way to assign multiple resources to events

It is now possible to assign multiple resources to an event by supplying them in the new resourceIds field. It only applies if the field is configured with perist: true.

Please check resourceIds docs for additional information.

EventCopyPaste has been made asynchronous

The EventCopyPaste feature has been enhanced to usa a page-global internal clipboard and also supports the browser's native Clipboard API if accessible. This means that it is possible to copy and paste events between multiple instances of Scheduler or other Grid-based components. It is also possible to copy an event and paste it inside a Spreadsheet app like Excel.

Another improvement is that both the beforeCopy and beforePaste events are now asynchronously preventable.

You can try this out in the Drag drop between multiple schedulers demo.

Please note that this enhancement has required API changes:

  • The copyEvents and pasteEvents functions are now asynchronous.

New TimelineHistogram view

This release introduces a new TimelineHistogram class which implements a grid with histogram charts displayed for rows in the timeaxis section.

const histogram = new TimelineHistogram({ appendTo : targetElement, startDate : new Date(2023, 0, 1), endDate : new Date(2023, 0, 6), autoHeight : true, columns : [{ text : 'Name', field : 'name' }], // define histogram value series series : { work : { // display work values as bars type : 'bar' }, maxWork : { // display maxWork values as outline type : 'outline' } }, // grid data store : new Store({ data : [ { id : 1, name : 'Mats', // the record histogram data histogramData : [ { work : 8, maxWork : 16 }, { work : 18, maxWork : 12 }, { work : 12, maxWork : 10 }, { work : 13, maxWork : 16 }, { work : 15, maxWork : 16 }, { work : 1, maxWork : 6 } ] }, { id : 2, name : 'Johan', histogramData : [ { work : 15, maxWork : 16 }, { work : 8, maxWork : 26 }, { work : 12, maxWork : 6 }, { work : 13, maxWork : 16 }, { work : 18, maxWork : 16 }, { work : 8, maxWork : 16 } ] }, { id : 3, name : 'Arcady', histogramData : [ { work : 15, maxWork : 16 }, { work : 18, maxWork : 9 }, { work : 8, maxWork : 11 }, { work : 12, maxWork : 16 }, { work : 13, maxWork : 16 }, { work : 10, maxWork : 5 } ] } ] }) });

Please check the new Timeline histogram demo and the "Timeline histogram" guide for more details.

Event color editing

We have added default editors for the eventColor field. There is one in the EventMenu feature's context menu and one in the EventEdit feature's event editing panel. Just set showEventColorPickers to true and the editors will appear. There is also a new EventColorColumn which can be added to any Scheduler. It renders a colored element which the user can click and select a new color as a default for each resource.

const scheduler = new Scheduler({ appendTo : targetElement, autoHeight : true, showEventColorPickers : true, startDate : new Date(2023, 5, 6), endDate : new Date(2023, 5, 13), columns : [ { field : 'name', text : 'Name', width : 100 } ], resources : [ { id : 1, name : 'Batman' }, { id : 2, name : 'Robin' } ], events : [ { id : 1, resourceId : 1, name : 'Double click me', startDate : '2023-06-08', endDate : '2023-06-11', eventColor : 'violet' }, { id : 2, resourceId : 2, name : 'Or me', startDate : '2023-06-13', endDate : '2023-06-18' } ] });

The selectable colors are those which are built-in as CSS classes to the Scheduler. See the EventModel's eventColor config for more details.

new Scheduler({
    // Activates the context menu event color picker. Also shows a EventColorField in the event editor 
    showEventColorPickers : true,

    columns : [
        // Adds a column in which the user can see and edit the resource default event color
        { type : 'eventcolor', text : 'Color', size : 80 }
    ]
})

See the editors in action in the updated Event editor demo.

Split schedule feature

Scheduler has a new feature called Split which allows you to split the schedule into multiple parts (two or four). This lets you access different parts of the schedule that might not otherwise fit in the same viewport. Try it in the live demo below, and in the new split demo:

const scheduler = new Scheduler({ appendTo : targetElement, height : '30em', startDate : new Date(2023, 4, 22), endDate : new Date(2023, 5, 30), features : { split : true }, columns : [ { field : 'name', text : 'Name', width : 100 } ], resources : ArrayHelper.populate(50, i => ({ id : i, name : `Resource ${i}` }), true), events : ArrayHelper.populate(200, i => ({ id : i, name : `Event ${i}`, resourceId : i % 50, startDate : new Date(2023, 4, 22, i * 12), duration : 4 }), true) }); scheduler.split({ direction : 'vertical' });

Scheduler v5.6.0

New npm packages for combining products

This release introduces a new set of npm packages and framework components, that allows combining multiple Bryntum products in the same application.

These packages contain the product specific code only, as opposed to the current packages that has all code for the products each product builds upon (for example Scheduler contains all code from Grid & Core).

The new packages are called thin packages, and moving forward it will be the recommended way of using Bryntum products in npm based applications (for all supported frameworks). The packages are initially available for licensed users only, but will be made available for trial users in the near future.

The following packages are available:

Package Purpose
@bryntum/core-thin Bryntum Core data and UI components package
@bryntum/grid-thin Bryntum Grid component package
@bryntum/scheduler-thin Bryntum Scheduler component package
@bryntum/schedulerpro-thin Bryntum Scheduler Pro component package
@bryntum/gantt-thin Bryntum Gantt component package
@bryntum/calendar-thin Bryntum Calendar component package
@bryntum/taskboard-thin Bryntum TaskBoard component package
@bryntum/engine-thin Bryntum Scheduling engine component package

Applications should install packages for the products they use, and the products those are built upon (see links to guides below for more information). For example an application using Scheduler Pro should also install Scheduler, Grid & Core:

npm install @bryntum/core-thin @bryntum/grid-thin @bryntum/scheduler-thin @bryntum/schedulerpro-thin

There are also new corresponding wrappers for the supported frameworks, which should be used instead of the current wrappers. For example for React:

Package Purpose
@bryntum/core-react-thin Bryntum Core UI widgets React wrappers package
@bryntum/grid-react-thin Bryntum Grid React wrapper package
@bryntum/scheduler-react-thin Bryntum Scheduler React wrapper package
@bryntum/schedulerpro-react-thin Bryntum Scheduler Pro React wrapper package
@bryntum/gantt-react-thin Bryntum Gantt React wrapper package
@bryntum/calendar-react-thin Bryntum Calendar React wrapper package
@bryntum/taskboard-react-thin Bryntum TaskBoard React wrapper package

Applications should install wrappers only for the products they use, there is no need to install them for the products those are built upon. For example an application using Scheduler Pro:

npm install @bryntum/schedulerpro-react-thin

More information:

Dependency terminal customization

The Dependencies feature now allow configuring the size (terminalSize) and offset (terminalOffset) from the event bar for terminals (connection points shown when hovering the bar). This lets you position the terminals fully inside or fully outside the bar. For example this makes the terminals smaller and moves them inside the bar:

new Scheduler({
    features : {
        dependencies : {
            terminalSize    : 8,
            terminalOffset  : -8
        }
    }
});

While this makes them larger and moves them outside the bar:

new Scheduler({
    features : {
        dependencies : {
            terminalSize    : 16,
            terminalOffset  : 10
        }
    }
});

Similar settings can be seen in action here, hover an event bar to display the terminals:

const scheduler = new Scheduler({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, startDate : new Date(2023, 4, 7), endDate : new Date(2023, 4, 14), eventStyle : 'outlined', resourceMargin : 20, rowHeight : 70, columns : [ { field : 'name', text : 'Name', width : 100 } ], resources : [ { id : 1, name : 'Bernard' }, { id : 2, name : 'Bianca' } ], events : [ { id : 1, resourceId : 1, name : 'Interview', startDate : '2023-05-08', endDate : '2023-05-09' }, { id : 2, resourceId : 1, name : 'Press meeting', startDate : '2023-05-10', endDate : '2023-05-11' }, { id : 3, resourceId : 2, name : 'Audition', startDate : '2023-05-09', endDate : '2023-05-11' }, { id : 4, resourceId : 2, name : 'Script deadline', startDate : '2023-05-12', endDate : '2023-05-12' } ], features : { dependencies : { terminalSize : 16, terminalOffset : 8, radius : 5 } }, dependencies : [ { id : 1, from : 1, to : 3 } ] });

It also allows configuring delays before showing (terminalShowDelay, to require an intentional hover on an event bar) and hiding (terminalHideDelay, to allow hide animations, and to be more forgiving) them.

new Scheduler({
    features : {
        dependencies : {
            terminalShowDelay : 100, // ms
            terminalHideDelay : 300
        }
    }
});

The b-hiding-terminals CSS class is added to the event bar while the terminals are being hidden, can be used as a target for CSS animations.

.b-hiding-terminals .b-sch-terminal {
    animation : MyHideTerminalsAnimation 0.3s forwards;
}

The dependencies demo was updated to allow experimenting with these new options

Support for asymmetrical resourceMargin

It's possible to set different values for top/left and bottom/right by assigning an object to resourceMargin with start (margin top in horizontal mode, margin left in vertical mode) and end (margin bottom / margin right) properties:

new Scheduler({
    resourceMargin : {
        start    : 15,
        end      : 1
    }
});

The rowHeight demo was updated to allow experimenting with this new object

Drag resizing rows

We have added a new feature called RowResize, that lets users resize resource rows by dragging their bottom border. It can be configured to allow resizing individual resources, or to apply the same size to all resources. See the updated rowheight example for a demonstration, or try it out below:

const scheduler = new Scheduler({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, startDate : new Date(2023, 4, 7), endDate : new Date(2023, 4, 14), eventStyle : 'border', features : { rowResize : true }, columns : [ { field : 'name', text : 'Name', width : 100 } ], resources : [ { id : 1, name : 'Bernard' }, { id : 2, name : 'Bianca' }, { id : 3, name : 'John' }, { id : 4, name : 'Rob' } ], events : [ { id : 1, resourceId : 1, name : 'Event', startDate : '2023-05-08', endDate : '2023-05-10' }, { id : 2, resourceId : 2, name : 'Meeting', startDate : '2023-05-12', endDate : '2023-05-13' }, { id : 3, resourceId : 2, name : 'Booking', startDate : '2023-05-09', endDate : '2023-05-11', eventColor : 'blue' }, { id : 4, resourceId : 3, name : 'Overlapping', startDate : '2023-05-08', endDate : '2023-05-10' }, { id : 5, resourceId : 3, name : 'Overlapping', startDate : '2023-05-09', endDate : '2023-05-11' } ] });

React components in vertical mode resource headers

A headerRenderer supplied in vertical modes resourceColumns configuration can now return JSX:

resourceColumns : {
    columnWidth    : 140,
    headerRenderer : ({ resourceRecord, elementConfig }) => {
        return (
            <ReactResourceHeader
                resourceRecord={resourceRecord}
                elementConfig={elementConfig}
            ></ReactResourceHeader>
        )
    }
}

In the snippet above, ReactResourceHeader is an example React component, that does the resource header rendering, you can use your own JSX. The React resource header renderer is demonstrated in the examples/frameworks/react/javascript/vertical demo.

Improvements to the ViewPresetCombo

The behaviour of the ViewPresetCombo has been changed to better align with the functionality of "zooming". Instead of calculating the new timespan from the current startDate, it will now calculate from the date that is in the center of the visible timespan. Additionally, there is a new config, useFixedDuration, that defaults to true. This will ensure that a ViewPreset always starts and ends with its default mainUnit. A month view will start at the 1:st and end at the 31:st for example. This behaviour is not new, but the config to turn it off is. Set it to false to use the default zoomToLevel behaviour instead.

Functions and events declarations for TypeScript have been improved

Declarations of class config/property functions and events (which are represented as onEventName functions) were improved to contain all available parameters and return type.

See examples below:

Old declarations:

    /**
     * User typed into the field. Please note that the value attached to this event is the raw input field value and
     * not the combos value
     */
    onInput: Function|string

    /**
     * Template function that can be used to customize the displayed value
     */
    displayValueRenderer: Function

New declarations:

    /**
     * User typed into the field. Please note that the value attached to this event is the raw input field value and
     * not the combos value
     */
    onInput: ((event : { source: Combo, value: string, event: Event }) => void)|string

    /**
     * Template function that can be used to customize the displayed value
     */
    displayValueRenderer: (record: Model, combo: Combo) => string|null

Client side print / PDF export

A new Print feature was added to allow printing Scheduler content using the browser print dialog. It extends the PDFExport feature and uses same configs which manage HTML markup rendering (exporters, columns, paper size, etc.). The only difference is that instead of sending generated HTML to a backend, the feature creates an iframe element with generated content and opens the browser print dialog from it.

Contents