最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - RedrawResize highcharts when printing website - Stack Overflow

programmeradmin2浏览0评论

When I'm printing the bottom right frame the text some text is partly covered by the highcharts because they don't resize before printing. Is there a solution to configure a printing layout with @media print for the website and force highcharts to redraw/resize to container size when website is printed?

HTML

<script src=".js"></script>
<script src=".js"></script>

<div id="container" style="height: 400px"></div>
<div id="container" style="height: 400px"></div>

JavaScript

$(function () {
    Highcharts.setOptions({ // Apply to all charts
        chart: {
            events: {
                beforePrint: function () {
                    this.oldhasUserSize = this.hasUserSize;
                    this.resetParams = [this.chartWidth, this.chartHeight, false];
                    this.setSize(600, 400, false);
                },
                afterPrint: function () {
                    this.setSize.apply(this, this.resetParams);
                    this.hasUserSize = this.oldhasUserSize;
                }
            }
        }
    });

    $('#container').highcharts({

        title: {
            text: 'Rescale to print'
        },

        subtitle: {
            text: 'Click the context menu and choose "Print chart".<br>The chart size is set to 600x400 and restored after print.'
        },

        xAxis: {
            categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
        },

        series: [{
            data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
        }]

    });

});

JSFiddle

When I'm printing the bottom right frame the text some text is partly covered by the highcharts because they don't resize before printing. Is there a solution to configure a printing layout with @media print for the website and force highcharts to redraw/resize to container size when website is printed?

HTML

<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>

<div id="container" style="height: 400px"></div>
<div id="container" style="height: 400px"></div>

JavaScript

$(function () {
    Highcharts.setOptions({ // Apply to all charts
        chart: {
            events: {
                beforePrint: function () {
                    this.oldhasUserSize = this.hasUserSize;
                    this.resetParams = [this.chartWidth, this.chartHeight, false];
                    this.setSize(600, 400, false);
                },
                afterPrint: function () {
                    this.setSize.apply(this, this.resetParams);
                    this.hasUserSize = this.oldhasUserSize;
                }
            }
        }
    });

    $('#container').highcharts({

        title: {
            text: 'Rescale to print'
        },

        subtitle: {
            text: 'Click the context menu and choose "Print chart".<br>The chart size is set to 600x400 and restored after print.'
        },

        xAxis: {
            categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
        },

        series: [{
            data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
        }]

    });

});

JSFiddle

Share Improve this question edited Sep 28, 2015 at 10:51 IKavanagh 6,18711 gold badges45 silver badges48 bronze badges asked Sep 28, 2015 at 10:38 user3665396user3665396 1911 gold badge1 silver badge9 bronze badges 2
  • Welcome to StackOverflow. I've edited your post to include the code from JSFiddle inline. It is more appropriate for questions on SO to include the code inline as the question would become useless if the link ever died. – IKavanagh Commented Sep 28, 2015 at 10:51
  • FYI, JSFiddle url should be http (jsfiddle.net/kscvce93) instead of https (https now blocks loading of scripts from other non-https sites) – Leonya Commented May 10, 2019 at 17:41
Add a comment  | 

4 Answers 4

Reset to default 11

Using listener that will trigger reflow for a chart and media queries in CSS chart should be printed in set size when printing a website.

JS:

$(function () {
    Highcharts.setOptions({ // Apply to all charts
        chart: {
            events: {
                beforePrint: function () {
                    this.oldhasUserSize = this.hasUserSize;
                    this.resetParams = [this.chartWidth, this.chartHeight, false];
                    this.setSize(600, 400, false);
                },
                afterPrint: function () {
                    this.setSize.apply(this, this.resetParams);
                    this.hasUserSize = this.oldhasUserSize;
                }
            }
        }
    });

    $('#container').highcharts({
        title: {
            text: 'Rescale to print'
        },
        subtitle: {
            text: 'Click the context menu and choose "Print chart".<br>The chart size is set to 600x400 and restored after print.'
        },
        xAxis: {
            categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
        },
        series: [{
            data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
        }]
    });

    var printUpdate = function () {
        $('#container').highcharts().reflow();
    };

    if (window.matchMedia) {
        var mediaQueryList = window.matchMedia('print');
        mediaQueryList.addListener(function (mql) {
            printUpdate();
        });
    }
});

CSS:

@page {
    size: A4;
    margin: 0;
}
@media print {
    html, body {
        padding:0px;
        margin:0px;
        width: 210mm;
        height: 297mm;
    }
    #container {
        float:left;
        padding: 0px;
        margin: 0px;
        width: 80%;
    }
}

HTML:

<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="height: 400px;"></div>

JSFiddle: http://jsfiddle.net/w4ro5xb7/13/

Test in full screen result for better effect: http://jsfiddle.net/w4ro5xb7/13/show/

Here is a mix of different solutions, with no need of exporting.js (which adds exporting button to all graphs on page...)

The size is automatically rescaled, then reset after print.

Tested mostly on IE

window.onbeforeprint = function() {
    $(Highcharts.charts).each(function(i,chart){
        chart.oldhasUserSize = chart.hasUserSize;
        chart.resetParams = [chart.chartWidth, chart.chartHeight, false];

        var height = chart.renderTo.clientHeight;
        var width = chart.renderTo.clientWidth;
        chart.setSize(width, height);
    });
}
window.onafterprint = function() {
    $(Highcharts.charts).each(function(i,chart){
        chart.setSize.apply(chart, chart.resetParams);
        chart.hasUserSize = chart.oldhasUserSize;
    });
}

UPDATE: I now use a different version, fixing the size of each chart instead of using clientWidth. It works on the 3 browsers I tested (IE 11, FF & Chrome)

function redimChartBeforePrint(chart, width, height) {
    if (typeof(width) == 'undefined')
        width  = 950;
    if (typeof(height) == 'undefined')
        height = 400;
    chart.oldhasUserSize = chart.hasUserSize;
    chart.resetParams = [chart.chartWidth, chart.chartHeight, false];
    chart.setSize(width, height, false);
}
function redimChartAfterPrint(chart) {
    chart.setSize.apply(chart, chart.resetParams);
    chart.hasUserSize = chart.oldhasUserSize;
}

window.onbeforeprint = function() {
    redimChartBeforePrint($('#chart1').highcharts());
    redimChartBeforePrint($('#chart2').highcharts(), 800, 600);
    ...
};
window.onafterprint = function() {
    redimChartAfterPrint($('#chart1').highcharts());
    redimChartAfterPrint($('#chart2').highcharts());
    ...
};

Taking these suggestions, I wanted to offer a 3rd approach that should solve some of the shortcomings of the previous answers in conjunction with other solutions I have seen elsewhere, resulting in what worked for me (that the above did not).

Setting window.onbeforeprint is fine, unless you have other onbeforeprint handlers and don't want to blow them away. window.addEventListener('onbeforeprint', function) allows you to both set numerous separate event listeners, AND remove them when you're done. Additionally, Safari does not support these specific event listeners anyways, so it is recommended to use window.matchMedia instead, which is supported on all evergreen browsers.

function _setupPrintHandler() {
    let chart; // save a local copy so you don't have to find the element again.
    var beforePrint = function() {
        chart = $('#container').highcharts();
        if (chart) {
            // Set your arbitrary width/height needed for printing
            // Save the existing chart info if explicitly set
            // beforeChartWidth = chart.chartWidth;
            // beforeChartHeight = chart.chartHeight;
            const printWidth = 710, printHeight = 450;
            chart.setSize(printWidth, printHeight, false);
            chart.reflow()
        }
    };
    var afterPrint = function() {
        if (chart) {
            // if the previous values were saved, use them, otherwise `null` will return to auto-fit the container size
            const prevWidth = beforeChartWidth || null;
            const prevHeight = beforeChartHeight || null;
            chart.setSize(prevWidth, prevHeight, false);
            chart.reflow();
        }
    };

    // use the new window.matchMedia query with better support
    if (window.matchMedia) {
        var mediaQueryList = window.matchMedia('print');
        mediaQueryList.addListener(function(mql) {
            if (mql.matches) {
                beforePrint();
            } else {
                afterPrint();
            }
        });
    }
    // Fallback if matchMedia isn't available
    else {
        window.addEventListener('onbeforeprint', beforePrint);
        window.addEventListener('onafterprint', afterPrint);
        // Use elsewhere if needed:
        // window.removeEventListener('onbeforeprint', beforePrint)
        // window.removeEventListener('onafterprint', afterPrint)
    }
};

Update:

Runnable example sans jQuery because it's 2020. Use the "expand snippet" link to test the print scenario.

Highcharts.setOptions({ // Apply to all charts
  chart: {
    events: {
      beforePrint: function() {
        // Not called from global print event
        this.oldhasUserSize = this.hasUserSize;
        this.resetParams = [this.chartWidth, this.chartHeight, false];
        this.setSize(600, 400, false);
      },
      afterPrint: function() {
        //not called from global print event
        this.setSize.apply(this, this.resetParams);
        this.hasUserSize = this.oldhasUserSize;
      }
    }
  }
});

Highcharts.chart('container', {
  title: {
    text: 'Rescale to print'
  },
  subtitle: {
    text: 'The chart size is set to 600x400 and restored after User-prompted print.'
  },
  xAxis: {
    categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
      'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
    ]
  },
  series: [{
    data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
  }]
});


function _setupPrintHandler() {
let beforeChartWidth, beforeChartHeight;
  var beforePrint = function() {
    // Access cached charts without jQuery
    Highcharts.charts.forEach(chart => {
      if (chart) {
        // Set your arbitrary width/height needed for printing
        // Save the existing chart info if explicitly set
        // beforeChartWidth = chart.chartWidth;
        // beforeChartHeight = chart.chartHeight;
        const printWidth = 600,
          printHeight = 200;
        chart.setSize(printWidth, printHeight, false);
        chart.reflow()
      }
    });
  };
  var afterPrint = function() {
    Highcharts.charts.forEach(chart => {
      if (chart) {
        // if the previous values were saved, use them, otherwise `null` will return to auto-fit the container size
        const prevWidth = beforeChartWidth || null;
        const prevHeight = beforeChartHeight || null;
        chart.setSize(prevWidth, prevHeight, false);
        chart.reflow();
      }
    });
  };

  // use the new window.matchMedia query with better support
  if (window.matchMedia) {
    var mediaQueryList = window.matchMedia('print');
    mediaQueryList.addListener(function(mql) {
      if (mql.matches) {
        beforePrint();
      } else {
        afterPrint();
      }
    });
  }
  // Fallback if matchMedia isn't available
  else {
    window.addEventListener('onbeforeprint', beforePrint);
    window.addEventListener('onafterprint', afterPrint);
    // Use elsewhere if needed:
    // window.removeEventListener('onbeforeprint', beforePrint)
    // window.removeEventListener('onafterprint', afterPrint)
  }
};

// Run the setup function
_setupPrintHandler()
<script src="https://code.highcharts.com/highcharts.js"></script>
<!-- Don't need exporting anymore -->
<!-- <script src="https://code.highcharts.com/modules/exporting.js"></script> -->

<div id="container" style="height: 400px"></div>

I have 2 lines of charts , first has one but second has many chart.

After click on print button I resize the charts to larger size then print then resize to the old size in html.

Get the old width : chart.plotSizeX

Get the old height : chart.plotSizeY

All charts are chartsDiv :

function btnChartsPrintClick() {
    let chart0 = $('#chart0').highcharts();
    chart0.setSize(700, 300, false); // resize the chart0 to larger size
    // let oldWidth = chart0.plotSizeX;
    // let oldHeight = chart0.plotSizeY;

    var chartCourseTypes = document.getElementsByClassName("chartCourseTypes");
    for (var i = 0; i < chartCourseTypes.length; i++) {
        let chart = $('#' + chartCourseTypes.item(i).id).highcharts();
        chart.setSize(700, 300, false);
    }   

    var mywindow = window.open('', 'PRINT');
    mywindow.document.write('<html><head><title>' + document.title + '</title>');
    mywindow.document.write('</head><body >');
    mywindow.document.write('<div style="text-align: center;">');
    let chartsDiv = document.getElementById('chartsDiv').innerHTML;
    //chartsDiv = chartsDiv.replace(/col-md-6/g, '');
    mywindow.document.write(chartsDiv);
    mywindow.document.write('</div>');
    mywindow.document.write('</body></html>');
    mywindow.document.close(); // necessary for IE >= 10
    mywindow.focus(); // necessary for IE >= 10*/
    mywindow.print();

    chart0.setSize(716, 345, false); // resize to the old size

    for (var i = 0; i < chartCourseTypes.length; i++) {
        let chart = $('#' + chartCourseTypes.item(i).id).highcharts();
        chart.setSize(331, 294, false); // resize to the old size
    }

    return true;
}

发布评论

评论列表(0)

  1. 暂无评论