需求
如下图表,小提琴图和右侧的图例是两个svg实现的,现在需要将这个图表转为图片,并可下载。
预期结果
获得一张图片,包含上图所有内容。
实现思路
将多个svg转为一个canvas元素,通过canvas元素输出base64编码,将base64编码赋值给img元素的src属性,即可通过img元素展示完整的图表。
实现代码
// 将一个svg转换为一个canvas
function drawSVGToCanvas(svg: SVGElement) {
const { width, height } = svg.getBoundingClientRect(); // 方法返回一个对象,该DOMRect对象提供有关元素大小及其相对于视口的位置的信息。
const serializer = new XMLSerializer();
const copy = svg.cloneNode(true);
const data = serializer.serializeToString(copy); // 返回字符串的序列化子树。
const image = new Image();
const blob = new Blob([data], {
type: 'image/svg+xml;charset=utf-8'
});
const url = URL.createObjectURL(blob);
return new Promise(resolve => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
image.addEventListener('load', () => {
ctx && ctx.drawImage(image, 0, 0, width, height);
URL.revokeObjectURL(url);
resolve(canvas);
}, { once: true });
image.src = url;
})
}
// 将多个svg转为base64编码
async function convertSVGsToSingleImage(svgs: SVGElement[], format = 'image/png') {
const canvas = document.createElement('canvas');
const ctx: any = canvas.getContext('2d');
const drawSVGs = Array.from(svgs).map(svg => drawSVGToCanvas(svg))
const renders = await Promise.all(drawSVGs);
canvas.width = Math.max(...renders.map((render: any) => render.width));
canvas.height = Math.max(...renders.map((render: any) => render.height));
renders.forEach((render: any) => ctx.drawImage(render, 0, 0, render.width, render.height));
const source = canvas.toDataURL(format).replace(format, 'image/octet-stream');
return source;
}
// 使用函数实现功能
convertSVGsToSingleImage(svgList).then(source => {
const image = new Image();
// image.addEventListener('load', () => {
// preview.append(image); // 如果需要将img元素添加到html中,此处preview即为容器元素
// })
image.src = source;
const imgOptions = {
src: source
};
store.commit('addCacheImages', imgOptions); // 此处的做法为将base64编码赋值到系统的其他地方(图片缓存组件)
});