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