关于网页下载图表长图图片的一些感触

885 阅读5分钟

因为工作需要,近期一直在做关于数据的报告,pc端窗口的,东西不是很难但是久下载功能上遇到了很多坑。

html2canvas

1.html2canvas能够实现在用户浏览器端直接对整个或部分页面进行截屏。
2.这个html2canvas脚本将当页面渲染成一个Canvas图片,通过读取DOM并将不同的样式应用到这些元素上实现。
3.它不需要来自服务器任何渲染,整张图片都是在客户端浏览器创建。
4.当浏览器不支持Canvas时,将采用Flashcanvas或ExplorerCanvas技术代替实现。
5.以下浏览器能够很好的支持该脚本:Firefox 3.5+, Google Chrome, Opera新的版本, IE9以上的浏览器。

用法

html2canvas(element, options)
    html2canvas(document.body, {
      onrendered: function(canvas) {
        var url = canvas.toDataURL();//图片地址
        document.body.appendChild(canvas);
      },
  width: 300,
  height: 300
})

所以,当时首选的还是html2canvas,这个名气比较大,但是,用之前听说存在很多坑,自己还不信,就去试了试,真是初生牛犊不怕虎啊,最后这点坑是跨不过去了,其中:

兼容性

1.首先,图片上模糊,特别是文件机器打的时候,需要把图片转成base64格式的,
2.html2canvas虽然可以控制图片的质量有点好处(在同一个js长页面中可以控制质量来缓解浏览器的压力),
但是对Firefox于火狐浏览器,会有报错,下载失败err,所以本小白又找到了替代他的domtoimage,这个下文会仔细介绍的。
3.html2canvas性能损耗很厉害,很容易造成浏览器的崩溃,所以又想下载出品质高清的图片着实有点难。

不知不觉身在魔都的我也被台风侵袭!!!

常用代码

方法一
var canvas = document.getElementById('pieChart')
function base64Img2Blob(code){
    var parts = code.split(';base64,')
    var contentType = parts[0].split(':')[1]
    var raw = window.atob(parts[1])
    var rawLength = raw.length
    var uInt8Array = new Uint8Array(rawLength)
for (var i = 0; i < rawLength; ++i) {
  uInt8Array[i] = raw.charCodeAt(i)
}
return new Blob([uInt8Array], {type: contentType})
}
function downloadFile(){
    var aLink = document.createElement('a')
    var blob = base64Img2Blob(canvas.toDataURL("image/png")) //new Blob([content])
    var evt = document.createEvent("HTMLEvents")
    evt.initEvent("click", false, false);//initEvent 不加后两个参数在FF下会报错
    aLink.download = new Date().getTime() + ".png"
    aLink.href = URL.createObjectURL(blob)
    aLink.dispatchEvent(evt)
}
方法二
   window.onload = function() {
    var canvas = document.getElementById("pieChart")
    var context = canvas.getContext("2d")
    // no argument defaults to image/png; image/jpeg, etc also work on some
    // implementations -- image/png is the only one that must be supported per spec.
    window.location = canvas.toDataURL("image/png")
    }
方法三
var canvas = document.getElementById("pieChart");
var ctx = canvas.getContext('2d');
var btn = document.getElementById('btn1');
btn.onclick() = function() {
    var type = 'png';
    download(type);
}
function download(type) {
    var imgdate = canvas.toDataURL(type);
    var fixtype = function(type) {
        type = type.toLowerCase().replace(/jpg/i, 'jpeg');
        var r = type.match(/png|jpeg|bmp|gif/)[0];
        return 'image' +  r;
    }
    imgdata = imgdata.replace(fixtype(type), 'image/octet-stream')
    var saveFile = function (data, filename) {
        var link = document.createElement('a');
        link.href = data;
        link.download = filename;
        var event = document.createElement('MouseEvents');
        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        link.dispatchEvent(event);
    }
    var filename = new Date().toLocaleDateString() + '.' + type;
    saveFile(imgdate, filename);
}

文字生成

// 默认a4大小,竖直方向,mm单位的PDF
var doc = new jsPDF();
// 添加文本‘Download PDF’
doc.text('Download PDF!', 10, 10);
doc.save('a4.pdf'); 

图片生成PDF

// 三个参数,第一个方向,第二个单位,第三个尺寸格式
var doc = new jsPDF('landscape','pt',[205, 115])
// 将图片转化为dataUrl
var imageData = ‘data:image/png;base64,iVBORw0KGgo...’;
doc.addImage(imageData, 'PNG', 0, 0, 205, 115);
doc.save('a4.pdf');

文字与图片生成PDF

 // 三个参数,第一个方向,第二个尺寸,第三个尺寸格式
var doc = new jsPDF('landscape','pt',[205, 155])
// 将图片转化为dataUrl
var imageData = ‘data:image/png;base64,iVBORw0KGgo...’;
//设置字体大小
doc.setFontSize(20);
//10,20这两参数控制文字距离左边,与上边的距离
doc.text('Stone', 10, 20);
// 0, 40, 控制文字距离左边,与上边的距离
doc.addImage(imageData, 'PNG', 0, 40, 205, 115);
doc.save('a4.pdf')

html2canvas + jsPDF

单页

var downPdf = document.getElementById("renderPdf");
downPdf.onclick = function() {
    html2canvas(document.body, {
        onrendered:function(canvas) { 
        //小编个人认为,不用单独的去声名createElement一下canvans
        ,分页的时候一定要搭配async\await更佳
          //返回图片dataURL,参数:图片格式和清晰度(0-1)
          var pageData = canvas.toDataURL('image/jpeg', 1.0);
          //方向默认竖直,尺寸ponits,格式a4[595.28,841.89]
          var pdf = new jsPDF('', 'pt', 'a4'); // 不传默认是a4格式
          //addImage后两个参数控制添加图片的尺寸,此处将页面高度按照a4纸宽高比列进行压缩
          pdf.addImage(pageData, 'JPEG', 0, 0, 595.28, 592.28/canvas.width * canvas.height );
          pdf.save('stone.pdf');
        }
    }
}

多页

var downPdf = document.getElementById("renderPdf");
    downPdf.onclick = function() {
        async function getPdf() {
            for (var i = 0, i < downPdf.length; i += 1; ) {
                await html2canvas(document.body, {
                    onrendered:function(canvas) { 
                      //返回图片dataURL,参数:图片格式和清晰度(0-1)
                      这里我没有写opts,有很多参数,scale等有需要得可以设置
                      var pageData = canvas.toDataURL('image/jpeg', 1.0);
                      //方向默认竖直,尺寸ponits,格式a4[595.28,841.89]
                      var pdf = new jsPDF('', 'pt', 'a4'); // 不传默认是a4格式
                      //addImage后两个参数控制添加图片的尺寸,此处将页面高度按照a4纸宽高比列进行压缩
                      pdf.addImage(pageData, 'JPEG', 0, 0, 595.28, 592.28/canvas.width * canvas.height );
                      pdf.save('stone.pdf');
                    }
                }
            }
        }
        getPdf(downPdf)
    }
})

}

domtoimage

html2canvas转换的base64位图不能被火狐/ios8以上版本所识别。会呈现出整个截图页面空白
问题分析:
这个问题的起因,应该是html2canvas对高版本的ios不支持(自我感觉),这个问题我很是头疼,当时根本没有对ios进行测
试。思来想去感觉html2canvas坑太多了。填都填不完。于是...
解决办法:
我采用了另一款插件,dom-to-image,弄上去没有问题了。

dom-to-image运用上去,在ios上能够出现内容了,但发现存在一个问题,部分图片内容,第一次进行公众号网页加载,没有
正确显示,要在次进入才会显示,此bug同样是ios8以上版本
问题分析:
这一个问题我没有找到问题所在,一脸懵,不过最终还是得到了解决。
解决办法:
运用dom-to-imagede toSvg方式完美解决问题。

 domtoimage.toPng(pdfWrapper).then(function (dataUrl: any) {
  const pageData = dataUrl
  const tpye = 'image/png'
  const baseStr = pageData.substr(pageData.indexOf('base64,') + 7, pageData.length)
  const blob = b64toBlob(baseStr, tpye, 512)
  if (navigator.msSaveBlob) {
    navigator.msSaveBlob(blob, `${'xxxx'}${'.png'}`)
  } else {
    const a = document.createElement('a')
    a.download = `${'XXXX'}${'.png'}`
    a.href = URL.createObjectURL(blob)
    document.body.appendChild(a)
    a.click()
    a.remove()
  }
  unLoadBtn.style.display = 'block'
  loadBtn.style.display = 'none'
  document.getElementById('Anchor')!.style.display = 'block'
}).catch((err: any) => {
  self.toggleTabelFix(true)
  message.error('下载报告失败')
  unLoadBtn.style.display = 'block'
  loadBtn.style.display = 'none'
  document.getElementById('Anchor')!.style.display = 'block'
  console.log('下载报告失败', err)
})

总结

不同的浏览器之间兼容性是不同的,这个还学要具体问题具体分析,本小白只是根绝我所需要的进行了查阅分享给大家,
更多的还是要各位大佬去挖掘。