@printine/designer 0.1.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.
Files changed (199) hide show
  1. package/README.md +146 -0
  2. package/dist/DesignerRuntimeContext.d.ts +3 -0
  3. package/dist/PrintineDesigner.d.ts +9 -0
  4. package/dist/api/client.d.ts +8 -0
  5. package/dist/api/client.js +82 -0
  6. package/dist/api/common-endpoints.d.ts +12 -0
  7. package/dist/api/design-endpoints.d.ts +18 -0
  8. package/dist/api/endpoints.d.ts +33 -0
  9. package/dist/api/endpoints.js +46 -0
  10. package/dist/api/files-endpoints.d.ts +1 -0
  11. package/dist/assets/icons/aspect_ratio.d.ts +3 -0
  12. package/dist/assets/icons/delete.d.ts +3 -0
  13. package/dist/assets/icons/fit_screen.d.ts +3 -0
  14. package/dist/assets/icons/index.d.ts +11 -0
  15. package/dist/assets/icons/loading_1.d.ts +3 -0
  16. package/dist/assets/icons/loading_2.d.ts +3 -0
  17. package/dist/assets/icons/loading_3.d.ts +3 -0
  18. package/dist/assets/icons/pan.d.ts +3 -0
  19. package/dist/assets/icons/setting.d.ts +3 -0
  20. package/dist/assets/icons/text_color.d.ts +3 -0
  21. package/dist/assets/icons/text_h.d.ts +3 -0
  22. package/dist/assets/icons/text_v.d.ts +3 -0
  23. package/dist/bundled-assets.d.ts +4 -0
  24. package/dist/components/add-design.d.ts +8 -0
  25. package/dist/components/assets-dialog.d.ts +21 -0
  26. package/dist/components/canvas-context-menu.d.ts +6 -0
  27. package/dist/components/color-picker/index.d.ts +10 -0
  28. package/dist/components/context.d.ts +24 -0
  29. package/dist/components/design.d.ts +9 -0
  30. package/dist/components/fonts.d.ts +26 -0
  31. package/dist/components/image-crop.d.ts +4 -0
  32. package/dist/components/image-edit.d.ts +1 -0
  33. package/dist/components/layout/aside.d.ts +3 -0
  34. package/dist/components/layout/bottom-nav/element-menu-sheet.d.ts +11 -0
  35. package/dist/components/layout/bottom-nav/element-sheet.d.ts +11 -0
  36. package/dist/components/layout/bottom-nav/index.d.ts +1 -0
  37. package/dist/components/layout/header.d.ts +5 -0
  38. package/dist/components/loading.d.ts +3 -0
  39. package/dist/components/menus/ai.d.ts +5 -0
  40. package/dist/components/menus/background.d.ts +6 -0
  41. package/dist/components/menus/clipart.d.ts +6 -0
  42. package/dist/components/menus/files.d.ts +7 -0
  43. package/dist/components/menus/image.d.ts +8 -0
  44. package/dist/components/menus/index.d.ts +13 -0
  45. package/dist/components/menus/layer.d.ts +5 -0
  46. package/dist/components/menus/product.d.ts +3 -0
  47. package/dist/components/menus/sca.d.ts +5 -0
  48. package/dist/components/menus/shapes.d.ts +6 -0
  49. package/dist/components/menus/templates.d.ts +6 -0
  50. package/dist/components/menus/text-effects.d.ts +5 -0
  51. package/dist/components/menus/text.d.ts +6 -0
  52. package/dist/components/placement-tab.d.ts +7 -0
  53. package/dist/components/preview/3d.d.ts +7 -0
  54. package/dist/components/preview/graphic.d.ts +7 -0
  55. package/dist/components/preview/index.d.ts +18 -0
  56. package/dist/components/preview/open.d.ts +7 -0
  57. package/dist/components/preview/real-time/3d.d.ts +12 -0
  58. package/dist/components/preview/real-time/graphic.d.ts +18 -0
  59. package/dist/components/preview/real-time/index.d.ts +11 -0
  60. package/dist/components/scale-tools.d.ts +7 -0
  61. package/dist/components/semi-deisgn-config.d.ts +13 -0
  62. package/dist/components/semi-design-link.d.ts +9 -0
  63. package/dist/components/store.d.ts +1 -0
  64. package/dist/components/toolbar.d.ts +2 -0
  65. package/dist/config-D2qm60gf.js +16 -0
  66. package/dist/contracts/api-design.d.ts +176 -0
  67. package/dist/contracts/design.d.ts +86 -0
  68. package/dist/design-7zRpRtv9.js +20331 -0
  69. package/dist/engine/canvas-designer.d.ts +101 -0
  70. package/dist/engine/canvas-designer.js +313 -0
  71. package/dist/engine/constants.d.ts +27 -0
  72. package/dist/engine/constants.js +148 -0
  73. package/dist/engine/editor.d.ts +186 -0
  74. package/dist/engine/editor.js +734 -0
  75. package/dist/engine/events.d.ts +34 -0
  76. package/dist/engine/events.js +7 -0
  77. package/dist/engine/extensions/curved-text.d.ts +59 -0
  78. package/dist/engine/fabric.d.ts +4 -0
  79. package/dist/engine/fabric.js +187 -0
  80. package/dist/engine/history.d.ts +27 -0
  81. package/dist/engine/history.js +56 -0
  82. package/dist/engine/managers/event.d.ts +101 -0
  83. package/dist/engine/managers/event.js +410 -0
  84. package/dist/engine/managers/resize.d.ts +24 -0
  85. package/dist/engine/managers/resize.js +63 -0
  86. package/dist/engine/managers/snapline.d.ts +70 -0
  87. package/dist/engine/managers/snapline.js +124 -0
  88. package/dist/engine/managers/workspace.d.ts +26 -0
  89. package/dist/engine/managers/workspace.js +53 -0
  90. package/dist/engine/processors/image.d.ts +88 -0
  91. package/dist/engine/processors/image.js +473 -0
  92. package/dist/engine/processors/template.d.ts +45 -0
  93. package/dist/engine/processors/template.js +314 -0
  94. package/dist/engine/processors/text.d.ts +74 -0
  95. package/dist/engine/processors/text.js +215 -0
  96. package/dist/engine/semi-export-editor.d.ts +199 -0
  97. package/dist/engine/types.d.ts +28 -0
  98. package/dist/engine/utils/common.d.ts +25 -0
  99. package/dist/engine/utils/common.js +68 -0
  100. package/dist/engine/utils/dialog.d.ts +25 -0
  101. package/dist/engine/utils/font.d.ts +5 -0
  102. package/dist/engine/utils/font.js +39 -0
  103. package/dist/engine/utils/image.d.ts +8 -0
  104. package/dist/engine/utils/image.js +50 -0
  105. package/dist/engine/utils/loading.d.ts +17 -0
  106. package/dist/engine/utils/loading.js +71 -0
  107. package/dist/engine/utils/measure.d.ts +6 -0
  108. package/dist/engine/utils/measure.js +6 -0
  109. package/dist/engine/utils/mockup.d.ts +59 -0
  110. package/dist/engine/utils/setting.d.ts +4 -0
  111. package/dist/engine/utils/setting.js +73 -0
  112. package/dist/fabric-types.d.ts +59 -0
  113. package/dist/full-designer.js +14 -0
  114. package/dist/hooks/pagination.d.ts +19 -0
  115. package/dist/hooks/use-adobe-express.d.ts +50 -0
  116. package/dist/hooks/use-before-unload.d.ts +1 -0
  117. package/dist/hooks/use-image-drop.d.ts +18 -0
  118. package/dist/hooks/use-oss-upload.d.ts +34 -0
  119. package/dist/hooks/use-screen.d.ts +1 -0
  120. package/dist/i18n/index.d.ts +12 -0
  121. package/dist/images/design/asset_empty.png +0 -0
  122. package/dist/images/design/design/background.svg +3 -0
  123. package/dist/images/design/design/color-picker.svg +15 -0
  124. package/dist/images/design/design/computer.svg +1 -0
  125. package/dist/images/design/design/copy.svg +1 -0
  126. package/dist/images/design/design/image.svg +10 -0
  127. package/dist/images/design/design/line.svg +1 -0
  128. package/dist/images/design/design/text.svg +1 -0
  129. package/dist/images/design/design/title.svg +1 -0
  130. package/dist/images/design/empty.png +0 -0
  131. package/dist/images/design/layer_empty.png +0 -0
  132. package/dist/images/design/menu/ai.svg +1 -0
  133. package/dist/images/design/menu/back.svg +4 -0
  134. package/dist/images/design/menu/background.svg +6 -0
  135. package/dist/images/design/menu/clipart.svg +6 -0
  136. package/dist/images/design/menu/file.svg +4 -0
  137. package/dist/images/design/menu/fill.svg +1 -0
  138. package/dist/images/design/menu/image.svg +7 -0
  139. package/dist/images/design/menu/layer.svg +6 -0
  140. package/dist/images/design/menu/product.svg +3 -0
  141. package/dist/images/design/menu/sca.svg +5 -0
  142. package/dist/images/design/menu/shapes.svg +5 -0
  143. package/dist/images/design/menu/templates.svg +6 -0
  144. package/dist/images/design/menu/text.svg +6 -0
  145. package/dist/images/design/menu/uploads.svg +7 -0
  146. package/dist/images/design/spinner.svg +3 -0
  147. package/dist/images/design/spinners.svg +17 -0
  148. package/dist/images/design/transparent_pattern.svg +5 -0
  149. package/dist/index.d.ts +39 -0
  150. package/dist/index.js +127 -0
  151. package/dist/lib/analytics.d.ts +17 -0
  152. package/dist/lib/cn.d.ts +3 -0
  153. package/dist/lib/common.d.ts +16 -0
  154. package/dist/lib/config.d.ts +14 -0
  155. package/dist/lib/navigation.d.ts +2 -0
  156. package/dist/renderer/ThreeDPreview.d.ts +14 -0
  157. package/dist/renderer/sticker.js +1731 -0
  158. package/dist/renderer/three-d-preview.js +32 -0
  159. package/dist/state/designer-store.d.ts +43 -0
  160. package/dist/state/designer-store.js +85 -0
  161. package/dist/style.css +1 -0
  162. package/dist/types.d.ts +184 -0
  163. package/dist/ui/accordion.d.ts +7 -0
  164. package/dist/ui/button-group.d.ts +11 -0
  165. package/dist/ui/button.d.ts +10 -0
  166. package/dist/ui/checkbox.d.ts +4 -0
  167. package/dist/ui/command.d.ts +18 -0
  168. package/dist/ui/confirm-dialog.d.ts +15 -0
  169. package/dist/ui/context-menu.d.ts +25 -0
  170. package/dist/ui/dialog.d.ts +15 -0
  171. package/dist/ui/drawer.d.ts +15 -0
  172. package/dist/ui/editable-combobox.d.ts +10 -0
  173. package/dist/ui/hint.d.ts +8 -0
  174. package/dist/ui/image.d.ts +24 -0
  175. package/dist/ui/input-group.d.ts +16 -0
  176. package/dist/ui/input-with-addon.d.ts +17 -0
  177. package/dist/ui/input.d.ts +3 -0
  178. package/dist/ui/label.d.ts +4 -0
  179. package/dist/ui/loading-button.d.ts +15 -0
  180. package/dist/ui/popover.d.ts +9 -0
  181. package/dist/ui/scroll-area.d.ts +5 -0
  182. package/dist/ui/select.d.ts +22 -0
  183. package/dist/ui/separator.d.ts +4 -0
  184. package/dist/ui/shared-loading-button.d.ts +20 -0
  185. package/dist/ui/simple-dialog.d.ts +19 -0
  186. package/dist/ui/simple-popover.d.ts +13 -0
  187. package/dist/ui/simple-select.d.ts +20 -0
  188. package/dist/ui/skeleton.d.ts +2 -0
  189. package/dist/ui/slider.d.ts +4 -0
  190. package/dist/ui/spinner-box.d.ts +12 -0
  191. package/dist/ui/spinner.d.ts +2 -0
  192. package/dist/ui/switch.d.ts +6 -0
  193. package/dist/ui/tab/index.d.ts +15 -0
  194. package/dist/ui/textarea.d.ts +3 -0
  195. package/dist/ui/tooltip.d.ts +7 -0
  196. package/dist/workers/image-resize.worker.d.ts +1 -0
  197. package/dist/workers/mockup.worker.d.ts +5 -0
  198. package/dist/workers/render.worker.d.ts +1 -0
  199. package/package.json +201 -0
@@ -0,0 +1,734 @@
1
+ import "./fabric.js";
2
+ import { v4 as R } from "uuid";
3
+ import { cloneObject as k, urlToDataURL as Y } from "./utils/common.js";
4
+ import { loadOverlaySvgImage as X, loadImage as U } from "./utils/image.js";
5
+ import { Loading as L } from "./utils/loading.js";
6
+ import { HistoryManager as T } from "./history.js";
7
+ import { LAYER_BLACK_LIST as A } from "./constants.js";
8
+ import { designerEventBus as x } from "./events.js";
9
+ import { ImageProcessor as B } from "./processors/image.js";
10
+ import { TemplateProcessor as E } from "./processors/template.js";
11
+ import { TextProcessor as W } from "./processors/text.js";
12
+ import { ResizeManager as _ } from "./managers/resize.js";
13
+ import { WorkspaceManager as D } from "./managers/workspace.js";
14
+ import { fabric as d } from "fabric";
15
+ class se {
16
+ constructor(t, s, e, n = {}) {
17
+ this.imageCache = /* @__PURE__ */ new Map(), this.overlayCache = /* @__PURE__ */ new Map(), this.deleteObject = (r) => {
18
+ if (r) {
19
+ const a = this.canvas._objects.find((c) => c.id === r);
20
+ a && (this.canvas.remove(a), this.revokeImgBlobLink(a));
21
+ } else {
22
+ const a = this.canvas.getActiveObjects();
23
+ a.length > 0 && (a.forEach((c) => {
24
+ this.canvas.remove(c), this.revokeImgBlobLink(c);
25
+ }), this.canvas.discardActiveObject());
26
+ }
27
+ this.canvas.requestRenderAll();
28
+ };
29
+ const i = typeof n == "number" ? { overlayScale: n } : n;
30
+ this.canvas = new d.Canvas(t, {
31
+ enableRetinaScaling: !0,
32
+ width: s.width,
33
+ height: s.height,
34
+ preserveObjectStacking: !0,
35
+ stopContextMenu: !1,
36
+ centeredRotation: !0,
37
+ hoverCursor: "grab",
38
+ moveCursor: "grabbing",
39
+ allowTouchScrolling: !0,
40
+ selection: !0,
41
+ interactive: !0,
42
+ controlsAboveOverlay: !0,
43
+ fireRightClick: !0
44
+ // 允许识别右键点击
45
+ }), this.overlayScale = i.overlayScale ?? 0.85, this.loadingOptions = i.loading ?? {}, this.events = i.events ?? x, this.imageProcessor = new B(this), this.templateProcessor = new E(this), this.textProcessor = new W(this), this.resizeManager = new _(this, e), this.workspaceManager = new D(this, i.workspace), this.setupImageCacheInterceptor();
46
+ }
47
+ /** Builds a loading indicator that already carries the package asset configuration. */
48
+ createLoading(t) {
49
+ return new L(this.canvas, t, this.loadingOptions);
50
+ }
51
+ /**
52
+ * 统一拦截图片创建:优先从会话缓存复用已加载的 HTMLImageElement,避免视图切换或导出时重复请求远程图片
53
+ */
54
+ setupImageCacheInterceptor() {
55
+ const t = this.imageCache, s = d.Image.fromURL, e = d.Image.fromObject;
56
+ if (d.Image._printineCacheHooked) return;
57
+ d.Image._printineCacheHooked = !0;
58
+ const n = (r) => {
59
+ if (!r) return null;
60
+ const a = t.get(r);
61
+ return a?.element && a.element.complete ? (t.set(r, { ...a, lastUsed: Date.now() }), a.element) : null;
62
+ };
63
+ d.Image.fromURL = function(r, a, c) {
64
+ const o = { ...c, crossOrigin: "anonymous" }, l = n(r);
65
+ if (l) {
66
+ const u = new d.Image(l, o);
67
+ u.originSrc = r, a && a(u);
68
+ return;
69
+ }
70
+ return s.call(
71
+ this,
72
+ r,
73
+ (u) => {
74
+ u && (u.originSrc = r), a && a(u);
75
+ },
76
+ o
77
+ );
78
+ };
79
+ const i = (r) => !!r && typeof r == "object" && typeof r.set == "function" && typeof r.shouldCache == "function";
80
+ d.Image.fromObject = function(r, a) {
81
+ const c = r?.originSrc || r?.src, o = n(c);
82
+ if (o) {
83
+ const { clipPath: l, ...u } = r ?? {}, v = new d.Image(o, { ...u });
84
+ if (v.originSrc = c, !l || i(l)) {
85
+ l && (v.clipPath = l), a?.(v);
86
+ return;
87
+ }
88
+ d.util.enlivenObjects(
89
+ [l],
90
+ (y) => {
91
+ const [P] = y || [];
92
+ P && (v.clipPath = P), a?.(v);
93
+ },
94
+ ""
95
+ );
96
+ return;
97
+ }
98
+ return e.call(this, { ...r, crossOrigin: "anonymous" }, a);
99
+ };
100
+ }
101
+ /**
102
+ * 渲染 overlayImage(SVG)
103
+ * @param mockup 模板信息
104
+ * @param changeView 是否切换视图,如果为 true,则需要重新设置画布和背景图
105
+ */
106
+ async renderOverlayImage(t, s = !1) {
107
+ const { image: e, clipPath: n } = await this.getOverlayImage(t.image), i = Math.min(this.canvas.width, this.canvas.height) * this.overlayScale, r = i / e.width, a = i / e.height, c = Math.min(r, a);
108
+ return e.set({
109
+ scaleX: c,
110
+ scaleY: c,
111
+ left: (this.canvas.width - e.width * c) / 2,
112
+ top: (this.canvas.height - e.height * c) / 2,
113
+ selectable: !1
114
+ }), n && n.set({
115
+ scaleX: c,
116
+ scaleY: c,
117
+ left: (this.canvas.width - n.width * c) / 2,
118
+ top: (this.canvas.height - n.height * c) / 2,
119
+ absolutePositioned: !0,
120
+ selectable: !1,
121
+ evented: !1
122
+ }), s && this.canvas.setViewportTransform([1, 0, 0, 1, 0, 0]), new Promise((o) => {
123
+ this.canvas.setOverlayImage(e, async () => {
124
+ this.workspaceManager.setClipPath(n ?? e, {
125
+ width: e.width,
126
+ height: e.height
127
+ }), this.setupOverlayBorders(e, n), this.canvas.renderAll(), o();
128
+ });
129
+ });
130
+ }
131
+ /**
132
+ * 获取 overlay 图:优先使用会话级缓存,避免重复网络请求
133
+ * 会返回深拷贝,确保不同视图间互不影响
134
+ */
135
+ async getOverlayImage(t) {
136
+ const s = this.overlayCache.get(t);
137
+ if (s) {
138
+ const r = await k(s.image), a = s.clipPath ? await k(s.clipPath) : void 0;
139
+ return { image: r, clipPath: a };
140
+ }
141
+ const e = await X(t);
142
+ this.overlayCache.set(t, e);
143
+ const n = await k(e.image), i = e.clipPath ? await k(e.clipPath) : void 0;
144
+ return { image: n, clipPath: i };
145
+ }
146
+ /**
147
+ * 绘制可设计区域边框,优先使用 clipPath 的真实形状
148
+ */
149
+ setupOverlayBorders(t, s) {
150
+ this.overlayBorderHandler && this.canvas.off("after:render", this.overlayBorderHandler);
151
+ const e = s ?? t;
152
+ this.overlayBorderHandler = () => {
153
+ const n = this.canvas.getContext(), i = this.canvas.viewportTransform || [1, 0, 0, 1, 0, 0];
154
+ n.save(), n.transform(i[0], i[1], i[2], i[3], i[4], i[5]);
155
+ const r = {
156
+ stroke: e.stroke,
157
+ strokeWidth: e.strokeWidth,
158
+ strokeDashArray: e.strokeDashArray,
159
+ fill: e.fill,
160
+ strokeUniform: e.strokeUniform
161
+ };
162
+ e.set({
163
+ stroke: "#C3C3CC",
164
+ strokeWidth: 1,
165
+ strokeDashArray: [],
166
+ fill: "transparent",
167
+ strokeUniform: !0,
168
+ objectCaching: !1
169
+ }), e.render(n);
170
+ const a = 6, c = (e.getScaledWidth() + a * 2) / e.getScaledWidth(), o = (e.getScaledHeight() + a * 2) / e.getScaledHeight(), l = e.left ?? 0, u = e.top ?? 0, v = e.scaleX ?? 1, y = e.scaleY ?? 1;
171
+ e.set({
172
+ strokeDashArray: [4, 4],
173
+ stroke: "#C3C3CC",
174
+ strokeWidth: 1,
175
+ strokeUniform: !0,
176
+ scaleX: v * c,
177
+ scaleY: y * o,
178
+ left: l - a,
179
+ top: u - a
180
+ }), e.render(n), e.set({
181
+ stroke: r.stroke,
182
+ strokeWidth: r.strokeWidth,
183
+ strokeDashArray: r.strokeDashArray,
184
+ fill: r.fill,
185
+ strokeUniform: r.strokeUniform,
186
+ scaleX: v,
187
+ scaleY: y,
188
+ left: l,
189
+ top: u
190
+ }), n.restore();
191
+ }, this.canvas.on("after:render", this.overlayBorderHandler);
192
+ }
193
+ /**
194
+ * 设置背景遮罩
195
+ */
196
+ async setBackgroundMask(t) {
197
+ const s = document.querySelector(".lower-canvas");
198
+ if (s && !t)
199
+ return s.style.backgroundImage = "", Promise.resolve();
200
+ const e = await U(t);
201
+ if (e == null) return Promise.resolve();
202
+ e.set({
203
+ scaleX: this.canvas.width / e.width,
204
+ scaleY: this.canvas.height / e.height
205
+ });
206
+ const n = e.toDataURL({ format: "png" });
207
+ s && (s.style.backgroundImage = `url(${n})`, s.style.backgroundSize = "100% 100%");
208
+ }
209
+ /**
210
+ * 设置背景颜色、透明图案
211
+ */
212
+ async setBackground(t) {
213
+ t ? await this.workspaceManager.setFillColor(t) : await this.workspaceManager.setTransparentPattern(), this.canvas.requestRenderAll();
214
+ }
215
+ /**
216
+ * 获取当前选中的对象
217
+ */
218
+ get activeObject() {
219
+ return this.canvas.getActiveObject();
220
+ }
221
+ /**
222
+ * 获取对象经过画布转换后的实际尺寸
223
+ */
224
+ getObjectActualSize(t) {
225
+ const { left: s = 0, top: e = 0, width: n = 0, height: i = 0 } = t.getBoundingRect(), r = t.getCenterPoint(), a = this.canvas.viewportTransform;
226
+ return {
227
+ left: s * a[0] + a[4],
228
+ top: e * a[3] + a[5],
229
+ width: n * a[0],
230
+ height: i * a[3],
231
+ centerX: r.x * a[0] + a[4],
232
+ centerY: r.y * a[3] + a[5]
233
+ };
234
+ }
235
+ /**
236
+ * 添加对象
237
+ */
238
+ addObject(t, s = !0) {
239
+ t.set({
240
+ id: R()
241
+ }), this.canvas.add(t), s && this.canvas.setActiveObject(t);
242
+ }
243
+ /**
244
+ * 恢复对象
245
+ */
246
+ async restoreObject(t) {
247
+ return new Promise((s) => {
248
+ d.util.enlivenObjects([t], (e) => s(e), "");
249
+ });
250
+ }
251
+ /**
252
+ * 清理图片 blob URL(只清理不在缓存中的临时 blob)
253
+ */
254
+ revokeImgBlobLink(t) {
255
+ if (t.type === "image" && t.getSrc) {
256
+ const s = t, e = s.getSrc(), n = s.originSrc || e;
257
+ if (e && e.startsWith("blob:")) {
258
+ const i = this.imageCache.get(n);
259
+ if (!i || i.blobUrl !== e)
260
+ try {
261
+ URL.revokeObjectURL(e);
262
+ } catch {
263
+ }
264
+ }
265
+ }
266
+ }
267
+ /**
268
+ * 修改对象的属性
269
+ */
270
+ updateObject(t, s) {
271
+ const e = this.canvas._objects.find((n) => n.id === t);
272
+ if (e) {
273
+ if (Object.prototype.hasOwnProperty.call(s, "angle"))
274
+ e.rotate(s.angle);
275
+ else if (Object.prototype.hasOwnProperty.call(s, "align")) {
276
+ const { left: n, right: i, top: r, bottom: a, center: c } = this.workspaceManager.dimension, o = e.getBoundingRect(!0, !0);
277
+ switch (s.align) {
278
+ case "top":
279
+ e.set({
280
+ top: e.top + (r - o.top)
281
+ });
282
+ break;
283
+ case "left":
284
+ e.set({
285
+ left: e.left + (n - o.left)
286
+ });
287
+ break;
288
+ case "horizontal-center":
289
+ e.set({
290
+ left: e.left + (c.x - (o.left + o.width / 2))
291
+ });
292
+ break;
293
+ case "right":
294
+ e.set({
295
+ left: e.left + (i - (o.left + o.width))
296
+ });
297
+ break;
298
+ case "vertical-center":
299
+ e.set({
300
+ top: e.top + (c.y - (o.top + o.height / 2))
301
+ });
302
+ break;
303
+ case "bottom":
304
+ e.set({
305
+ top: e.top + (a - (o.top + o.height))
306
+ });
307
+ break;
308
+ }
309
+ } else if (Object.prototype.hasOwnProperty.call(s, "zIndex"))
310
+ this.canvas.moveTo(e, s.zIndex);
311
+ else if (Object.prototype.hasOwnProperty.call(s, "scale"))
312
+ this.updateObjectScale(e, s.scale);
313
+ else if (Object.prototype.hasOwnProperty.call(s, "width") || Object.prototype.hasOwnProperty.call(s, "height")) {
314
+ const n = Object.prototype.hasOwnProperty.call(s, "width") ? e.width : e.height, r = (s.width || s.height) / n * this.workspaceManager.scale;
315
+ this.updateObjectScale(e, r);
316
+ } else
317
+ e.set(s);
318
+ e.setCoords(), this.canvas.requestRenderAll(), Object.prototype.hasOwnProperty.call(s, "selectable") || this.canvas.fire("object:modified", {
319
+ target: e
320
+ });
321
+ }
322
+ }
323
+ /**
324
+ * 对象缩放
325
+ */
326
+ updateObjectScale(t, s) {
327
+ const e = t.getCenterPoint(), n = this.workspaceManager.dimension.width * 0.01 / t.width;
328
+ t.scale(s < n ? n : s), t.setPositionByOrigin(e, "center", "center");
329
+ }
330
+ /**
331
+ * 修改画布上的对象的选中状态和事件状态
332
+ */
333
+ updateObjectsEvents(t) {
334
+ this.canvas.forEachObject((s) => {
335
+ s.set({
336
+ selectable: t,
337
+ evented: t
338
+ });
339
+ });
340
+ }
341
+ /**
342
+ * 获取当前可选择的对象,不包括背景图、裁剪区域
343
+ */
344
+ getLayerList() {
345
+ return this.canvas._objects.filter((t) => !A.includes(t.id || ""));
346
+ }
347
+ /**
348
+ * 设置当前选中的对象
349
+ */
350
+ setActiveObject(t) {
351
+ const s = this.canvas.getActiveObjects(), e = s.some((i) => i.id === t), n = this.getLayerList().find((i) => i.id === t);
352
+ n && (this.canvas.discardActiveObject(), (!e || s.length > 1) && this.canvas.setActiveObject(n), this.canvas.requestRenderAll());
353
+ }
354
+ /**
355
+ * 同时选中多个对象
356
+ */
357
+ setActiveObjects(t) {
358
+ const s = new d.ActiveSelection(t, { canvas: this.canvas });
359
+ this.canvas.setActiveObject(s), this.canvas.requestRenderAll();
360
+ }
361
+ /**
362
+ * 以画布中心点缩放画布
363
+ */
364
+ zoomToCenter(t) {
365
+ if (t === 1)
366
+ this.canvas.setViewportTransform([1, 0, 0, 1, 0, 0]);
367
+ else {
368
+ const s = this.canvas.viewportTransform, e = s[0], n = s[4], i = s[5], r = this.canvas.width / 2, a = this.canvas.height / 2, c = t - e, o = n - r * c, l = i - a * c;
369
+ this.canvas.setViewportTransform([t, 0, 0, t, o, l]);
370
+ }
371
+ this.canvas.requestRenderAll();
372
+ }
373
+ /**
374
+ * 获取当前画布上渲染的对象
375
+ */
376
+ getRenderedObjects() {
377
+ const { objects: t } = this.canvas.toJSON(T.DEFAULT_SAVE_PROPERTIES), s = this.workspaceManager.dimension;
378
+ return {
379
+ objects: t.filter((e) => !A.includes(e.id || "")),
380
+ workspaceMetadata: {
381
+ width: s.width,
382
+ height: s.height,
383
+ centerX: s.center.x,
384
+ centerY: s.center.y
385
+ }
386
+ };
387
+ }
388
+ /**
389
+ * 清空当前画布
390
+ */
391
+ clearCanvas() {
392
+ this.canvas._objects.length && (this.canvas.clear(), this.canvas.requestRenderAll());
393
+ }
394
+ /**
395
+ * 将图片对象的 clipPath 重新关联到画布上的对象
396
+ */
397
+ relinkClipPaths() {
398
+ const t = /* @__PURE__ */ new Map(), s = this.canvas.getObjects(), e = (i) => {
399
+ const r = i.id;
400
+ r && t.set(String(r), i), i.type === "group" && i._objects?.forEach(e);
401
+ };
402
+ s.forEach(e);
403
+ const n = (i) => {
404
+ const a = i.clipPath?.id;
405
+ if (a && t.has(String(a))) {
406
+ const c = t.get(String(a));
407
+ c.set({ absolutePositioned: !0 }), i.set("clipPath", c), i.dirty = !0;
408
+ }
409
+ i.type === "group" && i._objects?.forEach(n);
410
+ };
411
+ s.forEach(n);
412
+ }
413
+ /**
414
+ * 切换视图,重新渲染画布
415
+ */
416
+ async switchView(t, s, e) {
417
+ if (this.canvas.clear(), e && e.objects && e.objects.length)
418
+ return await this.textProcessor.preloadFontsFromState(e), new Promise((n) => {
419
+ this.canvas.loadFromJSON(
420
+ e,
421
+ async () => {
422
+ this.relinkClipPaths(), await this.renderOverlayImage(t, !0), await this.setBackground(s), e.workspaceMetadata && this._scaleObjectsToWorkspace(e.workspaceMetadata);
423
+ const i = this.canvas.getObjects().filter((r) => r.type === "image");
424
+ i.length > 0 && await Promise.all(
425
+ i.map((r) => new Promise((a) => {
426
+ const c = r.getElement(), o = r.getSrc() || r.originSrc;
427
+ if (!o) {
428
+ a();
429
+ return;
430
+ }
431
+ c && c.complete && c.naturalWidth > 0 ? (this.registerImageCache(o, r), a()) : c ? (c.onload = () => {
432
+ this.registerImageCache(o, r), a();
433
+ }, c.onerror = () => {
434
+ a();
435
+ }) : a();
436
+ }))
437
+ ), this.canvas.renderAll(), this.events.emit("design:layerChange"), n();
438
+ },
439
+ (i, r) => {
440
+ i.clipPath && !e.objects.some((a) => a.id === i.clipPath.id) && (delete r.clipPath, d.util.enlivenObjects(
441
+ [i.clipPath],
442
+ (a) => {
443
+ const c = a[0];
444
+ c && (r.set("clipPath", c), r.dirty = !0, this.canvas.requestRenderAll());
445
+ },
446
+ ""
447
+ ));
448
+ }
449
+ );
450
+ });
451
+ await this.renderOverlayImage(t, !0), await this.setBackground(s), e && e.object && await this.imageProcessor.addBitmapImage(e.object);
452
+ }
453
+ /**
454
+ * 根据 workspace 尺寸变化,按比例缩放所有对象
455
+ */
456
+ _scaleObjectsToWorkspace(t) {
457
+ const s = this.workspaceManager.dimension, e = Math.min(
458
+ s.width / t.width,
459
+ s.height / t.height
460
+ ), n = t.centerX, i = t.centerY, r = s.center.x, a = s.center.y, c = Math.abs(r - n), o = Math.abs(a - i), l = Math.abs(e - 1) >= 1e-3, u = c >= 0.1 || o >= 0.1;
461
+ if (!l && !u) return;
462
+ const v = this.canvas.getObjects(), y = new Set(v), P = /* @__PURE__ */ new Set(), S = (g) => {
463
+ const p = g.clipPath;
464
+ p && y.has(p) && P.add(p);
465
+ };
466
+ v.forEach(S);
467
+ const C = (g) => {
468
+ const p = (g.left || 0) - n, w = (g.top || 0) - i, m = r + p * e, f = a + w * e;
469
+ g.set({
470
+ left: m,
471
+ top: f,
472
+ scaleX: (g.scaleX || 1) * e,
473
+ scaleY: (g.scaleY || 1) * e
474
+ }), g.setCoords(), g.dirty = !0;
475
+ }, O = /* @__PURE__ */ new Set(), b = (g) => {
476
+ !g.selectable && !P.has(g) || (C(g), O.add(g));
477
+ };
478
+ v.forEach(b);
479
+ const h = (g) => {
480
+ const p = g.clipPath;
481
+ p && p.absolutePositioned && !y.has(p) && !O.has(p) && (C(p), O.add(p));
482
+ };
483
+ v.forEach(h);
484
+ }
485
+ /**
486
+ * 计算对象相对于画布的全局变换矩阵(包括父组的影响)
487
+ */
488
+ getGlobalTransformMatrix(t) {
489
+ return t.calcTransformMatrix();
490
+ }
491
+ /**
492
+ * 判断对象是否位于 activeSelection 中
493
+ */
494
+ isInActiveSelection(t) {
495
+ let s = t.group;
496
+ for (; s; ) {
497
+ if (s.type === "activeSelection") return !0;
498
+ s = s.group;
499
+ }
500
+ return !1;
501
+ }
502
+ /**
503
+ * 注册图片到缓存(会话级缓存,整个编辑期间保持)
504
+ */
505
+ registerImageCache(t, s, e) {
506
+ if (!t || t.startsWith("data:")) return;
507
+ const n = s.getElement(), i = this.imageCache.get(t);
508
+ this.imageCache.set(t, {
509
+ element: n,
510
+ blobUrl: e || i?.blobUrl,
511
+ lastUsed: Date.now()
512
+ });
513
+ }
514
+ /**
515
+ * 清除整个图片缓存(在关闭编辑器时调用)
516
+ */
517
+ clearImageCache() {
518
+ this.imageCache.forEach((t) => {
519
+ if (t.blobUrl)
520
+ try {
521
+ URL.revokeObjectURL(t.blobUrl);
522
+ } catch {
523
+ }
524
+ }), this.imageCache.clear();
525
+ }
526
+ /**
527
+ * 销毁编辑器,释放所有资源
528
+ */
529
+ destroy() {
530
+ this.clearImageCache(), this.canvas.clear(), this.canvas.dispose(), this.resizeManager.destroy();
531
+ }
532
+ /**
533
+ * 按需生成图片 dataURL(不缓存,减少内存占用)
534
+ */
535
+ async getCachedDataURL(t) {
536
+ if (!t)
537
+ return "";
538
+ const s = this.imageCache.get(t);
539
+ if (s?.element && s.element.complete) {
540
+ const e = document.createElement("canvas");
541
+ e.width = s.element.naturalWidth || s.element.width, e.height = s.element.naturalHeight || s.element.height;
542
+ const n = e.getContext("2d");
543
+ if (n) {
544
+ n.drawImage(s.element, 0, 0);
545
+ const i = e.toDataURL("image/png");
546
+ return e.width = 0, e.height = 0, i;
547
+ }
548
+ return "";
549
+ }
550
+ return await Y(t);
551
+ }
552
+ /**
553
+ * 从缓存克隆图片,避免重复下载
554
+ */
555
+ async cloneImageFromCache(t, s) {
556
+ const e = t.getSrc() || "", n = t.originSrc || "", i = t.isCropped, r = n || e;
557
+ if (r.startsWith("data:"))
558
+ return new Promise((c) => {
559
+ t.clone((o) => {
560
+ o.set(s), c(o);
561
+ }, ["absolutePositioned"]);
562
+ });
563
+ const a = this.imageCache.get(r);
564
+ return a?.element && a.element.complete ? new Promise(async (c) => {
565
+ const o = new d.Image(a.element, {
566
+ width: t.width,
567
+ height: t.height,
568
+ ...s
569
+ });
570
+ if (t.clipPath)
571
+ try {
572
+ const l = await k(t.clipPath, ["absolutePositioned"]);
573
+ o.set({ clipPath: l });
574
+ } catch {
575
+ }
576
+ i && (o.isCropped = !0, o.cropBlob = t.cropBlob), c(o);
577
+ }) : new Promise((c) => {
578
+ t.clone((o) => {
579
+ this.registerImageCache(r, o), o.set(s), i && (o.isCropped = !0, o.cropBlob = t.cropBlob), c(o);
580
+ }, ["absolutePositioned"]);
581
+ });
582
+ }
583
+ /**
584
+ * 导出 clipPath 区域内容(按打印区域原始尺寸)
585
+ * @param embedImages 是否将图片转为 dataURL 内嵌
586
+ * @param color 背景颜色
587
+ */
588
+ async export(t = !1, s) {
589
+ const e = this.workspaceManager.dimension, n = this.workspaceManager.printAreaSize?.width ?? e.width, i = this.workspaceManager.printAreaSize?.height ?? e.height, r = window.devicePixelRatio || 1, a = Math.max(n / e.width, i / e.height), c = Math.max(4, Math.min(8, Math.ceil(a * r)));
590
+ let o = new d.Rect({
591
+ left: 0,
592
+ top: 0,
593
+ width: e.width,
594
+ height: e.height,
595
+ absolutePositioned: !0,
596
+ strokeWidth: 0
597
+ });
598
+ this.canvas.clipPath && (o = await k(this.canvas.clipPath, ["absolutePositioned"]), o.set({
599
+ left: this.canvas.clipPath.left - e.left,
600
+ top: this.canvas.clipPath.top - e.top,
601
+ absolutePositioned: !0
602
+ }));
603
+ const l = new d.StaticCanvas(null, {
604
+ width: e.width,
605
+ height: e.height,
606
+ enableRetinaScaling: !1,
607
+ backgroundColor: s || "transparent",
608
+ preserveObjectStacking: !0,
609
+ clipPath: o
610
+ }), u = this.getLayerList();
611
+ (await Promise.all(
612
+ u.map(
613
+ (h) => new Promise((g) => {
614
+ try {
615
+ if (h.type === "image") {
616
+ const p = h;
617
+ let w = {
618
+ selectable: !1,
619
+ evented: !1,
620
+ flipX: h.flipX || !1,
621
+ flipY: h.flipY || !1
622
+ };
623
+ if (this.isInActiveSelection(h)) {
624
+ const m = this.getGlobalTransformMatrix(h), f = d.util.qrDecompose(m);
625
+ w = {
626
+ ...w,
627
+ left: (f.translateX || 0) - (e.left || 0),
628
+ top: (f.translateY || 0) - (e.top || 0),
629
+ angle: f.angle || 0,
630
+ scaleX: f.scaleX || 1,
631
+ scaleY: f.scaleY || 1,
632
+ originX: "center",
633
+ originY: "center"
634
+ };
635
+ } else
636
+ w = {
637
+ ...w,
638
+ left: h.left - e.left,
639
+ top: h.top - e.top,
640
+ angle: h.angle || 0,
641
+ scaleX: h.scaleX || 1,
642
+ scaleY: h.scaleY || 1,
643
+ originX: "left",
644
+ originY: "top"
645
+ };
646
+ this.cloneImageFromCache(p, w).then(async (m) => {
647
+ if (m.clipPath) {
648
+ const f = m.clipPath;
649
+ f.absolutePositioned && f.set({
650
+ left: (f.left || 0) - e.left,
651
+ top: (f.top || 0) - e.top
652
+ });
653
+ }
654
+ if (t && m.type === "image")
655
+ try {
656
+ const f = m, I = f.getSrc() || f.originSrc || "";
657
+ if (I) {
658
+ const M = await this.getCachedDataURL(I);
659
+ f.setSrc(M, () => g(m));
660
+ return;
661
+ }
662
+ } catch {
663
+ }
664
+ g(m);
665
+ }).catch(() => {
666
+ g(h);
667
+ });
668
+ } else
669
+ h.cloneAsImage(
670
+ (p) => {
671
+ if (this.isInActiveSelection(h)) {
672
+ const w = this.getGlobalTransformMatrix(h), m = d.util.qrDecompose(w);
673
+ p.set({
674
+ left: (m.translateX || 0) - (e.left || 0),
675
+ top: (m.translateY || 0) - (e.top || 0),
676
+ angle: m.angle || 0,
677
+ scaleX: (m.scaleX || 1) / c,
678
+ scaleY: (m.scaleY || 1) / c,
679
+ selectable: !1,
680
+ hasControls: !1,
681
+ hasBorders: !1,
682
+ originX: "center",
683
+ originY: "center"
684
+ });
685
+ } else {
686
+ const w = h.getBoundingRect(!0, !0);
687
+ p.set({
688
+ left: w.left - e.left,
689
+ top: w.top - e.top,
690
+ scaleX: 1 / c,
691
+ scaleY: 1 / c,
692
+ angle: 0,
693
+ selectable: !1,
694
+ hasControls: !1,
695
+ hasBorders: !1,
696
+ originX: "left",
697
+ originY: "top"
698
+ });
699
+ }
700
+ g(p);
701
+ },
702
+ { multiplier: c }
703
+ );
704
+ } catch {
705
+ g(h);
706
+ }
707
+ })
708
+ )
709
+ )).forEach((h) => l.add(h));
710
+ const y = n / e.width, P = i / e.height;
711
+ l.setViewportTransform([y, 0, 0, P, 0, 0]), l.renderAll();
712
+ const S = 1024;
713
+ let C = 1;
714
+ (n < S || i < S) && (C = Math.max(1, S / Math.max(n, i)));
715
+ let O = "";
716
+ const b = () => l.toDataURL({
717
+ format: "webp",
718
+ quality: 0.5,
719
+ width: n,
720
+ height: i,
721
+ multiplier: C
722
+ });
723
+ if (window.createImageBitmap && typeof l.toCanvasElement == "function") {
724
+ const h = l.toCanvasElement(C, { width: n, height: i });
725
+ O = await createImageBitmap(h);
726
+ } else
727
+ O = b();
728
+ return l.dispose(), O;
729
+ }
730
+ }
731
+ export {
732
+ se as Editor,
733
+ se as default
734
+ };