Reputation: 778
I created a chart using html canvas. The result would like it to be printed as a PDF file using Kendo. It works, but the graphic quality is very poor. For the solution I need I can't use kendo chart for limitation reasons
report.html
<div class="width-100-perc text-center">
<canvas id="canvas" width="100" height="100"></canvas>
<br />
</div>
report.ts
drawChart() {
console.log( 'foi');
const canvas: HTMLCanvasElement = (<HTMLCanvasElement>document.getElementById('canvas'));
console.log(this.series);
if (canvas) {
const ctx = canvas.getContext('2d');
// Base offset distance of 10
const offset = 0;
let beginAngle = 0;
let endAngle = 0;
// Used to calculate the X and Y offset
let offsetX, offsetY, medianAngle;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fill();
for (let i = 0; i < this.angles.length; i = i + 1) {
beginAngle = endAngle;
endAngle = endAngle + this.angles[i];
// The medium angle is the average of two consecutive angles
medianAngle = (endAngle + beginAngle) / 2;
// X and Y calculations
offsetX = Math.cos(medianAngle) * offset;
offsetY = Math.sin(medianAngle) * offset;
ctx.beginPath();
ctx.fillStyle = this.series[0].data[i].color;
// Adding the offsetX and offsetY to the center of the arc
ctx.moveTo(50 + offsetX, 50 + offsetY);
ctx.arc(50 + offsetX, 50 + offsetY, 40, beginAngle, endAngle);
ctx.lineTo(50 + offsetX, 50 + offsetY);
ctx.fill();
}
if (this.angles.length > 0) {
ctx.beginPath();
ctx.fillStyle = '#FFFFFF';
ctx.arc(50, 50, 15, 0, 2 * Math.PI);
ctx.fill();
}
}
}
Upvotes: 1
Views: 813
Reputation: 2250
This is not a problem with kendo's pdf export. Rather, it's inherent to the way the HTML canvas works. Your export looks distorted and pixelated because, at the end of the day, it's just a 100x100 image, which is rather low resolution. I'm assuming you want it to be that small since it is made to fit a specific part of the page. If you just directly export this canvas, that pixelated image is what you should expect.
I can propose this workaround. You need to refactor your drawChart()
method to take into account a scale (number). This would mean multiplying all x,y coordinates and dimensions by this value. By default, the scale is 1. When exporting to pdf, you will follow these steps:
This way, the chart is temporarily redrawn using a higher resolution canvas. In it's high(er) resolution state, it's exported and then it's redrawn with its original dimensions.
If you provide some example values of your this.angles
and this.series
I can refactor your drawChart()
function to take this into account. As it stands, I can't. But I've prepared a similar example here. This is the ReportComponent
I've created.
report.component.html
<button (click)="savePdf(false)">bad pdf</button>
<button (click)="savePdf(true)">good pdf</button>
<br/>
<kendo-pdf-export #pdf>
<canvas #canvas [width]="baseWidth" [height]="baseHeight"></canvas>
</kendo-pdf-export>
report.component.ts
export class ReportComponent implements AfterViewInit {
@ViewChild("canvas", { static: false })
public canvasRef: ElementRef<HTMLCanvasElement>;
@ViewChild("pdf", { static: false })
public pdf: PDFExportComponent;
@Input() public title: string = "";
public scale: number = 1;
public baseWidth: number = 100;
public baseHeight: number = 100;
constructor() {}
ngAfterViewInit() {
this.draw();
}
draw() {
const canvas = this.canvasRef.nativeElement;
canvas.width = this.baseWidth * this.scale; // scaled
canvas.height = this.baseHeight * this.scale; // scaled
const context = canvas.getContext("2d");
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 31.4 * this.scale; // scaled
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = "green";
context.fill();
context.lineWidth = 5 * this.scale; // scaled
context.strokeStyle = "#003300";
context.stroke();
}
savePdf(good: boolean) {
if (good) {
// scale 10x and re-draw
this.scale = 10;
this.draw();
this.pdf.saveAs("good.pdf");
this.scale = 1;
this.draw();
} else {
// just draw as is
this.pdf.saveAs("bad.pdf");
}
}
}
Upvotes: 2