Features

  • JavaScript Calendar from DayPilot Pro for JavaScript
  • Client-side PDF generation using jsPDF library (MIT license)
  • Exports the current calendar view (including appointments) as JPEG file which is inserted into a PDF file
  • The exported calendar image is scaled automatically to fit the page
  • Pure client-side solution, no server-side calls required
  • Supports multiple PDF page formats: Letter, A4 (other page formats supported by jsPDF can be added easily)
  • Supports portrait and landscape paper orientation
  • Inserts a custom header into the PDF file (you can add your own text)
  • Includes a trial version of DayPilot Pro for JavaScript (see License below)

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. Buy a license.

Online JavaScript Calendar Configurator

javascript-calendar-ui-builder-configurator.png

The project template was generated using Calendar UI Builder. This online configurator lets you customize the JavaScript calendar component and generate and download a full HTML5/JavaScript project .

JavaScript Calendar Component Initialization

javascript-calendar-initialization-source-code.png

The UI Builder will generate the calendar initialization code for you. However, the initialization is very simple and you can also create and configure the JavaScript Calendar component manually:

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

<script>
  var dp = new DayPilot.Calendar("dp", {
    locale: "en-us",
    viewType: "Week"
  });
  dp.init();
</script>

This config will create and display a weekly calendar.

Calendar Appointment Data

javascript-calendar-appointment-data.png

Now we will load a couple of calendar appointments (events). We will use a simple static list with three appointments:

var dp = new DayPilot.Calendar("dp", {
    locale: "en-us",
    viewType: "Week"
});
dp.events.list = [
    {
        id: "1",
        start: DayPilot.Date.today().addHours(11),
        end: DayPilot.Date.today().addHours(13),
        text: "Event 1",
        barColor: "#f1c232"
    },
    {
        id: "1",
        start: DayPilot.Date.today().addHours(12),
        end: DayPilot.Date.today().addHours(16),
        text: "Event 2",
        barColor: "#cc0000"
    },
    {
        id: "1",
        start: DayPilot.Date.today().addDays(1).addHours(10),
        end: DayPilot.Date.today().addDays(1).addHours(15),
        text: "Event 3",
        barColor: "#38761d"
    }
];
dp.init();

Creating a PDF Document using JavaScript

javascript-calendar-pdf-empty-page.png

We will use the open-source jsPDF JavaScript library to create the PDF file on the client side. The following sample will create a one-page PDF file with a header ("Calendar") and save it as a Blob object:

var pdf = new jsPDF("portrait", "in", "letter");
pdf.setFontSize(20);
pdf.text(0.5, 1, "Calendar");
var blob = pdf.output("blob");

JPEG Image Export

The DayPilot JavaScript Calendar can export the current view as a JPEG image using exportAs() method:

var image = dp.exportAs("jpeg");

The lossy JPEG format is not the best choice for the image export of the Calendar. However, PNG files can only be inserted into the PDF document as uncompressed data and that would make the output PDF file extremely large.

To compensate the loss of quality we will change the image output scale to 200% and maximize the JPEG quality:

var image = dp.exportAs("jpeg", {
  scale: 2,
  quality: 0.95
});

Exporting the Calendar to PDF

javascript-calendar-pdf-export-output.png

Now we can insert the image with the current calendar view into our PDF document:

function createPdfAsBlobOnePage() {
    var pdf = new jsPDF("portrait", "in", "letter");
    pdf.setFontSize(40);
    pdf.text(0.5, 1, "Calendar");

    var image = dp.exportAs("jpeg", {
        scale: 2,
        quality: 0.95
    });

    var dimensions = image.dimensions();  // pixels
    var maxDimensions = {width: 7, height: 9};   // inches
    var adjusted = shrink(dimensions, maxDimensions);

    pdf.addImage(image.toDataUri(), 'JPEG', 0.5, 1.5, adjusted.width, adjusted.height);

    return pdf.output("blob");
}

HTML Source Code

<h2>JavaScript Calendar</h2>
<div id="dp"></div>
<div class="space">
    <h2>Export to PDF</h2>
    <select id="pdf-orientation">
        <option value="portrait">Portrait</option>
        <option value="landscape">Landscape</option>
    </select>
    <select id="pdf-format">
        <option value="letter">Letter</option>
        <option value="a4">A4</option>
    </select>
    <button id="export">Export</button>
</div>

JavaScript Source Code

<script>

    var dp = new DayPilot.Calendar("dp", {
        locale: "en-us",
        viewType: "Week",
        columnWidthSpec: "Auto",
        cellHeight: 20,
        crosshairType: "Header",
        businessBeginsHour: 9,
        businessEndsHour: 17,
        dayBeginsHour: 0,
        dayEndsHour: 24,
        eventArrangement: "Cascade",
        timeRangeSelectedHandling: "Enabled",
        onTimeRangeSelected: function (args) {
            DayPilot.Modal.prompt("Create a new event:", "Event 1").then(function (modal) {
                var dp = args.control;
                dp.clearSelection();
                if (!modal.result) {
                    return;
                }
                dp.events.add(new DayPilot.Event({
                    start: args.start,
                    end: args.end,
                    id: DayPilot.guid(),
                    text: modal.result
                }));
            });
        },
        eventMoveHandling: "Update",
        onEventMoved: function (args) {
            this.message("Event moved");
        },
        eventResizeHandling: "Update",
        onEventResized: function (args) {
            this.message("Event resized");
        },
        eventDeleteHandling: "Disabled",
        eventClickHandling: "Disabled",
        eventHoverHandling: "Disabled"
    });
    dp.events.list = [
        {
            id: "1",
            start: DayPilot.Date.today().addHours(11),
            end: DayPilot.Date.today().addHours(13),
            text: "Event 1",
            barColor: "#f1c232"
        },
        {
            id: "1",
            start: DayPilot.Date.today().addHours(12),
            end: DayPilot.Date.today().addHours(16),
            text: "Event 2",
            barColor: "#cc0000"
        },
        {
            id: "1",
            start: DayPilot.Date.today().addDays(1).addHours(10),
            end: DayPilot.Date.today().addDays(1).addHours(15),
            text: "Event 3",
            barColor: "#38761d"
        }
    ];
    dp.init();

    var pdfConfig = {
        "letter-portrait": {
            orientation: "portrait",
            unit: "in",
            format: "letter",
            maxWidth: 7,
            maxHeight: 9,
            left: 0.5,
            top: 1,
            space: 0.2
        },
        "letter-landscape": {
            orientation: "landscape",
            unit: "in",
            format: "letter",
            maxWidth: 9,
            maxHeight: 7,
            left: 0.5,
            top: 1,
            space: 0.2
        },
        "a4-portrait": {
            orientation: "portrait",
            unit: "cm",
            format: "a4",
            maxWidth: 18,
            maxHeight: 23,
            left: 1.5,
            top: 3,
            space: 0.5
        },
        "a4-landscape": {
            orientation: "landscape",
            unit: "cm",
            format: "a4",
            maxWidth: 23,
            maxHeight: 18,
            left: 1.5,
            top: 3,
            space: 0.5
        }
    };

    (function () {
        document.getElementById("export").addEventListener("click", function (e) {
            var orientation = document.getElementById("pdf-orientation").value;
            var format = document.getElementById("pdf-format").value;
            var config = pdfConfig[format + "-" + orientation];
            var blob = createPdfAsBlobOnePage(config);
            DayPilot.Util.downloadBlob(blob, "calendar.pdf");
        });
    })();

    function createPdfAsBlobOnePage(config) {
        var pdf = new jsPDF(config.orientation, config.unit, config.format);
        pdf.setFontSize(20);
        pdf.text(config.left, config.top, "Calendar");

        var image = dp.exportAs("jpeg", {
            scale: 2,
            quality: 0.95
        });

        var dimensions = image.dimensions();  // pixels
        var maxDimensions = {width: config.maxWidth, height: config.maxHeight};   // inches
        var adjusted = shrink(dimensions, maxDimensions);

        pdf.addImage(image.toDataUri(), 'JPEG', config.left, config.top + config.space, adjusted.width, adjusted.height);

        return pdf.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>