Forum Discussion
Creating a pdf file from Storyline running under an LMS
I know there are many excellent examples of how to create a pdf file in Storyline using javascript libraries such as jspdf and I have done this successfully in projects compiled for the web...
...but has anyone tackled this with an lms version? I know you could pass data to the lms using xAPI - but I really just want to click a button and "save" the pdf file created within the course using variables collected during the course.
Any ideas would be welcome.
- JohnCooper-be3cCommunity Member
Just started work on a multi-page pdf document to be produced at the end of a course for my client. The requirement is that there are four screens in the course where the learner is asked to "reflect" on the section they have just covered and decide what they will do as a result.
Each of these screens has two questions - so there are 8 text responses which I have stored in variables in the course. At the end of the course, the learner will click a button to download a 4-page pdf. Each page has a summary of the section, the questions the learner was asked and their responses.
Code similar to that I published earlier works fine for the first page - the notes page is loaded as an image and the learner responses are positioned on the page to fill in the boxes.
I have added:
doc.addPage('landscape');
to the end of the first page and this successfully throws a pagebreak (there are actually two parametrs to this call - the page size is A4 by default but you can specify a different size as well as the orientation).
I will let you know how I get on...
- AriffKhalid-25fCommunity Member
Hi Matthew, Wondering if you could guide me.
i'm still getting the actionator::exeJavaScript - jsPDF is not defined error in console despite defining it in index_lms.html. I've also gone so far as to add it in story.html, index_lms.html, and also added a file href under imsmanifest.xml yet everytime i test it still gives me that error.
May i ask what other locations and changes you would need to make as you mentioned?thank you so much for your time
- Jürgen_Schoene_Community Member
>Yet whenever i add the line "window.jsPDF = window.jspdf.jsPDF" it still doesn't work
have you tested with the UMD (Universal Module Definition) Version?
the UMD Version can used in enviroments without modules ("Raw
<script>
loading") - like storyline javascript triggerresult in the browser console
jsPDF (v2.5.1) is initialized
- JohnCooper-be3cCommunity Member
OK - So I finally got round to looking at the JavaScript library pdf-lib.
The reason I was interested in this library as opposed (or as well as) jsPdf is that it provides code that can modify an existing pdf or, importantly, fill in a pdf form.
The latter is what I was really after. I create a lot of Storyline courses that capture learner input throughout the course and then they provide a button to allow the learner to download the course notes (including their input) as a pdf at the end of the course. There is a demo on our website:
Downloadable Learner Notes (profilelearning.com)
This demo - and the courses we have done so far use the jsPdf library. The multipage pdf is created by adding each page as a png image and then using x and y coordinates (read from a table) to position the learner's input on each page. As you can see from the demo, this works just fine. BUT it is a bit of a chore working out and adjusting the position of each text block and truncating the text if it exceeds the character count.
Filling in a pdf form would make this MUCH easier.
As per the discussion above I also wanted to experiment incorporating 'modern' JavaScript modules into Storyline.
I have got the first test working - I have created a simple form with three text fields, created a single storyline screen to capture three input fields and then used pdf-lib routines to fill in the pdf form
Developing Others 1 (profilelearning.com)
So far so good - this works for web publishing - and it is using the latest pdf-lib ES6 modules. I will now test it as a SCORM package and make sure I can make that call to the ES6 modules work.
I will post my findings
- JohnCooper-be3cCommunity Member
So, as per above, I have managed to create a downloadable pdf incorporating user input by using the JavaScript pdf-lib library. The pdf is a blank pdf form copied to the root folder, which is then filled out by a JavaScript routine using input from the learner. This could be used to fill out an action plan, or create a certificate, or complete some kind of survey.
The other thing is that this demo (see the second link above) uses ESM JavaScript module libraries only (so-called 'modern' JavaScript) - so it uses the pdf-lib and tiny-save-as libraries to create the filled out pdf form and download it.
The consequence of this is that I have been able to load the JavaScript libraries dynamically using the recently added Import () JavaScript construct. i.e. the JavaScript libraries are loaded when Storyline executes the JavaScript - meaning you do not have to edit the story.html or lms_index.html files after publishing the course.
Overall, I'm quite pleased with myself!
- MichaelCarlino-Community Member
Is there a minified version of JsPDF. Or has anyone preloaded the JSPDF that is downloadable from github. It just has a lot of files.
- MarkWCommunity Member
Have any of you been able to load the jsPDF library without editing the story.html file after publishing?
I've seen a few posts referring to doing this on the master slide but haven't gotten it to work myself.
- JohnCooper-be3cCommunity Member
Hi Mark
I haven't loaded jsPDF without modifying the story.html file - but that's because I don't use jsPDF anymore. I prefer to use the pdf-lib library which is more modern and more powerful (see discussion above). Because this library complies with the later ES6 module package format, you can actually load it dynamically FROM WITHIN THE JAVASCRIPT using an IMPORT statement:
async function loadMods() {
await import("https://unpkg.com/pdf-lib/dist/pdf-lib.js");
}NOTE: This should really have some error handling in case it doesn't load,,, but that's straightforward.
Including this in the JavaScript code loads the library from (In this case) the unpkg.com repository at run time. I use an async function to call the 'import' statement so I can use 'await' which will ensure the library is loaded before progressing.
There were a few heroes who criticised this method of loading libraries - but it works fine for me - no noticeable delays. AND, a big plus, it works when using RISE - no messing around with the published code.
With regard to Michael's comment about the size of javaScript libraries, using the Import statement means I can selectively load just the methods I need eg:
import { PDFDocument } from 'https://unpkg.com/pdf-lib';
which means it loads even faster.
Regards
- JohnCooper-be3cCommunity Member
Unfortunately I don't seem to be able to remove the links from the 'https://" statemnets above - I tried - but when I publish the post it just puts them back - ah well - dont follow them...
- MarkWCommunity Member
Thanks, John. We're committed to jsPDF for now, but I will keep this method in mind for the future. Much appreciated.
- JohnCooper-be3cCommunity Member
Hi Sarah,
I did get the multi-page pdf creation working BUT, as I explained above, I don't use the jsPDF library anymore. I use pdf-lib because:
- This reads a pdf form and fills the form in (i.e. no background image and then working out where everything goes) the pdf form can be as many pages as you like.
- You can change the pdf form without having to modify the JavaScript (as long as the form field names remain the same)
- It's way simpler to code and quicker to implement
- You can load the pdf-lib dynamically (i.e. you don't have to change the story.html file after publishing
There is a detailed example and the code is explained in this article:
I know it sounds like a backward step to change your code if you have it partially working but, believe me, you won't regret changing to pdf-lib it is much more powerful and so much quicker to code and use.
Best regards, John