This sample web application uses DayPilot JavaScript Scheduler and it is based on the HTML5 scheduler tutorial.


  • JavaScript/HTML5 scheduler component
  • Scheduler event data are loaded dynamically during scrolling
  • Resources grouped by category on the vertical axis
  • One year split into days and grouped by months
  • PHP backend


Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript. Buy a license.

HTML5 Scheduler Configuration

For a detailed guide on the scheduler component setup and configuration please see the HTML5 scheduler tutorial.

<script src="js/daypilot/daypilot-all.min.js" type="text/javascript"></script>

<div id="dp"></div>

<script type="text/javascript">
  var dp = new DayPilot.Scheduler("dp");

Dynamic Scheduler Event Loading

The scheduler events can be loaded using .events.list property (bulk loading) or using .events.add() method (individual events that are added to the scheduler immediately). This way you can load events for the whole timeline.

This tutorial shows how to load events dynamically during scrolling. This method load only the data for the current viewport (like in the online map applications).

1. Enable the dynamic loading using dynamicLoading property:

dp.dynamicLoading = true;

2. Add onScroll event handler. This event handler will be called whenever the current viewport changes (when the users scrolls).

dp.onScroll = function(args) { /* ... */ };


<script type="text/javascript">
  var dp = new DayPilot.Scheduler("dp");

  dp.dynamicLoading = true;
  dp.onScroll = function(args) {
    args.async = true;
    var start = args.viewport.start;
    var end = args.viewport.end;
        start: start.toString(),
        end: end.toString()
      function(data) { = data;



Async Loading

Most AJAX loading methods (such as jQuery .post(), .get(),  or .ajax() methods) use a success callback function to read the AJAX request result.

In this case, you need to turn on the async event loading using args.async property. The events will not be loaded until args.loaded() is called from the callback function.

dp.onScroll = function(args) {
  args.async = true;
  // ...

  var callback = function(data) { = data;


Sync Loading

It is also possible to load the events synchronously:

dp.onScroll = function(args) { = loadEvents();

Current Scheduler Viewport


The current viewport details are stored in args.viewport property:

  • args.viewport.start (DayPilot.Date)
  • args.viewport.end (DayPilot.Date)
  • args.viewport.resources (array of resource id strings)

The sample PHP backend doesn't use the resource list to filter the events - it loads all events between viewport.start and viewport.end.

require_once '_db.php';
$stmt = $db->prepare('SELECT * FROM [events] WHERE NOT ((end <= :start) OR (start >= :end))');
$stmt->bindParam(':start', $_POST['start']);
$stmt->bindParam(':end', $_POST['end']);
$result = $stmt->fetchAll();

class Event {}
$events = array();

foreach($result as $row) {
  $e = new Event();
  $e->id = $row['id'];
  $e->text = $row['name'];
  $e->start = $row['start'];
  $e->end = $row['end'];
  $e->resource = $row['resource_id'];
  $e->bubbleHtml = "Event details: <br/>".$e->text;
  $events[] = $e;

header('Content-Type: application/json');
echo json_encode($events);


Existing Events

The newly added events are compared with the list of events that are already loaded (stored in .events.list).

The events are compared using the following properties:

  • event id (id)
  • resource id (resource)
  • start time (start)

Matching existing events are overwritten with the new ones.