@logicflow/extension 2.0.0-beta.2 → 2.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/dist/index.min.js +2 -2
- package/es/components/menu/index.d.ts +1 -1
- package/es/components/menu/index.js +9 -10
- package/es/components/menu/index.js.map +1 -1
- package/es/index.d.ts +1 -0
- package/es/index.js +1 -0
- package/es/index.js.map +1 -1
- package/es/insert-node-in-polyline/index.js +3 -3
- package/es/insert-node-in-polyline/index.js.map +1 -1
- package/es/materials/node-selection/index.d.ts +2 -1
- package/es/materials/node-selection/index.js +64 -56
- package/es/materials/node-selection/index.js.map +1 -1
- package/es/tools/snapshot/index.d.ts +101 -11
- package/es/tools/snapshot/index.js +331 -147
- package/es/tools/snapshot/index.js.map +1 -1
- package/es/tools/snapshot/utils.d.ts +35 -0
- package/es/tools/snapshot/utils.js +238 -0
- package/es/tools/snapshot/utils.js.map +1 -0
- package/lib/components/menu/index.d.ts +1 -1
- package/lib/components/menu/index.js +9 -10
- package/lib/components/menu/index.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/insert-node-in-polyline/index.js +2 -2
- package/lib/insert-node-in-polyline/index.js.map +1 -1
- package/lib/materials/node-selection/index.d.ts +2 -1
- package/lib/materials/node-selection/index.js +63 -55
- package/lib/materials/node-selection/index.js.map +1 -1
- package/lib/tools/snapshot/index.d.ts +101 -11
- package/lib/tools/snapshot/index.js +331 -147
- package/lib/tools/snapshot/index.js.map +1 -1
- package/lib/tools/snapshot/utils.d.ts +35 -0
- package/lib/tools/snapshot/utils.js +247 -0
- package/lib/tools/snapshot/utils.js.map +1 -0
- package/package.json +7 -4
- package/src/components/menu/index.ts +16 -13
- package/src/index.ts +1 -0
- package/src/insert-node-in-polyline/index.ts +3 -3
- package/src/materials/node-selection/index.ts +72 -69
- package/src/tools/snapshot/README.md +130 -5
- package/src/tools/snapshot/index.ts +264 -98
- package/src/tools/snapshot/utils.ts +163 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 图片缓存, 已请求过的图片直接从缓存中获取
|
|
3
|
+
*/
|
|
4
|
+
const imageCache: Record<string, string> = {}
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 当获取图片失败时会返回失败信息,是 text/plain 类型的数据
|
|
8
|
+
* @param str - 图片内容
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
export function isTextPlainBase64(str: string) {
|
|
12
|
+
return str.startsWith('data:text/plain')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 将网络图片转为 base64
|
|
17
|
+
* @param url - 图片地址
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export async function convertImageToBase64(url: string): Promise<string> {
|
|
21
|
+
if (imageCache[url]) {
|
|
22
|
+
return imageCache[url]
|
|
23
|
+
}
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
try {
|
|
26
|
+
fetch(url)
|
|
27
|
+
.then((response) => response.blob())
|
|
28
|
+
.then((blob) => {
|
|
29
|
+
const reader = new FileReader()
|
|
30
|
+
reader.onloadend = () => {
|
|
31
|
+
resolve((imageCache[url] = reader.result as string))
|
|
32
|
+
}
|
|
33
|
+
reader.onerror = reject
|
|
34
|
+
reader.readAsDataURL(blob)
|
|
35
|
+
})
|
|
36
|
+
.catch(() => {
|
|
37
|
+
resolve((imageCache[url] = url))
|
|
38
|
+
})
|
|
39
|
+
} catch (error) {
|
|
40
|
+
// 如果转换失败,后续大概率仍然会失败,因此直接缓存
|
|
41
|
+
return (imageCache[url] = url)
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 使用 base64 的图片替换 img 标签的 src 或 image 标签的 href
|
|
48
|
+
* @param node - html 节点或 svg 节点
|
|
49
|
+
*/
|
|
50
|
+
export async function updateImageSrcOrHrefWithBase64Image(
|
|
51
|
+
node: HTMLImageElement | SVGImageElement,
|
|
52
|
+
attrName: 'src' | 'href',
|
|
53
|
+
) {
|
|
54
|
+
try {
|
|
55
|
+
const url = node.getAttribute(attrName) || ''
|
|
56
|
+
// 已经是 base64 图片,不需要处理
|
|
57
|
+
if (url.startsWith('data:')) {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
const base64Image = await convertImageToBase64(url)
|
|
61
|
+
if (isTextPlainBase64(base64Image)) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
node.setAttribute(attrName, base64Image)
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(error)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 使用 base64 的图片替换背景图片
|
|
72
|
+
* @param node - html 节点
|
|
73
|
+
* @param styleAttr - 样式属性名称
|
|
74
|
+
*/
|
|
75
|
+
export async function updateBackgroundImageWithBase64Image(
|
|
76
|
+
node: HTMLElement,
|
|
77
|
+
url: string,
|
|
78
|
+
) {
|
|
79
|
+
try {
|
|
80
|
+
// 已经是 base64 图片,不需要处理
|
|
81
|
+
if (url.startsWith('data:')) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
const base64Image = await convertImageToBase64(url)
|
|
85
|
+
if (isTextPlainBase64(base64Image)) {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
node.style.backgroundImage = `url(${base64Image})`
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error(error)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 更新图片数据
|
|
96
|
+
* @param node - 节点
|
|
97
|
+
*/
|
|
98
|
+
export async function updateImageSource(node: HTMLElement | SVGElement) {
|
|
99
|
+
const nodes = [node]
|
|
100
|
+
let nodePtr
|
|
101
|
+
const promises: any[] = []
|
|
102
|
+
while (nodes.length) {
|
|
103
|
+
nodePtr = nodes.shift()
|
|
104
|
+
if (nodePtr.children.length) {
|
|
105
|
+
nodes.push(...nodePtr.children)
|
|
106
|
+
}
|
|
107
|
+
if (nodePtr instanceof HTMLElement) {
|
|
108
|
+
// 如果有 style 的 background, backgroundImage 属性中有 url(xxx), 尝试替换为 base64 图片
|
|
109
|
+
const { background, backgroundImage } = nodePtr.style
|
|
110
|
+
const backgroundUrlMatch = background.match(/url\(["']?(.*?)["']?\)/)
|
|
111
|
+
if (backgroundUrlMatch && backgroundUrlMatch[1]) {
|
|
112
|
+
const imageUrl = backgroundUrlMatch[1]
|
|
113
|
+
promises.push(updateBackgroundImageWithBase64Image(nodePtr, imageUrl))
|
|
114
|
+
}
|
|
115
|
+
const backgroundImageUrlMatch = backgroundImage.match(
|
|
116
|
+
/url\(["']?(.*?)["']?\)/,
|
|
117
|
+
)
|
|
118
|
+
if (backgroundImageUrlMatch && backgroundImageUrlMatch[1]) {
|
|
119
|
+
const imageUrl = backgroundImageUrlMatch[1]
|
|
120
|
+
promises.push(updateBackgroundImageWithBase64Image(nodePtr, imageUrl))
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// 如果有 img 和 image 标签,尝试将 src 和 href 替换为 base64 图片
|
|
124
|
+
if (nodePtr instanceof HTMLImageElement) {
|
|
125
|
+
promises.push(updateImageSrcOrHrefWithBase64Image(nodePtr, 'src'))
|
|
126
|
+
} else if (nodePtr instanceof SVGImageElement) {
|
|
127
|
+
promises.push(updateImageSrcOrHrefWithBase64Image(nodePtr, 'href'))
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
await Promise.all(promises)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 重新复制canvas 用于在不裁剪原canvas的基础上通过拉伸方式达到自定义宽高目的
|
|
135
|
+
* @param originCanvas HTMLCanvasElement
|
|
136
|
+
* @param targetWidth number
|
|
137
|
+
* @param targetHeight number
|
|
138
|
+
*/
|
|
139
|
+
export function copyCanvas(
|
|
140
|
+
originCanvas: HTMLCanvasElement,
|
|
141
|
+
targetWidth: number,
|
|
142
|
+
targetHeight: number,
|
|
143
|
+
): HTMLCanvasElement {
|
|
144
|
+
const newCanvas = document.createElement('canvas')
|
|
145
|
+
newCanvas.width = targetWidth
|
|
146
|
+
newCanvas.height = targetHeight
|
|
147
|
+
const newCtx = newCanvas.getContext('2d')
|
|
148
|
+
if (newCtx) {
|
|
149
|
+
// 注意: 自定义宽高时,可能会拉伸图形,这时候padding也会被拉伸导致不准确
|
|
150
|
+
newCtx.drawImage(
|
|
151
|
+
originCanvas,
|
|
152
|
+
0,
|
|
153
|
+
0,
|
|
154
|
+
originCanvas.width,
|
|
155
|
+
originCanvas.height,
|
|
156
|
+
0,
|
|
157
|
+
0,
|
|
158
|
+
targetWidth,
|
|
159
|
+
targetHeight,
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
return newCanvas
|
|
163
|
+
}
|