How to Convert Canvas to SVG

Before, I made a request for a relational graph. Because exporting png and other images will be distorted when enlarged, I hope to export them as vector graphs. However, the export graph function that comes with G6 cannot be exported as SVG in Canvas mode, and SVG mode has many features that are not supported, so I tried to find a way to export Canvas as SVG.

This code uses an old library called canvas-to-svg

This library simulates canvas and exposes some canvas apis, which can finally be exported as svg

It should be noted that some canvas APIs do not support, such as setTransform, resetTransform, etc. If you need to use these two APIs, you can split them into translate and rotate, etc

Directly upload the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import CanvasToSVG from 'canvas-to-svg';
function addTextWaterMaskToCanvas(
context: CanvasRenderingContext2D,
textWaterMask: string,
) {
context.font = '16px Microsoft YaHei';
context.fillStyle = '#F2F3F5';
const { width, height } = context.canvas;
const textMaskCountHorizontal = Math.max(1, width / 150);
const textMaskCountVertical = Math.max(1, height / 150);
const fwidth = width / textMaskCountHorizontal;
const fheight = height / textMaskCountVertical;
for (let hh = 0; hh < height; hh += fheight) {
for (let ww = 0; ww < width; ww += fwidth) {
context.translate(ww, hh);
context.rotate(-Math.atan(height / width));
context.fillText(textWaterMask, -fwidth / 2, fheight / 2);
context.rotate(Math.atan(height / width));
context.translate(-ww, -hh);
}
}
}

export function downloadFullImageWithWaterMaskCreator(
graphInstance: IGraph | null,
textWaterMask: string,
) {
return function (
name?: string,
type?: DataUrlType,
imageConfig?: {
backgroundColor?: string;
padding?: number | number[];
},
callback?: (success: boolean) => void,
) {
graphInstance?.toFullDataURL(
res => {
const image = new Image();
image.src = res;
image.onload = function () {
try {
// const canvas = document.createElement('canvas');
// canvas.width = image.width;
// canvas.height = image.height;
// const context = canvas.getContext('2d');
const context = new CanvasToSVG(image.width, image.height);
if (context && name) {
context.rect(0, 0, image.width, image.height);
context.drawImage(image, 0, 0, image.width, image.height);

addTextWaterMaskToCanvas(context, textWaterMask);

// downloadCanvasImage(canvas, name, type);

const svg = context.getSerializedSvg(true);
const svgData = URL.createObjectURL(
new Blob([svg], { type: 'image/svg' }),
);
const downloadLink = document.createElement('a');
downloadLink.download = `${name}.svg`;
downloadLink.href = svgData;
downloadLink.click();

callback?.(true);
}
} catch {
callback?.(false);
}
};

image.onerror = function () {
callback?.(false);
};
},
type,
imageConfig,
);
};
}