linux 不识别 svg,解决html2canvas插件不能识别svg的问题

缘起

近期在使用 html2canvas 插件生成图片时,发现对于 svg 元素支持不是很好。

而且查阅网友的解决方案时, 发现是一份原文和N份copy, 总体来说解决方案有以下几种:

0、使用 canvg 插件转换 svg 元素

//以下是对svg的处理

var nodesToRecover = [];

var nodesToRemove = [];

var svgElem = $("#divReport").find('svg');//divReport为需要截取成图片的dom的id

svgElem.each(function (index, node) {

var parentNode = node.parentNode;

var svg = node.outerHTML.trim();

var canvas = document.createElement('canvas');

canvg(canvas, svg);

if (node.style.position) {

canvas.style.position += node.style.position;

canvas.style.left += node.style.left;

canvas.style.top += node.style.top;

}

nodesToRecover.push({

parent: parentNode,

child: node

});

parentNode.removeChild(node);

nodesToRemove.push({

parent: parentNode,

child: canvas

});

parentNode.appendChild(canvas);

});

这里有 nodesToRecover 和 nodesToRemove 两个变量,猜测应该是方便回滚用, 但是并没有回滚的相关代码。

1、把 svg 元素转换为图片,然后再转换成 canvas元素

//允许跨域获取,否则百度地图不能生成图片

const opts = {

useCORS: true,

ignoreElements: el => {

const tagName = el.tagName.toLowerCase();

const list = ['head', 'body', 'style', 'title', 'meta']

if(list.includes(tagName)) return false;

// id="extra" 下所有节点忽略

if(el.id === 'extra') return true;

return false;

},

// TODO:: SVG to canvas

onclone(cloneDom) {

const svgElems = $(cloneDom).find('svg');

svgElems.each(function (index, node) {

let parentNode = node.parentNode;

const svg_string = (node.outerHTML || xmlserializer.serializeToString(node)).trim()

const img = new Image();

img.src = 'data:image/svg+xml;charset=utf-8,' + svg_string;

img.crossOrigin = 'anonymous';

img.onload = function(){

const width = parseFloat($(node).css('width'));

const height = parseFloat($(node).css('height'));

const canvas = document.createElement('canvas');

canvas.width = width;

canvas.height = height;

const ctx = canvas.getContext("2d");

ctx.drawImage(img, 0, 0, width, height);

parentNode.appendChild(canvas).

parentNode.removeChild(node);

}

});

}

}

我发现百度地图上的 svg 元素是有绝对定位和偏移的, 他们的方案不能解决偏移的问题。

性空

后来测试方案0并不成功。 测试方案一,是因为没有追加图片到document 里面,导致没有触发onload方法失败的, 这里进行如下改进:

0、把当前页面的svg元素转换为 canvas 元素:

// 把svg转换为canvas

async convertSvg2Canvas() {

const svgElms = document.getElementsByTagName('svg');

// 回调

const callbacks = [];

for(let svg of svgElms) {

const parentElement = svg.parentElement;

const img = new Image();

img.src = `data:image/svg+xml,${encodeURIComponent((new XMLSerializer()).serializeToString(svg))}`;

img.crossOrigin = 'anonymous';

img.onload = async () => {

const width = parseFloat(svg.style.width);

const height = parseFloat(svg.style.height);

const canvas = document.createElement('canvas');

canvas.width = width;

canvas.height = height;

const ctx = canvas.getContext("2d");

ctx.drawImage(img, 0, 0, width, height);

parentElement.append(canvas);

svg.remove();

img.remove();

};

parentElement.append(img);

callbacks.push(img.onload);

}

//await this.axios.all(callbacks);

await Promise.all(callbacks);

},

1、等待svg转换完成之后,再使用html2canvas 截图:

async getPreviewImg() {

//显示加载图标

this.$store.dispatch('showDataloader');

await Promise.all([this.loadScript('/static/js/html2canvas.min.js'), this.convertSvg2Canvas()]);

//允许跨域获取,否则百度地图不能生成图片

const opts = {

useCORS: true

}

const canvasObj = await html2canvas(document.getElementById('poster_context'), opts);

var context = canvasObj.getContext('2d');

//防止图片模糊的设置

context.mozImageSmoothingEnabled = false;

context.webkitImageSmoothingEnabled = false;

context.msImageSmoothingEnabled = false;

context.imageSmoothingEnabled = false;

// png 格式图片

let imgType = "image/png";

this.canvasSrc = canvasObj.toDataURL(imgType);

this.previewShowFlag = true;

//隐藏加载图标

this.$store.dispatch('hideDataloader');

},

……

说明: 截屏的时候,必须等待 svg 元素全部转换成为 canvas 元素才可以,否则是截取不成功的

loadScript 方法用来异步加载js, 本人是全局mixin的, 下附 loadScript 方法:

// 动态加载 js 及 回调

async loadScript(src, callback = null) {

await new Promise(resolve => {

// 如果已经加载了本js,直接调用回调

if (this.checkScriptLoaded(src)) {

return resolve(callback);

}

let scriptNode = document.createElement("script");

scriptNode.setAttribute("type", "text/javascript");

scriptNode.setAttribute("src", src);

document.body.appendChild(scriptNode);

if (scriptNode.readyState) { //IE 判断

scriptNode.onreadystatechange = () => {

if (scriptNode.readyState == "complete" || scriptNode.readyState == 'loaded') {

return resolve(callback);

}

}

} else {

scriptNode.onload = () => resolve(callback);

}

})

},

// 检测是否加载了 js 文件

checkScriptLoaded(src) {

const scriptObjs = Array.from(document.getElementsByTagName('script'));

return scriptObjs.find(ele => ele.src.includes(src));

},

他山之石

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值