首页 >pdf操作 > 内容

【总结记录】Superset中dashboard图表进行html的编辑并转为pdf下载

2023年1月1日 12:08

需求:使用superset搭建的BI项目,需要在dashboard模块中,可以编辑所选的图表,并且将html下载为pdf格式的文件。BI页面展示大体如下:

功能分析

1.首先,我们需要一个预览功能,那就点击右上角三个点的按钮,弹出弹窗展示范围内的图表即可,这个实现的话主要就是把图表拿过来的过程,这个具体看代码如何实现;

2.然后我们需要在弹窗对html进行编辑操作,我们看到可操作性的不知图表还有text、table以及input输入框等内容,我们需要一个专业的插件的开完成,于是我们找到了jodit-react插件(因为代码使用了react框架,所以我们选择这个);

3.将修改后的页面保存并且下载为pdf格式,网上百度了一圈,我只找到两个插件,但实现的原理都是一样,我们选择大家基本都在用的插件,html2canvas和jspdf来实现。

实现过程以及遇到的问题

1.实现预览

我们需要先拿到这个需要展示的部分,看到页面上有一个下载图表为image的功能,直接操作了dom元素去拿页面,并且考虑到,使用jodit的时候需要传入的是string格式的html,所以,我们也直接去操作它的dom吧(不推荐,但是如过获取组件数据太麻烦。。);

那么我们就遇到了第一个问题,右边menu菜单,再打开弹窗的时候出现的延迟,预览的画面展示出了menu,这时候我们用了cloneNode,并删掉了对应的节点,所以现在我们展示的就是克隆后的节点html:

然后我们又遇到了canvas实现的图表无法正常显示的问题,我想到的方法就是toDataURL方法拿到url,并替换canvas为img,将url赋值给src属性,下面是具体的方法,我是用递归,因为可能下载的是一整页,就有很多canvas标签的情况,如下:

2.下面我们对预览的内容进行修改

之后也得到了html,这个是克隆并处理过的数据,我们用这个数据直接去进行下载pdf,网上的代码基本如下所示(这个是我拿来测试的):

<!DOCTYPE HTML><html>  <head>    <title>HTML转PDF测试</title>    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <style type="text/css">      /* Basic styling for root. */      #root {        width: 500px;        height: 700px;        background-color: yellow;      }      .dragdroppable {        position: relative;      }      .dragdroppable-row {        width: 100%;      }    </style>  </head>  <body>    <button onclick="test()">生成PDF</button>    <div id="app" style="height: 500px;border: 1px solid;">app</div>    <div class="dragdroppable dragdroppable-row">      <div id="root">        <svg xmlns="http://www.w3.org/2000/svg" version="1.1">          <polyline points="20,20 40,25 60,40 80,120 120,140 200,180"          style="fill:none;stroke:black;stroke-width:3" />        </svg>      </div>    </div>    <script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js"></script>    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.0.272/jspdf.debug.js"></script>    <script>      function test() {        // 获取DIV元素        var element1 = document.getElementById('root');        var element = element1.cloneNode(true);        var w = element.offsetWidth;    // 获得该容器的宽        var h = element.offsetHeight;    // 获得该容器的高        var offsetTop = element.offsetTop;    // 获得该容器到文档顶部的距离        var offsetLeft = element.offsetLeft;    // 获得该容器到文档最左的距离        var canvas = document.createElement("canvas");        var abs = 0;        var win_i = document.body.clientWidth;    // 获得当前可视窗口的宽度(不包含滚动条)        var win_o = window.innerWidth;    // 获得当前窗口的宽度(包含滚动条)        if (win_o > win_i) {            abs = (win_o - win_i) / 2;    // 获得滚动条长度的一半        }        canvas.width = w * 2;    // 将画布宽&&高放大两倍        canvas.height = h * 2;        var context = canvas.getContext("2d");        context.scale(2, 2);        context.translate(-offsetLeft - abs, -offsetTop);        // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此        // translate的时候,要把这个差值去掉        document.body.appendChild(element);        html2canvas(element, {            allowTaint: true,            scale: 2, // 提升画面质量,但是会增加文件大小        }).then(function (canvas) {            document.body.removeChild(element);            var contentWidth = canvas.width;            var contentHeight = canvas.height;            //一页pdf显示html页面生成的canvas高度;            var pageHeight = contentWidth / 592.28 * 841.89;            //未生成pdf的html页面高度            var leftHeight = contentHeight;            //页面偏移            var position = 0;            //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高            var imgWidth = 595.28;            var imgHeight = 592.28 / contentWidth * contentHeight;            var pageData = canvas.toDataURL('image/jpeg', 1.0);            var pdf = new jsPDF('', 'pt', 'a4');            //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)            //当内容未超过pdf一页显示的范围,无需分页            if (leftHeight < pageHeight) {                pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);            } else {    // 分页                while (leftHeight > 0) {                    pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)                    leftHeight -= pageHeight;                    position -= 841.89;                    //避免添加空白页                    if (leftHeight > 0) {                        pdf.addPage();                    }                }            }            pdf.save(`${name}.pdf`);        });      }    </script>  </body></html>

结果是可以正常展示的,下面我们运用起来。

可以正常下载,但是如果按照上面的配置,那么下载出的pdf内容,就可能无法显示,原因是因为它继承了图表在页面上的位置,pdf显示为空白,由于已经提前测试了插件,可以排除插件的问题,并且我去掉了预览功能直接下载进行测试,结果也不正常,这就证明,superset的图表和插件有冲突。

3.尝试直接操作canvas图表的样式

1)尝试着给它添加绝对定位的样式;

2)尝试在html2canvas上添加高度;

3)最后又想到了,替换canvas变成替换为img,实现的代码如下所示:

 let element = document.getElementById('copyDom');    domToImage    .toJpeg(element, {      quality: 0.95,      bgcolor: '#fff',      // Mapbox controls are loaded from different origin, causing CORS error      // See https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL#exceptions      filter: (node) =>        node.className !== 'mapboxgl-control-container',      ...{},    })    .then(dataUrl => {        var imgWidth = 595.28;        var imgHeight = 592.28 / element.offsetWidth * element.offsetHeight;        var pageHeight = element.offsetWidth / 592.28 * 841.89;        var leftHeight = element.offsetHeight;        var pdf = new jsPDF('', 'pt', _type ? [imgWidth, imgHeight] : 'a4');        var p = 0;        pdf.addImage(dataUrl, 'JPEG', 0, 0, imgWidth, imgHeight);        pdf.save(`${name}.pdf`);        document.body.removeChild(element);    })

实现的原理都是一样的,方式变了而已,这个方法可以实现下载pdf并且样式正常,我没有分页,分页的代码会出现内容被分割,因为这些图表没有规律,也不是自己写的,没法具体到每一个观察高度,中间还出现了克隆的html没法使用的问题,我想到它可能不在整个页面中,于是使用appendChild将html加载body的后面,然后再下载完成之后,remove掉,成功解决问题。。

总结问题及解决方法

1.canvas画出的图表无法显示的问题

这个可以使用方法将canvas转为img标签;

2.superset的dashboard图表无法使用html2canvas正常显示

插件没有问题,但是却和superset产生了冲突,换一种方式,转为图片再下载;

3.克隆html时

要注意如果无法显示或者操作,就将html写在body上,然后记得remove,就可以正常显示和操作属性了;


参考文章:https://blog.csdn.net/q553866469/article/details/119884967

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时候联系我们修改或删除,在此表示感谢。

特别提醒:

1、请用户自行保存原始数据,为确保安全网站使用完即被永久销毁,如何人将无法再次获取。

2、如果上次文件较大或者涉及到复杂运算的数据,可能需要一定的时间,请耐心等待一会。

3、请按照用户协议文明上网,如果发现用户存在恶意行为,包括但不限于发布不合适言论妄图

     获取用户隐私信息等行为,网站将根据掌握的情况对用户进行限制部分行为、永久封号等处罚。

4、如果文件下载失败可能是弹出窗口被浏览器拦截,点击允许弹出即可,一般在网址栏位置设置

5、欢迎将网站推荐给其他人,网站持续更新更多功能敬请期待,收藏网站高效办公不迷路。

      



登录后回复

共有0条评论