@leafer-in/export 1.7.0 → 1.8.0
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/dist/export.cjs +108 -100
- package/dist/export.esm.js +109 -101
- package/dist/export.esm.min.js +1 -1
- package/dist/export.esm.min.js.map +1 -1
- package/dist/export.js +108 -100
- package/dist/export.min.cjs +1 -1
- package/dist/export.min.cjs.map +1 -1
- package/dist/export.min.js +1 -1
- package/dist/export.min.js.map +1 -1
- package/package.json +4 -4
- package/src/export.ts +107 -99
- package/src/trim.ts +5 -2
package/src/export.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IExportModule, IExportOptions, IExportResult, IExportResultFunction, IUI, IExportFileType, IFunction, IRenderOptions, IBoundsData, IBounds, ILocationType, ILeaf } from '@leafer-ui/interface'
|
|
2
|
-
import { Creator, Matrix, TaskProcessor, FileHelper, Bounds, Platform, MathHelper, Resource } from '@leafer-ui/draw'
|
|
2
|
+
import { Creator, Matrix, TaskProcessor, FileHelper, Bounds, Platform, MathHelper, Resource, Export } from '@leafer-ui/draw'
|
|
3
3
|
|
|
4
4
|
import { getTrimBounds } from './trim'
|
|
5
5
|
|
|
@@ -8,146 +8,154 @@ export const ExportModule: IExportModule = {
|
|
|
8
8
|
|
|
9
9
|
syncExport(leaf: IUI, filename: string, options?: IExportOptions | number | boolean): IExportResult {
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Export.running = true
|
|
12
12
|
|
|
13
13
|
let result: IExportResult
|
|
14
|
-
const fileType = FileHelper.fileType(filename)
|
|
15
|
-
const isDownload = filename.includes('.')
|
|
16
|
-
options = FileHelper.getExportOptions(options)
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
const { download } = Platform.origin
|
|
15
|
+
try {
|
|
20
16
|
|
|
17
|
+
const fileType = FileHelper.fileType(filename)
|
|
18
|
+
const isDownload = filename.includes('.')
|
|
19
|
+
options = FileHelper.getExportOptions(options)
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
const { toURL } = Platform
|
|
22
|
+
const { download } = Platform.origin
|
|
23
23
|
|
|
24
|
-
isDownload && download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename)
|
|
25
|
-
result = { data: isDownload ? true : leaf.toJSON(options.json) }
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
if (fileType === 'json') {
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
isDownload && download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename)
|
|
28
|
+
result = { data: isDownload ? true : leaf.toJSON(options.json) }
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
} else if (fileType === 'svg') {
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const { slice, clip, trim, screenshot, padding, onCanvas } = options
|
|
37
|
-
const smooth = options.smooth === undefined ? (leafer ? leafer.config.smooth : true) : options.smooth
|
|
38
|
-
const contextSettings = options.contextSettings || (leafer ? leafer.config.contextSettings : undefined)
|
|
32
|
+
isDownload && download(toURL(leaf.toSVG(), 'svg'), filename)
|
|
33
|
+
result = { data: isDownload ? true : leaf.toSVG() }
|
|
39
34
|
|
|
40
|
-
const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill // leafer use
|
|
41
|
-
const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix()
|
|
42
|
-
|
|
43
|
-
// 获取元素大小
|
|
44
|
-
if (screenshot) {
|
|
45
|
-
renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot
|
|
46
35
|
} else {
|
|
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
|
-
|
|
36
|
+
|
|
37
|
+
let renderBounds: IBoundsData, trimBounds: IBounds, scaleX = 1, scaleY = 1
|
|
38
|
+
const { worldTransform, isLeafer, leafer, isFrame } = leaf
|
|
39
|
+
const { slice, clip, trim, screenshot, padding, onCanvas } = options
|
|
40
|
+
const smooth = options.smooth === undefined ? (leafer ? leafer.config.smooth : true) : options.smooth
|
|
41
|
+
const contextSettings = options.contextSettings || (leafer ? leafer.config.contextSettings : undefined)
|
|
42
|
+
|
|
43
|
+
const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill // leafer use
|
|
44
|
+
const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix()
|
|
45
|
+
|
|
46
|
+
// 获取元素大小
|
|
47
|
+
if (screenshot) {
|
|
48
|
+
renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot
|
|
49
|
+
} else {
|
|
50
|
+
let relative: ILocationType | ILeaf = options.relative || (isLeafer ? 'inner' : 'local')
|
|
51
|
+
|
|
52
|
+
scaleX = worldTransform.scaleX
|
|
53
|
+
scaleY = worldTransform.scaleY
|
|
54
|
+
|
|
55
|
+
switch (relative) {
|
|
56
|
+
case 'inner':
|
|
57
|
+
matrix.set(worldTransform)
|
|
58
|
+
break
|
|
59
|
+
case 'local':
|
|
60
|
+
matrix.set(worldTransform).divide(leaf.localTransform)
|
|
61
|
+
scaleX /= leaf.scaleX
|
|
62
|
+
scaleY /= leaf.scaleY
|
|
63
|
+
break
|
|
64
|
+
case 'world':
|
|
65
|
+
scaleX = 1
|
|
66
|
+
scaleY = 1
|
|
67
|
+
break
|
|
68
|
+
case 'page':
|
|
69
|
+
relative = leafer || leaf
|
|
70
|
+
default:
|
|
71
|
+
matrix.set(worldTransform).divide(leaf.getTransform(relative))
|
|
72
|
+
const l = relative.worldTransform
|
|
73
|
+
scaleX /= scaleX / l.scaleX
|
|
74
|
+
scaleY /= scaleY / l.scaleY
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
renderBounds = leaf.getBounds('render', relative)
|
|
72
78
|
}
|
|
73
79
|
|
|
74
|
-
renderBounds = leaf.getBounds('render', relative)
|
|
75
|
-
}
|
|
76
80
|
|
|
81
|
+
// 缩放元素
|
|
82
|
+
const scaleData = { scaleX: 1, scaleY: 1 }
|
|
83
|
+
MathHelper.getScaleData(options.scale, options.size, renderBounds, scaleData)
|
|
77
84
|
|
|
78
|
-
|
|
79
|
-
const scaleData = { scaleX: 1, scaleY: 1 }
|
|
80
|
-
MathHelper.getScaleData(options.scale, options.size, renderBounds, scaleData)
|
|
85
|
+
let pixelRatio = options.pixelRatio || 1
|
|
81
86
|
|
|
82
|
-
let pixelRatio = options.pixelRatio || 1
|
|
83
87
|
|
|
88
|
+
// 导出元素
|
|
89
|
+
let { x, y, width, height } = new Bounds(renderBounds).scale(scaleData.scaleX, scaleData.scaleY)
|
|
90
|
+
if (clip) x += clip.x, y += clip.y, width = clip.width, height = clip.height
|
|
84
91
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (clip) x += clip.x, y += clip.y, width = clip.width, height = clip.height
|
|
92
|
+
const renderOptions: IRenderOptions = { exporting: true, matrix: matrix.scale(1 / scaleData.scaleX, 1 / scaleData.scaleY).invert().translate(-x, -y).withScale(1 / scaleX * scaleData.scaleX, 1 / scaleY * scaleData.scaleY) }
|
|
93
|
+
let canvas = Creator.canvas({ width: Math.floor(width), height: Math.floor(height), pixelRatio, smooth, contextSettings })
|
|
88
94
|
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
let sliceLeaf: IUI
|
|
96
|
+
if (slice) {
|
|
97
|
+
sliceLeaf = leaf
|
|
98
|
+
sliceLeaf.__worldOpacity = 0 // hide slice
|
|
91
99
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
sliceLeaf.__worldOpacity = 0 // hide slice
|
|
100
|
+
leaf = leafer || leaf // render all in bounds
|
|
101
|
+
renderOptions.bounds = canvas.bounds
|
|
102
|
+
}
|
|
96
103
|
|
|
97
|
-
leaf = leafer || leaf // render all in bounds
|
|
98
|
-
renderOptions.bounds = canvas.bounds
|
|
99
|
-
}
|
|
100
104
|
|
|
105
|
+
canvas.save()
|
|
101
106
|
|
|
102
|
-
|
|
107
|
+
if (isFrame && fill !== undefined) {
|
|
108
|
+
const oldFill = leaf.get('fill')
|
|
109
|
+
leaf.fill = ''
|
|
110
|
+
leaf.__render(canvas, renderOptions)
|
|
111
|
+
leaf.fill = oldFill as string
|
|
112
|
+
} else {
|
|
113
|
+
leaf.__render(canvas, renderOptions)
|
|
114
|
+
}
|
|
103
115
|
|
|
104
|
-
|
|
105
|
-
const oldFill = leaf.get('fill')
|
|
106
|
-
leaf.fill = ''
|
|
107
|
-
leaf.__render(canvas, renderOptions)
|
|
108
|
-
leaf.fill = oldFill as string
|
|
109
|
-
} else {
|
|
110
|
-
leaf.__render(canvas, renderOptions)
|
|
111
|
-
}
|
|
116
|
+
canvas.restore()
|
|
112
117
|
|
|
113
|
-
canvas.restore()
|
|
114
118
|
|
|
119
|
+
if (sliceLeaf) sliceLeaf.__updateWorldOpacity() // show slice
|
|
115
120
|
|
|
116
|
-
|
|
121
|
+
if (trim) {
|
|
122
|
+
trimBounds = getTrimBounds(canvas)
|
|
123
|
+
const old = canvas, { width, height } = trimBounds
|
|
124
|
+
const config = { x: 0, y: 0, width, height, pixelRatio }
|
|
117
125
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const config = { x: 0, y: 0, width, height, pixelRatio }
|
|
126
|
+
canvas = Creator.canvas(config)
|
|
127
|
+
canvas.copyWorld(old, trimBounds, config)
|
|
128
|
+
}
|
|
122
129
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
if (padding) {
|
|
131
|
+
const [top, right, bottom, left] = MathHelper.fourNumber(padding)
|
|
132
|
+
const old = canvas, { width, height } = old
|
|
126
133
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
canvas = Creator.canvas({ width: width + left + right, height: height + top + bottom, pixelRatio })
|
|
135
|
+
canvas.copyWorld(old, old.bounds, { x: left, y: top, width, height })
|
|
136
|
+
}
|
|
130
137
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
if (needFill) canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over')
|
|
139
|
+
if (onCanvas) onCanvas(canvas)
|
|
140
|
+
|
|
141
|
+
const data = filename === 'canvas' ? canvas : canvas.export(filename, options)
|
|
142
|
+
result = { data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds }
|
|
134
143
|
|
|
135
|
-
|
|
136
|
-
if (onCanvas) onCanvas(canvas)
|
|
144
|
+
}
|
|
137
145
|
|
|
138
|
-
|
|
139
|
-
result = { data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds }
|
|
146
|
+
} catch (error) {
|
|
140
147
|
|
|
148
|
+
result = { data: '', error }
|
|
141
149
|
}
|
|
142
150
|
|
|
143
|
-
|
|
151
|
+
Export.running = false
|
|
144
152
|
|
|
145
153
|
return result
|
|
146
154
|
},
|
|
147
155
|
|
|
148
156
|
export(leaf: IUI, filename: IExportFileType | string, options?: IExportOptions | number | boolean): Promise<IExportResult> {
|
|
149
157
|
|
|
150
|
-
|
|
158
|
+
Export.running = true
|
|
151
159
|
|
|
152
160
|
return addTask((success: IExportResultFunction) =>
|
|
153
161
|
|
|
@@ -155,7 +163,7 @@ export const ExportModule: IExportModule = {
|
|
|
155
163
|
|
|
156
164
|
const getResult = async () => {
|
|
157
165
|
if (!Resource.isComplete) return Platform.requestRender(getResult)
|
|
158
|
-
const result: IExportResult =
|
|
166
|
+
const result: IExportResult = Export.syncExport(leaf, filename, options)
|
|
159
167
|
if (result.data instanceof Promise) result.data = await result.data
|
|
160
168
|
success(result)
|
|
161
169
|
resolve()
|
package/src/trim.ts
CHANGED
|
@@ -19,6 +19,9 @@ export function getTrimBounds(canvas: ILeaferCanvas): IBounds {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const bounds = new Bounds()
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
if (pointBounds) {
|
|
23
|
+
toBounds(pointBounds, bounds)
|
|
24
|
+
bounds.scale(1 / canvas.pixelRatio).ceil()
|
|
25
|
+
}
|
|
26
|
+
return bounds
|
|
24
27
|
}
|