Search code examples
jsfprimefaceschartsexportjqplot

Primefaces charts crashing chrome when exporting as image


We are trying to export charts generated by primefaces(jqplot) through exportAsImage function:

function exportChart() {

    try {
        imgPie = PF('graphicPie').exportAsImage(); // this is an instance of p:pieChart
        document.getElementById('frmReports:b64_gr0').value = imgPie.src;
    }catch(err){  
    }
    try {
        imgBar = PF('graphicBarEvent').exportAsImage(); // this is an instance of p:barChart, here is where the script crashes 
        document.getElementById('frmReports:b64_gr1').value = imgBar.src;
    }catch(err){
    }

 }

The first chart (pieChart) exports with no problem, but when the script tries to export the second chart (barChart), the web page freezes and Chrome shows "Aw, Snap!" exception.

This only happens in Chrome and only with clients in a different domain (if we test this script in the same machine where the application server is running, the script works fine).

barChart component code:

<p:barChart id="graphicBarEvent" widgetVar="graphicBarEvent"
    showDatatip="false" value="#{reportsMB.barEventModel}"
    legendPosition="n" style="height:170px; width: 100%;"
    seriesColors="#{reportsMB.factBarChartSeriesColors}"
    legendCols="3" extender="bar_ext" >
    <p:ajax event="itemSelect" listener="#{reportsMB.itemSelectFactBars}" /> 
</p:barChart>

Solution

  • Found the issue, apparently there is a bug in jqplot function that was causing infinite loop in Chrome.

    i had to override this JS function: jqplotToImageCanvas specifically this inner method:

      function writeWrappedText (el, context, text, left, top, canvasWidth) {
                 var lineheight = getLineheight(el);
                 var tagwidth = $(el).innerWidth();
                 var tagheight = $(el).innerHeight();
                 var words = text.split(/\s+/);
                 var wl = words.length;
                 var w = '';
                 var breaks = [];
                 var temptop = top;
                 var templeft = left;
    
                 for (var i=0; i<wl; i++) {
                     w += words[i];
                   if (context.measureText(w).width > tagwidth && w.length > words[i].length) {
                         breaks.push(i);
                         w = '';
                         i--;
                     }   
                 }
                 if (breaks.length === 0) {
                     // center text if necessary
                     if ($(el).css('textAlign') === 'center') {
                         templeft = left + (canvasWidth - context.measureText(w).width)/2  - transx;
                     }
                     context.fillText(text, templeft, top);
                 }
                 else {
                     w = words.slice(0, breaks[0]).join(' ');
                     // center text if necessary
                     if ($(el).css('textAlign') === 'center') {
                         templeft = left + (canvasWidth - context.measureText(w).width)/2  - transx;
                     }
                     context.fillText(w, templeft, temptop);
                     temptop += lineheight;
                     for (var i=1, l=breaks.length; i<l; i++) {
                         w = words.slice(breaks[i-1], breaks[i]).join(' ');
                         // center text if necessary
                         if ($(el).css('textAlign') === 'center') {
                             templeft = left + (canvasWidth - context.measureText(w).width)/2  - transx;
                         }
                         context.fillText(w, templeft, temptop);
                         temptop += lineheight;
                     }
                     w = words.slice(breaks[i-1], words.length).join(' ');
                     // center text if necessary
                     if ($(el).css('textAlign') === 'center') {
                         templeft = left + (canvasWidth - context.measureText(w).width)/2  - transx;
                     }
                     context.fillText(w, templeft, temptop);
                 }
    
             } 
    

    In chrome when "words" is "0" this results in an infinite loop.