forked from qq15725/modern-screenshot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dom-to-foreign-object-svg.ts
100 lines (87 loc) · 2.9 KB
/
dom-to-foreign-object-svg.ts
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { cloneNode } from '../clone-node'
import { orCreateContext } from '../create-context'
import { destroyContext } from '../destroy-context'
import { embedWebFont } from '../embed-web-font'
import { embedNode } from '../embed-node'
import {
consoleWarn,
createSvg,
isElementNode,
isSVGElementNode,
} from '../utils'
import type { Context } from '../context'
import type { Options } from '../options'
export async function domToForeignObjectSvg<T extends Node>(node: T, options?: Options): Promise<SVGElement>
export async function domToForeignObjectSvg<T extends Node>(context: Context<T>): Promise<SVGElement>
export async function domToForeignObjectSvg(node: any, options?: any) {
const context = await orCreateContext(node, options)
if (isElementNode(context.node) && isSVGElementNode(context.node)) return context.node
const {
ownerDocument,
log,
tasks,
svgStyleElement,
svgDefsElement,
svgStyles,
font,
progress,
autoDestruct,
onCloneNode,
onEmbedNode,
onCreateForeignObjectSvg,
} = context
log.time('clone node')
const clone = await cloneNode(context.node, context, true)
if (svgStyleElement && ownerDocument) {
let allCssText = ''
svgStyles.forEach((klasses, cssText) => {
allCssText += `${ klasses.join(',\n') } {\n ${ cssText }\n}\n`
})
svgStyleElement.appendChild(ownerDocument.createTextNode(allCssText))
}
log.timeEnd('clone node')
onCloneNode?.(clone)
if (font !== false && isElementNode(clone)) {
log.time('embed web font')
await embedWebFont(clone, context)
log.timeEnd('embed web font')
}
log.time('embed node')
embedNode(clone, context)
const count = tasks.length
let current = 0
const runTask = async () => {
while (true) {
const task = tasks.pop()
if (!task) break
try {
await task
} catch (error) {
consoleWarn('Failed to run task', error)
}
progress?.(++current, count)
}
}
progress?.(current, count)
await Promise.all([...Array(4)].map(runTask))
log.timeEnd('embed node')
onEmbedNode?.(clone)
const svg = createForeignObjectSvg(clone, context)
svgDefsElement && svg.insertBefore(svgDefsElement, svg.children[0])
svgStyleElement && svg.insertBefore(svgStyleElement, svg.children[0])
autoDestruct && destroyContext(context)
onCreateForeignObjectSvg?.(svg)
return svg
}
function createForeignObjectSvg(clone: Node, context: Context): SVGSVGElement {
const { width, height } = context
const svg = createSvg(width, height, clone.ownerDocument)
const foreignObject = svg.ownerDocument.createElementNS(svg.namespaceURI, 'foreignObject')
foreignObject.setAttributeNS(null, 'x', '0%')
foreignObject.setAttributeNS(null, 'y', '0%')
foreignObject.setAttributeNS(null, 'width', '100%')
foreignObject.setAttributeNS(null, 'height', '100%')
foreignObject.append(clone)
svg.appendChild(foreignObject)
return svg
}