What a Rickroll Taught Us About DHTMLX Scheduler Performance

We recently came across a delightfully impractical performance demo: turn a scheduling component into a video player by drawing every frame as event bars. It was clever, visual, and impossible to ignore.

We had to try it with our JavaScript Scheduler. Our version played the video, and exposed a performance bottleneck that ordinary workloads hadn’t made obvious.


Every colored block is a real DHTMLX Scheduler event with real start and end dates.

Stress Test You Can Watch

The idea is Bryntum’s, and it is a good one. The experiment starts with a simple observation: a scheduler draws colored rectangles at calculated positions, and a video is made of colored regions that change over time. Turn each frame into a small enough set of rectangles, and the scheduling component becomes the display.

A normal benchmark gives you numbers. This stress test puts the failure mode on screen: if the rendering pipeline falls behind, the video stutters.

That made it worth exploring.

How It Works

The browser plays a video in a hidden element and draws each decoded frame onto a tiny off-screen canvas. The demo then reduces the color precision, groups neighboring pixels of the same color into horizontal runs, and merges those runs until every row has a fixed upper limit.

Those segments are written into a pool of events created at startup. The pool is reused for the entire video. Before each update, the demo compares the next frame with the current one and skips every event whose position and color are unchanged.

We wanted the experiment to exercise the same Timeline rendering path used by regular Scheduler applications. Every visible block gets a real start_date and end_date. The Timeline calculates its position and width from those dates using the same date-to-pixel code it uses for an appointment, booking, or task. When a block moves in the next frame, its dates change and the Timeline places it again.

The repaint call uses the ordinary public API:

for (const event of changedThisFrame) {
    scheduler.updateEvent(event.id);
}

The whole pipeline puts a hard limit on the work required for each frame. It reduces the input, caps the worst case, reuses data, and repaints only what changed:

  • The fixed event pool is created once and reused for the entire video. Events that haven’t changed aren’t sent through updateEvent().
  • Unused event slots fall outside the visible range, so Scheduler removes their nodes from the layout.
  • Text, resize handles, drag-and-drop, selection, shadows, rounded corners, and transitions are disabled because a video frame doesn’t need them.

WAI-ARIA generation is also disabled for this visual-only stress test. User-facing schedules should keep accessibility features enabled.

The result is still a normal DHTMLX Scheduler Timeline. It is simply configured for a workload no one had in mind when the Timeline API was designed.

What the Experiment Found

A typical Scheduler interaction updates one or a few events. This demo keeps a 960-event pool, updates an average of 880 events for each frame of the built-in clip, and repeats that work continuously.

Our first version rendered the picture, but it couldn’t keep pace with that continuous workload. Profiling showed that the video processing wasn’t the problem. Most of the time was spent finding rendered events.

Each event refresh scanned the full list of rendered nodes to find the one it needed, so refreshing N events cost O(N²) attribute reads. That cost is easy to miss when only a few events change. Here, the same scan ran hundreds of times per frame and became the main bottleneck.

We replaced the repeated scans with an index keyed by event ID. The repeated lookup disappeared from the CPU profile.

We ran the same 960-event workload on a MacBook Air M1 before and after the fix. The two runs changed almost the same number of events per frame:

Scheduler version event pool changed/framed Scheduler ms Frame ms p95 ms FPS
7.2.14 960 890 96.3 99.4 102.4 8.8
7.2.15 960 880 10.9 12.7 14.8 37.4

Scheduler repaint time fell from 96.3 ms to 10.9 ms – an 8.8× improvement. Total JavaScript frame time fell from 99.4 ms to 12.7 ms, or 7.8×.

With the fix in place, the larger 2016-event preset averaged 1835 changed events, 29.5 Scheduler ms, 32.0 frame ms, 48.1 p95 ms, and 16.3 FPS.

The p95 column is the 95th-percentile total frame time. FPS also includes browser rendering work after our JavaScript finishes, so the millisecond columns are the more useful measure of Scheduler performance.

While tracing the same path, we also found and fixed a Timeline cleanup bug that could leave duplicate nodes behind during touch interactions.

We added regression coverage for both changes. This wasn’t a video-specific optimization: it improves the event-refresh path used by regular Scheduler applications.

What This Changes for Real Schedules

Most scheduling applications will never update an entire screen several times per second. They don’t need to. But dense operational timelines often show hundreds or thousands of visible bookings, work orders, vehicles, or production steps, and they update subsets of that data throughout the day.

That is why the improvement matters beyond a video demo. Dense, frequently updated timelines use the same rendering path, so the work we did here also helps real schedules stay responsive as more data comes into view.

The fix is included in the DHTMLX Scheduler 7.2.15 patch release. After upgrading, applications that frequently update dense views can benefit without changing their application code.

Try It Yourself

Open the live video Timeline demo and use the built-in generated clip, drop in a video file of your own, or point it at your camera. The source video stays off-screen. Everything you see in the Timeline is made from Scheduler events.

The default size uses a 960-event workload, with smaller and larger presets available. The HUD shows sampling, encoding, diffing, Scheduler repaint time, changed-event count, and effective FPS.

Click “Run benchmark” for a warm-up followed by a fixed measurement window.

If you want to inspect the implementation, see the demo source on GitHub. The example uses the DHTMLX Scheduler Timeline view, which is available in DHTMLX Scheduler PRO.

We set out to see whether our Scheduler could play a video. We came away with a memorable demo and a faster Scheduler for our customers. Not a bad result from one irresistible stress test.

Useful Materials

Advance your web development with DHTMLX

Gantt chart
Event calendar
Diagram library
30+ other JS components