Groupios-folderShape

By Kamal Sharma

Businesses often need webpage data to be converted into a PDF so they can see a snapshot of business critical pages. If you need to display a Visualforce page as a PDF, just put “Render As” equal to PDF, and it works.
If you want to send a Visualforce page as a PDF attachment, the same will work with four to five lines of code in the controller. This is because anything rendered through JavaScript won’t display on the PDF page. In reality, the Visualforce page to PDF conversion happens on the server side, and the stuff which is supposed to render on the client side will not appear in the converted PDF. If we want to convert only the chart, then we have a solution, we can use Google Chart. But keep in mind that these charts are deprecated ones. The latest Google Chart will be rendered at client side.
A no-excuse solution helps to resolve not only this PDF rendering issue but also lots of print-related issues too. What happens if we take a screenshot of the page and render that screenshot image as a PDF? This way, the PDF will have the same look and content as it shows on the screen to the end user.
There are numerous available JavaScript libraries that can convert a page into an image, and an image into a PDF. Once you have access to this, your implementation of the solution can vary as per the exact requirement.
I have put a sample working process here as an example — you can enhance or modify it based on your requirements:

Visualforce Page:

<apex:page docType="html-5.0" controller="SEM_BlogController" showHeader="false" sidebar="false" standardStylesheets="false">

   <head>

       <title>Demo</title>

       <!-- Libraries to take screenshot and image to pdf conversion-->

       <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

       <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.min.js"></script>

       <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>

       <script src="https://cdnjs.cloudflare.com/ajax/libs/amcharts/3.13.0/exporting/rgbcolor.js"></script>

       <script src="https://cdnjs.cloudflare.com/ajax/libs/amcharts/3.13.0/exporting/canvg.js"></script>

       <!-- Code to take screenshot and image to pdf conversion-->

       <script>

           function render(targetElem) {

               var nodesToRecover = []

               var nodesToRemove = []

               var svgs = $(targetElem).find('svg');

               svgs.each(function(index, node) {

                   var parentNode = node.parentNode

                   var svg = parentNode.innerHTML

                   var canvas = document.createElement('canvas')

                   xml = (new XMLSerializer()).serializeToString(node)

                   xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '')

                   canvg(canvas, xml); // html to image

                   nodesToRecover.push({

                       parent: parentNode,

                       child: node

                   })

                   parentNode.removeChild(node)

                   nodesToRemove.push({

                       parent: parentNode,

                       child: canvas

                   })

                   parentNode.appendChild(canvas)

               })

               

               html2canvas(targetElem, {

                   onrendered: function(canvas) {

                       canvas.style.visibility = 'hidden'

                       

                       document.body.appendChild(canvas);

                       var doc = new jsPDF('p', 'pt', [canvas.height,canvas.width]); // create pdf file

                       doc.addHTML(canvas, {}, function() { // add image to pdf file

                           sendEmail(btoa(doc.output()));

                           document.body.removeChild(canvas)

                       })

                   }

               })

           }

       </script>

   </head>

   <body>

       <apex:form >

           <apex:actionFunction action="{!sendEmail}" name="sendEmail" rerender="" status="counterStatus" >

               <apex:param name="pdfContent" assignTo="{!pdfContent}" value="" />

           </apex:actionFunction>

           

           <div class="buttonAndMessageContainer">

               <apex:actionStatus startText="Sending Email...."

                                  stopText="Email Sent Successfully!" startStyle="display:block;" stopStyle="display:none;" id="counterStatus"/>

               

               <div class="buttonContainer" >

                   <apex:commandButton reRender="messageForSendMail" value="Send Result as Email Attachment" onclick="render(document.getElementById('resultForPdf'))"></apex:commandButton>

               </div>

           </div>

           

           <div id="resultForPdf">

               <apex:repeat value="{!questionMap}" var="question">

                   <div>

                       <span id="{!question}"></span>

                   </div>

                   

                   <apex:chart renderTo="{!question}" data="{!questionMap[question].chartData}" height="300" width="300" background="#F5F5F5">

                       <apex:legend position="bottom"/>

                       <apex:pieSeries labelField="name" dataField="data" donut="50">

                           <apex:chartLabel display="none" orientation="vertical"

                                            font="bold 18px Helvetica"/>

                       </apex:pieSeries>

                   </apex:chart>

               </apex:repeat>

           </div>

       </apex:form>

   </body>

</apex:page>

Controller:

public class SEM_BlogController {

   public Map<String,Question> questionMap {get;set;}

   public String message {get;set;}

   private String emailId;

   

   //constructor

   public SEM_BlogController(){

       questionMap = new Map<String,Question>();

       emailId = 'demo@gmail.com';

       populateChartData();

   }

   public void populateChartData() {

       Question que;

       List<chartDataWrapper> data;

       chartDataWrapper chartData;

       for(Integer i = 0 ; i < 5 ; i++){

           data = new List<chartDataWrapper>();

           for(Integer j = 0 ; j < 3 ; j++){

               chartData = new chartDataWrapper('ans' + j,  j + 8);

               data.add(chartData);

           }

           que = new Question();

           que.question = 'Demo Question ' + i + '?';

           que.chartData = data;

           questionMap.put(que.question,que);

       }

   }

   

    public void sendEmail(){

       

       String body = Apexpages.currentPage().getParameters().get('pdfContent');

       Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

       String[] toAddresses = new String[]{emailId};

       

           mail.setToAddresses(toAddresses);

           mail.setSubject('Demo PDF');

           mail.setPlainTextBody('Hi, PFB the sample PDF file.');

           mail.setBccSender(false);

           mail.setUseSignature(false);

           mail.saveAsActivity = false;

           body = body.replace('https://c.cs83.visual.force.com/', '');

           // Add to attachment file list

           List<Messaging.Emailfileattachment> fileAttachments = new List<Messaging.Emailfileattachment>();

           Messaging.Emailfileattachment efa = new Messaging.Emailfileattachment();

           efa.setFileName('demo.pdf');

           efa.setBody(EncodingUtil.base64Decode(body));

           fileAttachments.add(efa);

           mail.setFileAttachments(fileAttachments);

           //Send email

           

           Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

           message = 'Email has been send successfully!';

   }

 

// Wrapper class

   public class chartDataWrapper {

 

       public String name { get; set; }

       public Integer data { get; set; }

 

       public chartDataWrapper(String name, Integer data) {

           this.name = name;

           this.data = data;

       }

   }

   public class Question{

       public String question {get;set;}

       public List<chartDataWrapper> chartData {get;set;}

   }

}

You may have excuses, but you have a way as well to find out the solution.

Join the Conversation

Your email address will not be published. Required fields are marked *

close-link
close-link
Subscribe to our blogs

close-link
Subscribe to our blogs