Canvas 调整chart.js画布的大小以进行打印

Canvas 调整chart.js画布的大小以进行打印,canvas,chart.js,Canvas,Chart.js,我正在使用@media print{自定义我的打印视图。我的图表的问题是,它们的打印大小取决于浏览器窗口的大小。因此,当我的浏览器很大时,画布对于页面来说会太大(我正在使用响应图表) 我试图在@media print{中重新定义画布的大小,但没有成功 当我打印时(不影响我的浏览器视图),有哪些解决方案可以获得一致的图表大小 问题是图表不适合新的打印宽度维度。幸运的是,我们可以在启动打印时执行重画 解决方案是在调用打印时使用canvas.toDataURL()方法将图表呈现为图像,然后在打印后将其

我正在使用
@media print{
自定义我的打印视图。我的图表的问题是,它们的打印大小取决于浏览器窗口的大小。因此,当我的浏览器很大时,画布对于页面来说会太大(我正在使用响应图表)

我试图在
@media print{
中重新定义画布的大小,但没有成功

当我打印时(不影响我的浏览器视图),有哪些解决方案可以获得一致的图表大小


问题是图表不适合新的打印宽度维度。幸运的是,我们可以在启动打印时执行重画

解决方案是在调用打印时使用
canvas.toDataURL()
方法将图表呈现为图像,然后在打印后将其切换回画布图表

要检测何时调用函数,webkit提供方法
window.matchMedia('print')
(在打印期间为
true
,之后为
false
),而其他浏览器使用
window.onbeforeprint
window.onafterprint


然后剩下要做的就是使用CSS确保图像响应,即缩放到100%宽度。

我为画布使用了自定义打印样式,并使用了自定义右填充:

@media print {
  .chartCanvas {
    padding-right: 1cm;
  }
}

按照链接和Reggie Pinkham的示例,我能够在Angular 2中实现这一点。示例是typescript,但读者应该能够相当轻松地将其应用于常规JavaScript,以便在其他项目中工作。请注意,我只在Linux box上的最新Chrome版本中测试了这一点,因为这对于我的内部公司来说很好y项目

// imports left out here
export class ScaleChartComponent implements OnInit {
private chart:Chart;
private chartNode:HTMLCanvasElement;
private chartImage:HTMLImageElement;
private mediaQueryListener:MediaQueryListListener;

// el is a reference to the root node of my angular html component think of it as just a div container.
constructor(private el:ElementRef) { }
ngOnDestroy() {
  this.chart.clear();
  this.chart.destroy();
  this.chart = null;
  this.cleanupPrint();
}

ngAfterViewInit() {
  this.drawChart();
  this.setupPrint();
}
// need to setup the event listeners here and hold a reference to cleanup afterwards.
public setupPrint() {
  if (!window.matchMedia) {
    return;
  }

  var mediaQueryList = window.matchMedia('print');
  this.mediaQueryListener = this.handlePrintMediaChange.bind(this);
  mediaQueryList.addListener(this.mediaQueryListener);
}
// make sure to cleanup the reference after the fact.
public cleanupPrint() {
  if (!window.matchMedia) {
    return;
  }
  var mediaQueryList = window.matchMedia('print');
  mediaQueryList.removeListener(this.mediaQueryListener);
  this.mediaQueryListener = null;
}

// here's where the magic happens. I first grab the image
// then 
public handlePrintMediaChange(mql) {
  if (mql.matches) {
    let dataUrl = this.chartNode.toDataURL('image/png');
    
    if (this.chartNode && this.chartNode.parentNode) {
      this.chartImage = new Image();
      this.chartImage.src = dataUrl;
      this.chartNode.parentNode.appendChild(this.chartImage);
      this.chartService.destroyChart(this.chart);
      this.chartNode.parentNode.removeChild(this.chartNode);
    }

  } else {
  // here is where we switch back to non print mode.
    if (this.chartImage) {
      if (this.chartImage.parentNode) {
        this.chartImage.parentNode.removeChild(this.chartImage);
      }
      this.chartImage = null;
    }
    // go through and recreate the entire chart again.
    this.drawChart();
  }
}

public drawChart() {
  var chartData = {}; // setup your chart data here.
  this.chartNode = this.createChartNode();
  if (this.chartNode) {
    this.chart = ; // execute your chart.js draw commands here.
  }
}
private createChartNode() {
   let componentElement = this.el.nativeElement as Element;
   let element = componentElement.querySelector(".scale-chart-container");
  if (!element) {
    console.error("could not find element with class .scale-chart-container");
    return null;
  }

  let chartNode = document.createElement("canvas") as HTMLCanvasElement;
  element.appendChild(chartNode);
  chartNode = chartNode;
  return chartNode;
}
}
请注意,我遗漏了Chart.js命令和数据,因为这些命令和数据会因人员而异。我有一个外部服务来处理我遗漏的内容


我希望这能帮助那些对Reggie的答案感到困惑的人。

如果你的图表很简单,试着使用css

@media print {
    canvas.chart-canvas {
        min-height: 100%;
        max-width: 100%;
        max-height: 100%;
        height: auto!important;
        width: auto!important;
    }
}

这里有一个简单的修复方法,基于它,比Stephen的答案更容易实现:

//修复chartjs打印:
window.onbeforeprint=(ev)=>{
for(Chart.instances中的变量id){
让instance=Chart.instances[id];
设b64=instance.toBase64Image();
设i=新图像();
//代替下面的内容,您可以在
//决定将其更改为什么的图表。这对我很有用
//然而:
i、 style.maxWidth=“100vw”;
i、 src=b64;
让parent=instance.canvas.parentNode;
instance.tempImage=i;
instance.oldDisplay=instance.canvas.style.display;
instance.canvas.style.display=“无”;
父母、子女(一);
}
};
window.onafterprint=(ev)=>{
for(Chart.instances中的变量id){
让instance=Chart.instances[id];
if(instance.tempImage){
让parent=instance.canvas.parentNode;
parent.removeChild(instance.tempImage);
instance.canvas.style.display=instance.oldDisplay;
删除instance.oldsplay;
删除instance.tempImage;
}
}
};

不确定这是如何解决问题的。由于添加了填充,画布仍然没有调整大小。有人知道这方面的工作示例吗?这个问题提供了一个在Chrome中工作的示例,但显然不是在Firefox/IE中。我确认它在Chrome中工作。此解决方案与我的react UI中的react-chartjs-2包装器组件一起工作。比我迄今为止看到的任何其他解决方案都要简单。我在IE、Chrome、MS Edge中进行了测试。在Firefox中没有得到很好的预览,但我认为Firefox设置存在问题。浏览器没有为我正确打印任何页面。我们只是在画布上添加一个类吗?@Briantum你能分享一下吗你的解决方案?这是一个上帝般的答案。谢谢!不幸的是,这在2.9.4版的Chart.js(在Firefox 84和Chrome 87上测试)上对我不起作用。在chartjs 3 beta9上起作用,谢谢!