Features
Uses JavaScript Scheduler control from DayPilot Pro for JavaScript
Export the Scheduler to a multi-page PDF file (client-side).
Splits the Scheduler vertically (by rows), printing row and time headers on every page.
Prints a specified number of rows per page.
Includes a trial version of DayPilot Pro for JavaScript (see License below)
The PDF export uses jsPDF library (MIT license)
See also a related tutorial that shows how to split a long timeline into multiple pages horizontally:
License
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.
Scheduler Configuration
We will use a simple Scheduler configuration:
The vertical (Y) axis displays 20 resources.
The horizontal (X) axis displays 31 days.
Two row header columns (default column with the resource name + custom column with event count)
A sample "Reservation #1" event (from January 4 to January 8)
<div id="dp"></div>
<script>
var dp = new DayPilot.Scheduler("dp");
dp.scale = "Day";
dp.timeHeaders = [
{ groupBy: "Month"},
{ groupBy: "Day", format: "d"}
];
dp.startDate = new DayPilot.Date("2021-01-01");
dp.days = 31;
dp.resources = [
{name: "Resource 1", id: 1},
{name: "Resource 2", id: 2},
{name: "Resource 3", id: 3},
{name: "Resource 4", id: 4},
{name: "Resource 5", id: 5},
{name: "Resource 6", id: 6},
{name: "Resource 7", id: 7},
{name: "Resource 8", id: 8},
{name: "Resource 9", id: 9},
{name: "Resource 10", id: 10},
{name: "Resource 11", id: 11},
{name: "Resource 12", id: 12},
{name: "Resource 13", id: 13},
{name: "Resource 14", id: 14},
{name: "Resource 15", id: 15},
{name: "Resource 16", id: 16},
{name: "Resource 17", id: 17},
{name: "Resource 18", id: 18},
{name: "Resource 19", id: 19},
{name: "Resource 20", id: 20},
];
dp.events.list = [
{
start: "2021-01-04T00:00:00",
end: "2021-01-09T00:00:00",
id: 1,
resource: 2,
text: "Reservation #1"
}
];
dp.rowHeaderColumns = [
{ title: "Resource", display: "name"},
{ title: "Event count"},
];
dp.onBeforeRowHeaderRender = function(args) {
var events = args.row.events.all().length;
if (events > 0) {
args.row.columns[1].html = events;
}
};
dp.init();
</script>
PDF Export (Single Page)
In order to export the Scheduler as a single page we will use DayPilot.Scheduler.exportAs() method with area
option set to "full"
.
The export function creates a new PDF file using jsPDF library:
var doc = new jsPDF("portrait", "in", "letter");
It prints a page header ("Scheduler"):
doc.setFontSize(40);
doc.text(0.5, 1, "Scheduler");
It exports the Scheduler as JPEG image using exportAs()
method. It uses the following options:
It prints the complete Scheduler (
area: "full"
).It uses
scale: 2
to make the exported file bigger. The default 1:1 scale might result in a blurred image when inserted into a PDF file.It uses JPEG image format. This isn't optimal because JPEG uses a lossy compression and the exported image is better suited for lossless formats (straight lines, uniform backgrounds). However, jsPDF can only insert a PNG image uncompressed (equivalent of BMP) and that would result in an extremely big PDF file.
It tries to compensates the lossy JPEG format by increasing the image quality to
0.95
.
var image = dp.exportAs("jpeg", {
area: "full",
scale: 2,
quality: 0.95
});
The dimensions of the output image are scaled down using shrink()
method so the image fits the page.
var dimensions = image.dimensions(); // pixels
var maxDimensions = { width:7, height: 9}; // inches
var shrinked = shrink(dimensions, maxDimensions);
The resulting JPEG image is inserted into the PDF page:
doc.addImage(image.toDataUri(), 'JPEG', 0.5, 1.5, shrinked.width, shrinked.height);
Full sample:
<script>
$("#download").click(function() {
var blob = createPdfAsBlobOnePage();
DayPilot.Util.downloadBlob(blob, "scheduler.pdf");
});
function createPdfAsBlobOnePage() {
var doc = new jsPDF("portrait", "in", "letter");
doc.setFontSize(40);
doc.text(0.5, 1, "Scheduler");
var image = dp.exportAs("jpeg", {
area: "full",
scale: 2,
quality: 0.95
});
var dimensions = image.dimensions(); // pixels
var maxDimensions = { width:7, height: 9}; // inches
var shrinked = shrink(dimensions, maxDimensions);
doc.addImage(image.toDataUri(), 'JPEG', 0.5, 1.5, shrinked.width, shrinked.height);
return doc.output("blob");
}
function shrink(dimensions, max) {
var widthRatio = dimensions.width / max.width;
var heightRatio = dimensions.height / max.height;
var ratio = Math.max(widthRatio, heightRatio);
ratio = Math.max(ratio, 1);
var width = dimensions.width / ratio;
var height = dimensions.height / ratio;
return { width: width, height: height};
}
</script>
PDF Export (Multiple Pages)
It's also possible to export a specifies segment of the Scheduler using area: "range"
option.
We will use this mode to split the Scheduler vertically during export, displaying a selected number of rows per page.
The start and end row of every segment is specified using resourceFrom
and resourceTo
options.
<script>
$("#download").click(function() {
var blob = createPdfAsBlob(5);
DayPilot.Util.downloadBlob(blob, "scheduler.pdf");
});
function createPdfAsBlob(rowsPerPage) {
var doc = new jsPDF("landscape", "in", "letter")
doc.setFontSize(40);
doc.text(0.5, 1, "Scheduler");
var rows = dp.rows.all();
var pages = Math.ceil(rows.length / rowsPerPage);
for (var i = 0; i < pages; i++) {
var startId = i*rowsPerPage;
var endId = i*rowsPerPage + rowsPerPage - 1;
endId = Math.min(endId, rows.length - 1);
var image = dp.exportAs("jpeg", {
area: "range",
scale: 2,
resourceFrom: rows[startId].id,
resourceTo: rows[endId].id,
quality: 0.95
});
var dimensions = image.dimensions(); // pixels
var maxDimensions = { width: 10, height: 6}; // inches
var shrinked = shrink(dimensions, maxDimensions); // inches
doc.addImage(image.toDataUri(), 'JPEG', 0.5, 1.5, shrinked.width, shrinked.height);
var last = (i === pages - 1);
if (!last) {
doc.addPage();
}
}
return doc.output("blob");
}
function shrink(dimensions, max) {
var widthRatio = dimensions.width / max.width;
var heightRatio = dimensions.height / max.height;
var ratio = Math.max(widthRatio, heightRatio);
ratio = Math.max(ratio, 1);
var width = dimensions.width / ratio;
var height = dimensions.height / ratio;
return { width: width, height: height};
}
</script>