记一个用 antv/g6 图表导出 PDF 时的画质偏低解决方案
先吐槽,antv/g6 绝对是我用过的最难用的图表库!谁用谁知道!一大堆不明所以的 api,不是一般的难用!而且有问题问GPT也没用,GPT用的还是G6旧的版本!
说下场景:展示出公司 A 的上下游公司,公司 A 的上下游公司 B 又要展示它的上游或者下游公司 C,画出一个关系图,如:

然后导出的时候,要用到官方的一个api:
toDataURL
const dataURL = await graph.toDataURL({ encoderOptions: 1, // 图片质量, 仅对 image/jpeg 和 image/webp 有效,取值范围 0 ~ 1 mode: 'viewport' // viewport: 导出视口内容 overall: 导出整个画布 });
获取到 dataURL 后,再用 jspdf 进行处理,生成 PDF,处理完之后发现,无论怎么调,画质都很模糊,特别是当渲染的内容过多的时候;后来发现是 mode 的问题, 把 mode 改为 overall 就可以了,会进行全幅导出;但是这时候你发现,导出 JPG 没问题, 导出 PDF 比例失真了,还需要重新计算实际渲染图片的比列和 PDF 的比值,还要区分宽度比高度大、小的情况。直接贴代码记录:
async downloadPdf(graph) { // console.log("graph", graph); // 将DataURL转换为PDF并下载 // await graph.zoomTo(1); const dataURL = await graph.toDataURL({ encoderOptions: 1, // 图片质量, 仅对 image/jpeg 和 image/webp 有效,取值范围 0 ~ 1 mode: 'overall' // viewport: 导出视口内容 overall: 导出整个画布 }); const pdfName = `${this.sourceData.enterpriseName}产业图谱`; // 解决PDF导出比例问题,获取实际渲染的图片的宽高度,而不是画布宽高 const img = await this.getImageDimensionsFromDataURL(dataURL); console.log('img', img.width, img.height) // 将base64的数据URL转换为二进制字符串 var binary = atob(dataURL.split(",")[1]); // 为二进制字符串分配一个ArrayBuffer var array = new Uint8Array(binary.length); for (var i = 0; i < binary.length; i++) { array[i] = binary.charCodeAt(i); } // 使用ArrayBuffer创建Blob对象 // const blob = new Blob([array], { type: "image/jpeg" }); // 将DataURL转换为Blob // 创建jsPDF实例 const pdf = new jsPDF(); // 计算img与pdf宽度的比例,计算出pdf高度 console.log('pdf size', pdf.internal.pageSize.getWidth(), pdf.internal.pageSize.getHeight()) const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const height = img.height; const width = img.width; if (width > height) { // 宽度大于高度的情况 { const w = pdfWidth; const h = height * (pdfWidth / width); // 默认不居中,需要计算居中时y坐标 // const y = Math.abs(pdfHeight - h) / 2; // 将Blob添加到PDF pdf.addImage(array, "JPEG", 0, 0, w, h, pdfName, 'MEDIUM'); } } else { // 宽度小于高度的情况 { let x = 0; let h = pdfHeight; let w = width * (pdfHeight / height); // 默认不居中,需要计算居中时x坐标 x = Math.abs(pdfWidth - w) / 2; if (w > pdfWidth) { w = pdfWidth; h = height * (pdfWidth / width); x = 0; } // 将Blob添加到PDF pdf.addImage(array, "JPEG", x, 0, w, h, pdfName, 'MEDIUM'); } } // 保存生成的PDF pdf.save(pdfName + ".pdf"); }, getImageDimensionsFromDataURL(dataUrl) { return new Promise((resolve, reject) => { // 创建一个Blob对象 const byteString = atob(dataUrl.split(',')[1]); // 移除dataURL的前缀并解码Base64字符串 const ab = new ArrayBuffer(byteString.length); const ia = new Uint8Array(ab); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } const blob = new Blob([ab], { type: 'octet/stream' }); const img = new Image(); img.onload = function () { resolve({ width: img.width, height: img.height }); }; img.onerror = function () { reject(new Error('Failed to load image')); }; // 创建一个可访问的URL并设置给img的src属性 const url = URL.createObjectURL(blob); img.src = url; }); },

浙公网安备 33010602011771号