html2canvas 目標元素過長canvas渲染不全【折中方案】

Problem

使用html2canvas.js處理瀏覽器截屏時,發現當元素寬度超過某個閾值後會出現超出部分渲染異常現象。html

Debug

html2canvas截屏,實質是dom轉canvns,canvas轉圖片。

目標寬度20000+pxcanvas

  • 無操做,copyDom顯示正常,canvas寬高正常,但右側元素顯示爲黑塊,且位置居左。
  • withBlack
  • option添加foreignObjectRendering: true,copyDom顯示正常,canvas寬高正常,但右側原異常元素缺失部分文本。
  • lostLabel
  • option指定width爲10000,copyDom顯示正常,canvas寬度10000,導出10000寬-圖正常。

初步推斷canvas渲染有寬度上限,百度一番仍無定論瀏覽器

Solution

首先不是視圖外元素缺失的問題,試了不少都無結果。最後敲定折中方案就是根據寬度計算 拆分出圖。app

Old code

/**
 * @description html轉圖片導出
 * @param ele
 * @param option
 * @param fileName
 * @param uuidKey
 */
export const handleHtml2Down = (ele, option, fileName, uuidKey) => {
    window.pageYOffset = 0;
    document.documentElement.scrollTop = 0
    document.body.scrollTop = 0
    const targetDom = document.querySelector(ele)
    const copyDom = targetDom.cloneNode(true)
    copyDom.style.width = targetDom.scrollWidth + 'px'
    copyDom.style.height = targetDom.scrollHeight + 'px'
    copyDom.style.position = 'absolute'
    copyDom.style.top = '0px'
    copyDom.style.zIndex = '-1'
    copyDom.style.backgroundColor = 'white'
    document.body.appendChild(copyDom)
    html2canvas(copyDom, {
        height: copyDom.scrollHeight,
        width: copyDom.scrollWidth,
        allowTaint: false,
        useCORS: true,
        ...option
    }).then((canvas => {
        copyDom.parentNode.removeChild(copyDom)
        canvas.style.width = parseFloat(canvas.style.width) * 0.8 + 'px'
        canvas.style.height = parseFloat(canvas.style.height) * 0.6 + 'px'
        let imgURL = canvas.toDataURL('image/png',1.0)
        const alink = document.createElement("a")
        alink.href = imgURL
        let theName =  fileName || getUUID(uuidKey)
        alink.download = `${theName}.png`
        alink.click()
    }))
}

New code

/**
 * @description html轉圖片導出【寬度分頁】
 * @param ele 目標dom元素
 * @param option html2canvas函數執行參數
 * @param fileName 導出圖片文件(可不傳)
 * @param uuidKey uuid前綴字符(可不傳)
 */
export const handleHtml2Down = async (ele, option, fileName, uuidKey) => {
    //  reset this page scroll
    window.pageYOffset = 0;
    document.documentElement.scrollTop = 0
    document.body.scrollTop = 0
    //  targetDom - target 2 img
    const targetDom = document.querySelector(ele)
    //  copyDom - copy dom from targetDom
    const copyDom = targetDom.cloneNode(true)
    //   copyWrapper - wrapper contain the copyDom , use for with-overflow
    const copyWrapper = document.createElement('div')
    //  init the copyDom
    copyDom.style.width = targetDom.scrollWidth + 'px'
    copyDom.style.height = targetDom.scrollHeight + 'px'
    copyDom.style.transform = ''
    copyDom.style.margin = '0 0'
    //  define the maxWidth:15000(px)
    const maxW = 15000
    //  define the val
    let urls = [], w = targetDom.scrollWidth,index=0
    //  init the copyWrapper
    copyWrapper.style.backgroundColor = 'white'
    copyWrapper.style.width = (w > maxW ? maxW : w) + 'px'
    copyWrapper.style.height = targetDom.scrollHeight + 'px'
    //  fix the element
    copyWrapper.style.position = 'fixed'
    copyWrapper.style.top = '0px'
    //  make sure the copyWrapper is invisible
    copyWrapper.style.zIndex = '-1'
    //  use for pageControl
    copyWrapper.style.overflow = 'hidden'
    //  execute dom append
    copyWrapper.appendChild(copyDom)
    document.body.appendChild(copyWrapper)
    //  generate canvas from dom in Loop
    while (w > 0){
        await html2canvas(copyWrapper, {
            height: copyWrapper.scrollHeight,
            width: (w > maxW ? maxW : w),
            foreignObjectRendering: true,
            allowTaint: false,
            useCORS: true,
            ...option
        }).then((canvas => {
            canvas.style.width = parseFloat(canvas.style.width) * 0.8 + 'px'
            canvas.style.height = parseFloat(canvas.style.height) * 0.6 + 'px'
            urls.push(canvas.toDataURL('image/png',1.0))
            w = w - maxW
            index++
            copyWrapper.style.width = w
            copyDom.style.marginLeft = `-${maxW * index}px`
        }))
    }
    //  execute dom remove
    copyDom.parentNode.removeChild(copyDom)
    console.log(urls)
    //  export urls & execute img download
    urls.forEach(url=>{
        let alink = document.createElement("a")
        alink.href = url 
        alink.download = `${fileName || getUUID(uuidKey)}.png`
        alink.click()
    })
}
expory getUUID = (preffix)=> { return preffix + 'i-am-uuid-123'}

Result

r1
r2

End

thanks 4 read & welcome 4 leaving a message.dom

相關文章
相關標籤/搜索