一、产品需求:
页面上有可拖拽可移动的宫格布局,每个宫格都有echarts图,(即,每个宫格中,只有一个canvas),实现一键截图将宫格的文字、echarts图均截取并下载到本地, 支持截取滚动条下方的内容
二、框架与插件:
1、vue框架
2、插件:html2canvas、echarts、vue-grid-layout
使用html2canvas是为了将 单个宫格中的所有元素都绘制到同一个canvas中
vue-grid-layout可以实现条目的 拖拽、移动
三、流程分析
1、将页面回到顶部
2、获取第一个宫格的所有元素,并放到一个canvas中作为底层canvas
3、依次获取剩余的宫格内容,并绘制到第一个canvas中,关键!!!!
四、代码
getPic() {
// 截图时回到顶部
this.$refs.picContainer.wrap.scrollTop = 0
this.$nextTick(() => {
// 1、先拿到第一个宫格内容,
// 注意:第一个宫格htmlelement.getBoundingClientRect().top是y坐标偏移量,htmlelement.getBoundingClientRect().left是x坐标偏移量
let firstPic = document.getElementById('pic_' + 0)
let baseOffsetX = firstPic.getBoundingById().left
let baseOffsetY = firstPic.getBoundingById().top
// 注意:截取整个网页区域
let fullGridLayoutWidth = firstPic.offsetParent.offsetWidth
let fullGridLayoutHeight = firstPic.offsetParent.scrollHeight
Html2canvas(firstPic, {
scale: 0.9,
width: fullGridLayoutWidth,
height: fullGridLayoutHeight
}).then(canvas => {
// 底层canvas,
const ctx = canvas.getContext('2d')
// 关键::2、将其他宫格的html变成canvas
for(let i = 1; i < 4; i ++) {
setTimeout(() => {
let picDom = document.getElementById('pic_' + i)
Html2canvas(pic, {
scale: 0.9,
width: fullGridLayoutWidth,
height: fullGridLayoutHeight
}).then(canvas => {
let position = this.getPosition(picDom)
let sourceX = position.x * 0.9
let sourceY = position.y * 0.9
let desX = sourceX + baseOffsetX
let desY = sourceY + baseOffsetY
// drawImage的9个参数一定要给准确了,否则无法绘制上去
ctx.drawImage( canvas,
sourceX,
sourceY,
picDom.offsetWidth * 0.9,
picDom.offsetHeight * 0.9,
desX,
desY,
picDom.offsetWidth * 0.9,
picDom.offsetHeight * 0.9
)
// 3、下载截图,已经绘制完最后一个宫格的canvas了
if(i === 3) {
this.imgUrl = ctx.canvas.toDataURL('image/png', 0.9)
// 兼容ie浏览器下载图片
let blob = this.base64ToBlob(this.imgUrl)
if(window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, 'img.png')
return
}
// 非ie浏览器下载
let link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = 'img.png'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}, 100)
}
})
}, 300)
})
},
position(dom) {
let str = dom.style.transform
let str1=str.substring(str.indexOf('(') + 1, str.indexOf(')'))
let str2 = str1.replace(/px/g, '')
let list = str2.split(',')
let pos = {
x: Number(list[0])
y: Number(list[1])
}
return pos
}
function base64ToBlob(urlData, type) {
var mime = 'image/png';
// 去掉url的头,并转化为byte
var bytes = window.atob(urlData);
// 处理异常,将ascii码小于0的转换为大于0
var ab = new ArrayBuffer(bytes.length);
// 生成视图(直接针对内存):8位无符号整数,长度1个字节
var ia = new Uint8Array(ab);
for (var i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], {
type: mime
});
}