相关文章推荐
高大的眼镜  ·  使用AudioContext和WebSock ...·  1 月前    · 
豪爽的牛肉面  ·  impala recursive - CSDN文库·  2 月前    · 
爱听歌的抽屉  ·  Présentation de ...·  10 月前    · 

在项目中有这样一个需求,需要调用其他系统业务API生成页面(canvas)渲染图表,并将图表导出成PDF文件,上传到服务器,并将文件地址,传给第三方业务系统,使第三方业务系统能够通过文件服务器下载该图表PDF文件

以上就是原始的需求描述了

当我们接到这个需求的时候就已经大概或许猜测出,这事流程较复杂,能不能直接甩锅到后端同学,让后端同学去完成这一系列的骚操作。

尽管 前后端 都是可以完成的。

但是后端有一个难点(耗时点)是画图表的操作;只要图表能够画出来,剩下的无非就是 canvas 转 pdf 文件,然后调用文件服务 service 进行上传,同步第三方系统,完事。

呐. 需要前端提供 画图表的模版什么的,或者需要前端吧canvas 转 图片 或者 pdf .

这一波操作下来, 好像前端的工作量也没怎么减少。

经过一系列沟通与讨论,发现一个很nice点就是,生成图表的业务,已经封装成npm 包了。

那这事 就显得 不那么棘手了。

现在 我们具体简单整理 整个流程:

step1. 在本系统安装 图表 npm 包,调用业务系统API 生成图表

step2. 将生成的canvas图表 转成 pdf

step3. 将pdf上传拿到文件路径

step4. 将pdf文件路径同步给第三方

整个需求梳理下来的流程就大概就是这了。

经过上述的需求分析 我们大致 明确了每一步需要做的操作了。

现在我们就具体分析一下可能存在的细节或遗漏点

先查看了 图表的npm 包,先集成 这个包 进入 我们自己的业务系统,并隐藏

同时生成多张图表,并将多张生成一个PDF文件 ???

PDF的分页问题?

PDF的临时存储 ? 要不要先下载下来 让用户再手动选择文件进行上传?能不能接受这多一步的操作,或者我们能不能规避这一步的操作呢?

PDF的上传? 到底是用户手动选择上传 还是 程序自动静默上传 ?其实我们都偏向后者,减少用户操作,一步到位

因为是多张图表,具体多少张不知道,可能几张,可能几时上百张,没有给出具体阈值? 这个问题就显得比较尖锐了,主要反应在两个方面:

第一方面:一次渲染这么多canvas 页面必定会卡顿或直接浏览器崩溃

第二方面:就算上面说的页面不卡顿或者浏览器不崩溃,生成的pdf文件大小如果太大,上传也将是一个问题,这个时候就又要考虑大文件上传方案了。

第三方面:这一系列的操作虽然是自动静默进行的,能不能在页面上反馈出进度或状态,让用户知晓当前进行到哪一步了。

那我们还是本着先实现功能,再优化细节的方式进行了demo的编写;

本文就仅给出大概实现思路和部分参考代码:

集成 图表 组件 comA

< button @ click = "handleCanvasToPdf" > 下载PDF </ button > < div ref = "canvasList" > < com-a v-for = "(item,index) in list" :key = "item.id" :ref = "'comA_'+index" />

安装 jsPDF

npm install jspdf -S

methods :{ async handleLoadData ( ){ const res = await API . request ( '/xxx/xxx' ,{ size : 3 }) const list = res. data || [], handleCanvasToPdf ( ){ const canvasList = this . $refs . canvasList . querySelectorAll ( 'canvas' ) if (!canvasList. length ){ return } const cacheImageList = canvasList. map ( ( canvas )=> { return canvas. toDataURL ( 'image/jpeg' , 1 ) // 创建一个pdf 文档 指定 现实方式,单位,及默认大小 const pdf = new jsPDF ( 'p' , 'pt' , 'a4' ) const width = pdf. internal . pageSize . getWidth () const height = pdf. internam . pageSize . getHeight () // 把图片内容添分页加到 pdf 文档中,这里没有做计算分页,我们一张图片就渲染一页 cacheImageList. forEach ( ( img,index )=> { pdf. addImage (img, 'JPEG' , 0 , 0 ,width,height) // 分页 , 如果不是最后一页就添加一页 if (imageCacheList. length - 1 !== index){ padf. addPage () // pdf 文档已经准备好了,现在只需要导出就好了 pdf. save ( 'temp.pdf' ) 运行上面的方法 就能自动下载pdf 文件了 打开下载下来的 PDF 文件,果然如预期,直呼内行 .......

当调整参数 size = 20 后等请求完成后,立马点击 下载PDF 新的问题就来了:

PDF中 部分 页面内容空白,而且是靠后,越往后越空白!甚至在前几页内容都不完整,有些图表内容也仅仅只渲染了一半;

只需搭眼一看,就知道是渲染时间的问题,所有的canvas 还没有渲染完成就被拿去转换成文件了。要如何解决这个问题呢 ? 请看下一篇!

最后的最后

经过我们简单的demo 发现整个过程还是很顺畅的 现在所暴露的问题也慢慢浮现了,让我们简单整理下一现在要解决的问题:

  • 如何不下载PDF到本地磁盘,就能上传???
  • 如何保证PDF多页面不空白,也就是如何保证canvas列表已经全部渲染???
  • 如何保证很多个图表渲染的时候页面不卡顿???
  • 下一篇 我们继续分析如何解决上述问题

    使用jsPdf 将页面生成PDF文件并自动上传 DEMO(二)

    下面有请今天的主角小趴菜:

    小趴菜.jpeg