@anu3ev/fabric-image-editor 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 (3) hide show
  1. package/dist/main.js +3146 -0
  2. package/package.json +46 -0
  3. package/readme.md +8 -0
package/dist/main.js ADDED
@@ -0,0 +1,3146 @@
1
+ import { ActiveSelection as k, util as x, controlsUtils as Le, InteractiveFabricObject as Oe, Pattern as Te, loadSVGFromURL as Ee, FabricImage as ue, Point as Ze, Rect as Be, Circle as ke, Triangle as xe, Group as ze, Canvas as Ye } from "fabric";
2
+ import { create as We } from "jsondiffpatch";
3
+ var He = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict", p = function() {
4
+ for (var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 21, t = "", a = crypto.getRandomValues(new Uint8Array(e |= 0)); e--; )
5
+ t += He[a[e] & 63];
6
+ return t;
7
+ };
8
+ function de(n, e, t, a, r, i, o) {
9
+ try {
10
+ var s = n[i](o), c = s.value;
11
+ } catch (d) {
12
+ return void t(d);
13
+ }
14
+ s.done ? e(c) : Promise.resolve(c).then(a, r);
15
+ }
16
+ function Ue(n) {
17
+ return function() {
18
+ var e = this, t = arguments;
19
+ return new Promise(function(a, r) {
20
+ var i = n.apply(e, t);
21
+ function o(c) {
22
+ de(i, a, r, o, s, "next", c);
23
+ }
24
+ function s(c) {
25
+ de(i, a, r, o, s, "throw", c);
26
+ }
27
+ o(void 0);
28
+ });
29
+ };
30
+ }
31
+ class Ve {
32
+ /**
33
+ * Конструктор принимает редактор и опции.
34
+ * @param {Object} params
35
+ * @param {ImageEditor} params.editor – редактор, содержащий canvas
36
+ * @param {Object} params.options — настройки редактора (см. defaults.js)
37
+ * @param {Boolean} [params.options.canvasDragging] — включить перетаскивание канваса
38
+ * @param {Boolean} [params.options.mouseWheelZooming] — включить зум колесом мыши
39
+ * @param {Boolean} [params.options.bringToFrontOnSelection] — поднимать объект на передний план при выборе
40
+ * @param {Boolean} [params.options.copyObjectsByHotkey] — копировать объекты по Ctrl+C
41
+ * @param {Boolean} [params.options.pasteImageFromClipboard] — вставлять изображения и объекты из буфера обмена
42
+ * @param {Boolean} [params.options.undoRedoByHotKeys] — отмена/повтор по Ctrl+Z/Ctrl+Y
43
+ * @param {Boolean} [params.options.selectAllByHotkey] — выделение всех объектов по Ctrl+A
44
+ * @param {Boolean} [params.options.deleteObjectsByHotkey] — удаление объектов по Delete
45
+ * @param {Boolean} [params.options.resetObjectFitByDoubleClick] — сброс фита объекта по двойному клику
46
+ */
47
+ constructor(e) {
48
+ var {
49
+ editor: t,
50
+ options: a = {}
51
+ } = e;
52
+ this.editor = t, this.canvas = t.canvas, this.options = a, this.isUndoRedoKeyPressed = !1, this.handleAdaptCanvasToContainerBound = this.debounce(this.handleAdaptCanvasToContainer.bind(this), 500), this.handleCopyEventBound = this.handleCopyEvent.bind(this), this.handlePasteEventBound = this.handlePasteEvent.bind(this), this.handleUndoRedoEventBound = this.handleUndoRedoEvent.bind(this), this.handleUndoRedoKeyUpBound = this.handleUndoRedoKeyUp.bind(this), this.handleSelectAllEventBound = this.handleSelectAllEvent.bind(this), this.handleDeleteObjectsEventBound = this.handleDeleteObjectsEvent.bind(this), this.handleObjectModifiedHistoryBound = this.debounce(this.handleObjectModifiedHistory.bind(this), 300), this.handleObjectRotatingHistoryBound = this.debounce(this.handleObjectRotatingHistory.bind(this), 300), this.handleObjectAddedHistoryBound = this.handleObjectAddedHistory.bind(this), this.handleObjectRemovedHistoryBound = this.handleObjectRemovedHistory.bind(this), this.handleOverlayUpdateBound = this.handleOverlayUpdate.bind(this), this.handleCanvasDragStartBound = this.handleCanvasDragStart.bind(this), this.handleCanvasDraggingBound = this.handleCanvasDragging.bind(this), this.handleCanvasDragEndBound = this.handleCanvasDragEnd.bind(this), this.handleMouseWheelZoomBound = this.handleMouseWheelZoom.bind(this), this.handleBringToFrontBound = this.handleBringToFront.bind(this), this.handleResetObjectFitBound = this.handleResetObjectFit.bind(this), this.handleLockedSelectionBound = this._filterLockedSelection.bind(this), this.init();
53
+ }
54
+ /**
55
+ * Инициализация всех обработчиков согласно опциям.
56
+ */
57
+ init() {
58
+ var {
59
+ adaptCanvasToContainer: e,
60
+ canvasDragging: t,
61
+ mouseWheelZooming: a,
62
+ bringToFrontOnSelection: r,
63
+ copyObjectsByHotkey: i,
64
+ pasteImageFromClipboard: o,
65
+ undoRedoByHotKeys: s,
66
+ selectAllByHotkey: c,
67
+ deleteObjectsByHotkey: d,
68
+ resetObjectFitByDoubleClick: l
69
+ } = this.options;
70
+ t && (this.canvas.on("mouse:down", this.handleCanvasDragStartBound), this.canvas.on("mouse:move", this.handleCanvasDraggingBound), this.canvas.on("mouse:up", this.handleCanvasDragEndBound)), a && this.canvas.on("mouse:wheel", this.handleMouseWheelZoomBound), r && (this.canvas.on("selection:created", this.handleBringToFrontBound), this.canvas.on("selection:updated", this.handleBringToFrontBound)), l && this.canvas.on("mouse:dblclick", this.handleResetObjectFitBound), e && window.addEventListener("resize", this.handleAdaptCanvasToContainerBound, {
71
+ capture: !0
72
+ }), i && document.addEventListener("keydown", this.handleCopyEventBound, {
73
+ capture: !0
74
+ }), o && document.addEventListener("paste", this.handlePasteEventBound, {
75
+ capture: !0
76
+ }), s && (document.addEventListener("keydown", this.handleUndoRedoEventBound, {
77
+ capture: !0
78
+ }), document.addEventListener("keyup", this.handleUndoRedoKeyUpBound, {
79
+ capture: !0
80
+ })), c && document.addEventListener("keydown", this.handleSelectAllEventBound, {
81
+ capture: !0
82
+ }), d && document.addEventListener("keydown", this.handleDeleteObjectsEventBound, {
83
+ capture: !0
84
+ }), this.canvas.on("object:modified", this.handleObjectModifiedHistoryBound), this.canvas.on("object:rotating", this.handleObjectRotatingHistoryBound), this.canvas.on("object:added", this.handleObjectAddedHistoryBound), this.canvas.on("object:removed", this.handleObjectRemovedHistoryBound), this.canvas.on("object:added", this.handleOverlayUpdateBound), this.canvas.on("selection:created", this.handleOverlayUpdateBound), this.canvas.on("selection:created", this.handleLockedSelectionBound.bind(this)), this.canvas.on("selection:updated", this.handleLockedSelectionBound.bind(this));
85
+ }
86
+ /**
87
+ * При массовом выделении объектов удаляем из него залоченные.
88
+ */
89
+ _filterLockedSelection(e) {
90
+ var {
91
+ selected: t
92
+ } = e;
93
+ if (t != null && t.length && t.length !== 1) {
94
+ var a = t.some((o) => o.locked);
95
+ if (a) {
96
+ var r = t.filter((o) => !o.locked);
97
+ if (r.length === 0) {
98
+ this.canvas.discardActiveObject();
99
+ return;
100
+ }
101
+ if (r.length === 1) {
102
+ this.canvas.setActiveObject(r[0]);
103
+ return;
104
+ }
105
+ var i = new k(r, {
106
+ canvas: this.canvas
107
+ });
108
+ this.canvas.setActiveObject(i), this.canvas.requestRenderAll();
109
+ }
110
+ }
111
+ }
112
+ /**
113
+ * Обработчики для сохранения состояния редактора в истории.
114
+ * Срабатывают при изменении объектов (перемещение, изменение размера и т.д.).
115
+ */
116
+ handleObjectModifiedHistory() {
117
+ this.editor.historyManager.skipHistory || this.editor.historyManager.saveState();
118
+ }
119
+ handleObjectRotatingHistory() {
120
+ this.editor.historyManager.skipHistory || this.editor.historyManager.saveState();
121
+ }
122
+ handleObjectAddedHistory() {
123
+ this.editor.historyManager.skipHistory || this.editor.historyManager.saveState();
124
+ }
125
+ handleObjectRemovedHistory() {
126
+ this.editor.historyManager.skipHistory || this.editor.historyManager.saveState();
127
+ }
128
+ /**
129
+ * Обновление overlayMask при добавлении объектов или выделении.
130
+ */
131
+ handleOverlayUpdate() {
132
+ var {
133
+ interactionBlocker: e
134
+ } = this.editor;
135
+ !e.isBlocked || !e.overlayMask || this.editor.interactionBlocker.refresh();
136
+ }
137
+ // --- Глобальные DOM-обработчики ---
138
+ /**
139
+ * Обработчик изменения размеров окна браузера.
140
+ * Адаптирует канвас к размерам контейнера.
141
+ */
142
+ handleAdaptCanvasToContainer() {
143
+ var {
144
+ width: e,
145
+ height: t
146
+ } = this.editor.montageArea;
147
+ this.editor.canvasManager.setResolutionWidth(e, {
148
+ adaptCanvasToContainer: !0,
149
+ withoutSave: !0
150
+ }), this.editor.canvasManager.setResolutionHeight(t, {
151
+ adaptCanvasToContainer: !0,
152
+ withoutSave: !0
153
+ }), this.editor.canvasManager.centerMontageArea(), this.editor.transformManager.resetObjects();
154
+ }
155
+ /**
156
+ * Обработчик для Ctrl+C (копирование).
157
+ * @param {Object} event — объект события
158
+ * @param {Boolean} event.ctrlKey — зажата ли клавиша Ctrl
159
+ * @param {Boolean} event.metaKey — зажата ли клавиша Cmd (для Mac)
160
+ * @param {String} event.code — код клавиши
161
+ */
162
+ handleCopyEvent(e) {
163
+ var {
164
+ ctrlKey: t,
165
+ metaKey: a,
166
+ code: r
167
+ } = e;
168
+ !t && !a || r !== "KeyC" || (e.preventDefault(), this.editor.clipboardManager.copy());
169
+ }
170
+ /**
171
+ * Обработчик вставки объекта или изображения из буфера обмена.
172
+ * @param {Object} event — объект события
173
+ * @param {Object} event.clipboardData — данные из буфера обмена
174
+ * @param {Array} event.clipboardData.items — элементы буфера обмена
175
+ */
176
+ handlePasteEvent(e) {
177
+ var t, {
178
+ clipboardData: a
179
+ } = e;
180
+ if (a != null && (t = a.items) !== null && t !== void 0 && t.length) {
181
+ var {
182
+ items: r
183
+ } = a, i = r[r.length - 1];
184
+ if (i.type.indexOf("image") !== -1) {
185
+ var o = i.getAsFile();
186
+ if (!o) return;
187
+ var s = new FileReader();
188
+ s.onload = (g) => {
189
+ this.editor.imageManager.importImage({
190
+ source: g.target.result
191
+ });
192
+ }, s.readAsDataURL(o);
193
+ return;
194
+ }
195
+ var c = a.getData("text/html");
196
+ if (c) {
197
+ var d = new DOMParser(), l = d.parseFromString(c, "text/html"), u = l.querySelector("img");
198
+ if (u != null && u.src) {
199
+ this.editor.imageManager.importImage({
200
+ source: u.src
201
+ });
202
+ return;
203
+ }
204
+ }
205
+ this.editor.clipboardManager.paste();
206
+ }
207
+ }
208
+ /**
209
+ * Обработчик для отмены/повтора (Ctrl+Z/Ctrl+Y).
210
+ * @param {Object} event — объект события
211
+ * @param {Boolean} event.ctrlKey — зажата ли клавиша Ctrl
212
+ * @param {Boolean} event.metaKey — зажата ли клавиша Cmd (для Mac)
213
+ * @param {String} event.code — код клавиши
214
+ */
215
+ handleUndoRedoEvent(e) {
216
+ var t = this;
217
+ return Ue(function* () {
218
+ var {
219
+ ctrlKey: a,
220
+ metaKey: r,
221
+ code: i,
222
+ repeat: o
223
+ } = e;
224
+ !a && !r || o || t.isUndoRedoKeyPressed || (i === "KeyZ" ? (e.preventDefault(), t.isUndoRedoKeyPressed = !0, yield t.editor.historyManager.undo()) : i === "KeyY" && (e.preventDefault(), t.isUndoRedoKeyPressed = !0, yield t.editor.historyManager.redo()));
225
+ })();
226
+ }
227
+ /**
228
+ * Обработчик для отпускания клавиш Ctrl+Z/Ctrl+Y.
229
+ * @param {Object} event — объект события
230
+ * @param {String} event.code — код клавиши
231
+ */
232
+ handleUndoRedoKeyUp(e) {
233
+ var {
234
+ code: t
235
+ } = e;
236
+ (t === "KeyZ" || t === "KeyY") && (this.isUndoRedoKeyPressed = !1);
237
+ }
238
+ /**
239
+ * Обработчик для выделения всех объектов (Ctrl+A).
240
+ * @param {Object} event — объект события
241
+ * @param {Boolean} event.ctrlKey — зажата ли клавиша Ctrl
242
+ * @param {Boolean} event.metaKey — зажата ли клавиша Cmd (для Mac)
243
+ * @param {String} event.code — код клавиши
244
+ */
245
+ handleSelectAllEvent(e) {
246
+ var {
247
+ ctrlKey: t,
248
+ metaKey: a,
249
+ code: r
250
+ } = e;
251
+ !t && !a || r !== "KeyA" || (e.preventDefault(), this.editor.selectionManager.selectAll());
252
+ }
253
+ /**
254
+ * Обработчик для удаления объектов (Delete).
255
+ * @param {Object} event — объект события
256
+ * @param {String} event.code — код клавиши
257
+ */
258
+ handleDeleteObjectsEvent(e) {
259
+ e.code === "Delete" && (e.preventDefault(), this.editor.deletionManager.deleteSelectedObjects());
260
+ }
261
+ // --- Обработчики для событий canvas (Fabric) ---
262
+ /**
263
+ * Начало перетаскивания канваса (срабатывает при mouse:down).
264
+ * @param {Object} options
265
+ * @param {Object} options.e — объект события
266
+ */
267
+ handleCanvasDragStart(e) {
268
+ var {
269
+ e: t
270
+ } = e;
271
+ t.altKey && (this.canvas.isDragging = !0, this.canvas.selection = !1, this.canvas.lastPosX = t.clientX, this.canvas.lastPosY = t.clientY);
272
+ }
273
+ /**
274
+ * Перетаскивание канваса (mouse:move).
275
+ * @param {Object} options
276
+ * @param {Object} options.e — объект события
277
+ *
278
+ * TODO: Надо как-то ограничить область перетаскивания, чтобы канвас не уходил сильно далеко за пределы экрана
279
+ */
280
+ handleCanvasDragging(e) {
281
+ var {
282
+ e: t
283
+ } = e;
284
+ if (this.canvas.isDragging) {
285
+ var a = this.canvas.viewportTransform;
286
+ a[4] += t.clientX - this.canvas.lastPosX, a[5] += t.clientY - this.canvas.lastPosY, this.canvas.requestRenderAll(), this.canvas.lastPosX = t.clientX, this.canvas.lastPosY = t.clientY;
287
+ }
288
+ }
289
+ /**
290
+ * Завершение перетаскивания канваса (mouse:up).
291
+ * Сохраняет новое положение канваса.
292
+ */
293
+ handleCanvasDragEnd() {
294
+ this.canvas.setViewportTransform(this.canvas.viewportTransform), this.canvas.isDragging = !1, this.canvas.selection = !0;
295
+ }
296
+ /**
297
+ * Обработчик зума колесиком мыши.
298
+ * @param {Object} options
299
+ * @param {Object} options.e — объект события
300
+ */
301
+ handleMouseWheelZoom(e) {
302
+ var {
303
+ e: t
304
+ } = e, a = 1e-3, r = -t.deltaY * a;
305
+ this.editor.transformManager.zoom(r), t.preventDefault(), t.stopPropagation();
306
+ }
307
+ /**
308
+ * Обработчик, поднимающий выделенные объекты на передний план.
309
+ * @param {Object} event - объект события Fabric
310
+ * @param {Array} event.selected - массив выбранных объектов
311
+ */
312
+ handleBringToFront(e) {
313
+ var {
314
+ selected: t
315
+ } = e;
316
+ t != null && t.length && t.forEach((a) => {
317
+ this.editor.layerManager.bringToFront(a);
318
+ });
319
+ }
320
+ /**
321
+ * Обработчик сброса объекта по двойному клику.
322
+ */
323
+ handleResetObjectFit(e) {
324
+ var {
325
+ target: t
326
+ } = e;
327
+ t && this.editor.transformManager.resetObject(t);
328
+ }
329
+ /**
330
+ * Метод для удаления всех слушателей
331
+ */
332
+ destroy() {
333
+ window.removeEventListener("resize", this.handleAdaptCanvasToContainerBound, {
334
+ capture: !0
335
+ }), document.removeEventListener("keydown", this.handleCopyEventBound, {
336
+ capture: !0
337
+ }), document.removeEventListener("paste", this.handlePasteEventBound, {
338
+ capture: !0
339
+ }), document.removeEventListener("keydown", this.handleUndoRedoEventBound, {
340
+ capture: !0
341
+ }), document.removeEventListener("keyup", this.handleUndoRedoKeyUpBound, {
342
+ capture: !0
343
+ }), document.removeEventListener("keydown", this.handleSelectAllEventBound, {
344
+ capture: !0
345
+ }), document.removeEventListener("keydown", this.handleDeleteObjectsEventBound, {
346
+ capture: !0
347
+ }), this.options.canvasDragging && (this.canvas.off("mouse:down", this.handleCanvasDragStartBound), this.canvas.off("mouse:move", this.handleCanvasDraggingBound), this.canvas.off("mouse:up", this.handleCanvasDragEndBound)), this.options.mouseWheelZooming && this.canvas.off("mouse:wheel", this.handleMouseWheelZoomBound), this.options.bringToFrontOnSelection && (this.canvas.off("selection:created", this.handleBringToFrontBound), this.canvas.off("selection:updated", this.handleBringToFrontBound)), this.options.resetObjectFitByDoubleClick && this.canvas.off("mouse:dblclick", this.handleResetObjectFitBound), this.canvas.off("object:modified", this.handleObjectModifiedHistoryBound), this.canvas.off("object:rotating", this.handleObjectRotatingHistoryBound), this.canvas.off("object:added", this.handleObjectAddedHistoryBound), this.canvas.off("object:removed", this.handleObjectRemovedHistoryBound), this.canvas.off("object:added", this.handleOverlayUpdateBound), this.canvas.off("selection:created", this.handleOverlayUpdateBound), this.canvas.off("selection:created", this.handleLockedSelectionBound.bind(this)), this.canvas.off("selection:updated", this.handleLockedSelectionBound.bind(this));
348
+ }
349
+ // Дебаунс для снижения частоты сохранения состояния
350
+ debounce(e, t) {
351
+ var a = null;
352
+ return function() {
353
+ for (var r = arguments.length, i = new Array(r), o = 0; o < r; o++)
354
+ i[o] = arguments[o];
355
+ var s = this;
356
+ clearTimeout(a), a = setTimeout(() => {
357
+ e.apply(s, i);
358
+ }, t);
359
+ };
360
+ }
361
+ }
362
+ class Pe {
363
+ /**
364
+ * @description Класс для динамической загрузки внешних модулей.
365
+ */
366
+ constructor() {
367
+ this.cache = /* @__PURE__ */ new Map(), this.loaders = {
368
+ jspdf: () => import("jspdf")
369
+ };
370
+ }
371
+ /**
372
+ * Загружает модуль по имени и сохраняет промис в кеше.
373
+ * @param {string} name — строковый литерал, например 'fabric' или '../helpers'
374
+ * @returns {Promise<Module>} — namespace-объект ES-модуля
375
+ */
376
+ loadModule(e) {
377
+ return this.loaders[e] ? (this.cache.has(e) || this.cache.set(e, this.loaders[e]()), this.cache.get(e)) : Promise.reject(new Error('Unknown module "'.concat(e, '"')));
378
+ }
379
+ }
380
+ class Re {
381
+ /**
382
+ * @param {string|URL} [scriptUrl] — URL скрипта воркера.
383
+ * По-умолчанию использует файл рядом с этим модулем
384
+ */
385
+ constructor() {
386
+ var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : new URL("data:text/javascript;base64,LyogZXNsaW50LWRpc2FibGUgbm8tcmVzdHJpY3RlZC1nbG9iYWxzICovCgpzZWxmLm9ubWVzc2FnZSA9IGFzeW5jKGUpID0+IHsKICBjb25zdCB7IGFjdGlvbiwgcGF5bG9hZCwgcmVxdWVzdElkIH0gPSBlLmRhdGEKCiAgdHJ5IHsKICAgIHN3aXRjaCAoYWN0aW9uKSB7CiAgICBjYXNlICdyZXNpemVJbWFnZSc6IHsKICAgICAgY29uc3QgeyBkYXRhVVJMLCBtYXhXaWR0aCwgbWF4SGVpZ2h0LCBzaXplVHlwZSB9ID0gcGF5bG9hZAogICAgICBjb25zdCBpbWdCaXRtYXAgPSBhd2FpdCBjcmVhdGVJbWFnZUJpdG1hcChhd2FpdCAoYXdhaXQgZmV0Y2goZGF0YVVSTCkpLmJsb2IoKSkKCiAgICAgIC8vINCy0YvRh9C40YHQu9GP0LXQvCDQvdC+0LLRi9C5INGA0LDQt9C80LXRgAogICAgICBsZXQgeyB3aWR0aCwgaGVpZ2h0IH0gPSBpbWdCaXRtYXAKICAgICAgbGV0IHJhdGlvID0gTWF0aC5taW4obWF4V2lkdGggLyB3aWR0aCwgbWF4SGVpZ2h0IC8gaGVpZ2h0KQoKICAgICAgaWYgKHNpemVUeXBlID09PSAnbWluJykgewogICAgICAgIHJhdGlvID0gTWF0aC5tYXgobWF4V2lkdGggLyB3aWR0aCwgbWF4SGVpZ2h0IC8gaGVpZ2h0KQogICAgICB9CgogICAgICB3aWR0aCA9IE1hdGguZmxvb3Iod2lkdGggKiByYXRpbykKICAgICAgaGVpZ2h0ID0gTWF0aC5mbG9vcihoZWlnaHQgKiByYXRpbykKCiAgICAgIC8vINGA0LjRgdGD0LXQvCDQuNC30L7QsdGA0LDQttC10L3QuNC1INCyIG9mZnNjcmVlbgogICAgICBjb25zdCBvZmZzY3JlZW4gPSBuZXcgT2Zmc2NyZWVuQ2FudmFzKHdpZHRoLCBoZWlnaHQpCiAgICAgIGNvbnN0IGN0eCA9IG9mZnNjcmVlbi5nZXRDb250ZXh0KCcyZCcpCiAgICAgIGN0eC5kcmF3SW1hZ2UoaW1nQml0bWFwLCAwLCAwLCB3aWR0aCwgaGVpZ2h0KQoKICAgICAgLy8g0LrQvtC90LLQtdGA0YLQuNC8INC+0LHRgNCw0YLQvdC+INCyIGRhdGFVUkwKICAgICAgY29uc3QgcmVzaXplZEJsb2IgPSBhd2FpdCBvZmZzY3JlZW4uY29udmVydFRvQmxvYigpCgogICAgICBzZWxmLnBvc3RNZXNzYWdlKHsgcmVxdWVzdElkLCBhY3Rpb24sIHN1Y2Nlc3M6IHRydWUsIGRhdGE6IHJlc2l6ZWRCbG9iIH0pCiAgICAgIGJyZWFrCiAgICB9CgogICAgY2FzZSAndG9EYXRhVVJMJzogewogICAgICBjb25zdCB7IGJpdG1hcCwgZm9ybWF0LCBxdWFsaXR5LCByZXR1cm5CbG9iIH0gPSBwYXlsb2FkCiAgICAgIGNvbnN0IHsgd2lkdGgsIGhlaWdodCB9ID0gYml0bWFwCgogICAgICAvLyDRgNC40YHRg9C10Lwg0LjQt9C+0LHRgNCw0LbQtdC90LjQtSDQsiBvZmZzY3JlZW4KICAgICAgY29uc3Qgb2ZmID0gbmV3IE9mZnNjcmVlbkNhbnZhcyhiaXRtYXAud2lkdGgsIGJpdG1hcC5oZWlnaHQpCiAgICAgIGNvbnN0IGN0eCA9IG9mZi5nZXRDb250ZXh0KCcyZCcpCiAgICAgIGN0eC5kcmF3SW1hZ2UoYml0bWFwLCAwLCAwLCB3aWR0aCwgaGVpZ2h0KQoKICAgICAgLy8g0LrQvtC90LLQtdGA0YLQuNGA0YPQtdC8INCyIGJsb2IsINCwINC30LDRgtC10Lwg0LIgZGF0YVVSTAogICAgICBjb25zdCBibG9iID0gYXdhaXQgb2ZmLmNvbnZlcnRUb0Jsb2IoeyB0eXBlOiBmb3JtYXQsIHF1YWxpdHkgfSkKCiAgICAgIGlmIChyZXR1cm5CbG9iKSB7CiAgICAgICAgc2VsZi5wb3N0TWVzc2FnZSh7IHJlcXVlc3RJZCwgYWN0aW9uLCBzdWNjZXNzOiB0cnVlLCBkYXRhOiBibG9iIH0pCiAgICAgICAgYnJlYWsKICAgICAgfQoKICAgICAgY29uc3QgZGF0YVVSTCA9IGF3YWl0IG5ldyBQcm9taXNlKChyZXMpID0+IHsKICAgICAgICBjb25zdCByID0gbmV3IEZpbGVSZWFkZXIoKQogICAgICAgIHIub25sb2FkID0gKCkgPT4gcmVzKHIucmVzdWx0KQogICAgICAgIHIucmVhZEFzRGF0YVVSTChibG9iKQogICAgICB9KQoKICAgICAgc2VsZi5wb3N0TWVzc2FnZSh7IHJlcXVlc3RJZCwgYWN0aW9uLCBzdWNjZXNzOiB0cnVlLCBkYXRhOiBkYXRhVVJMIH0pCiAgICAgIGJyZWFrCiAgICB9CgogICAgZGVmYXVsdDoKICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIGFjdGlvbiAke2FjdGlvbn1gKQogICAgfQogIH0gY2F0Y2ggKGVycikgewogICAgc2VsZi5wb3N0TWVzc2FnZSh7IHJlcXVlc3RJZCwgYWN0aW9uLCBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IGVyci5tZXNzYWdlIH0pCiAgfQp9Cg==", import.meta.url);
387
+ this.worker = new Worker(e, {
388
+ type: "module"
389
+ }), this._callbacks = /* @__PURE__ */ new Map(), this.worker.onmessage = this._handleMessage.bind(this);
390
+ }
391
+ /**
392
+ * Обработчик сообщений от воркера
393
+ * @param {Object} data
394
+ * @param {String} data.action - название действия
395
+ * @param {String} data.requestId - уникальный идентификатор запроса
396
+ * @param {Boolean} data.success - успешность выполнения действия
397
+ * @param {Object} data.data - данные, которые вернул воркер
398
+ * @param {String} data.error - ошибка, если она произошла
399
+ * @returns {void}
400
+ */
401
+ _handleMessage(e) {
402
+ var {
403
+ data: t
404
+ } = e, {
405
+ requestId: a,
406
+ success: r,
407
+ data: i,
408
+ error: o
409
+ } = t, s = this._callbacks.get(a);
410
+ s && (r ? s.resolve(i) : s.reject(new Error(o)), this._callbacks.delete(a));
411
+ }
412
+ /**
413
+ * Универсальный метод отправки команды в воркер
414
+ * @param {String} action
415
+ * @param {Object} payload
416
+ * @param {Array} [transferables] - массив объектов, которые нужно передать в воркер
417
+ * @returns {Promise<any>}
418
+ */
419
+ post(e, t) {
420
+ var a = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : [], r = "".concat(e, ":").concat(p(8));
421
+ return new Promise((i, o) => {
422
+ this._callbacks.set(r, {
423
+ resolve: i,
424
+ reject: o
425
+ }), this.worker.postMessage({
426
+ action: e,
427
+ payload: t,
428
+ requestId: r
429
+ }, a);
430
+ });
431
+ }
432
+ /**
433
+ * Завершает работу воркера
434
+ */
435
+ terminate() {
436
+ this.worker.terminate();
437
+ }
438
+ }
439
+ var b = 12, Ge = 2, _ = 8, X = 20, Fe = 100, Q = 20, K = 8, _e = 100, J = 32, $ = 1, Xe = "#2B2D33", q = "#3D8BF4", ee = "#FFFFFF";
440
+ function z(n, e, t, a, r) {
441
+ var i = b, o = Ge;
442
+ n.save(), n.translate(e, t), n.rotate(x.degreesToRadians(r.angle)), n.fillStyle = ee, n.strokeStyle = q, n.lineWidth = $, n.beginPath(), n.roundRect(-12 / 2, -12 / 2, i, i, o), n.fill(), n.stroke(), n.restore();
443
+ }
444
+ function le(n, e, t, a, r) {
445
+ var i = _, o = X, s = Fe;
446
+ n.save(), n.translate(e, t), n.rotate(x.degreesToRadians(r.angle)), n.fillStyle = ee, n.strokeStyle = q, n.lineWidth = $, n.beginPath(), n.roundRect(-8 / 2, -20 / 2, i, o, s), n.fill(), n.stroke(), n.restore();
447
+ }
448
+ function ge(n, e, t, a, r) {
449
+ var i = Q, o = K, s = _e;
450
+ n.save(), n.translate(e, t), n.rotate(x.degreesToRadians(r.angle)), n.fillStyle = ee, n.strokeStyle = q, n.lineWidth = $, n.beginPath(), n.roundRect(-20 / 2, -8 / 2, i, o, s), n.fill(), n.stroke(), n.restore();
451
+ }
452
+ var Qe = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE4Ljc1IDQuMzc1djMuNzVhLjYyNS42MjUgMCAwIDEtLjYyNS42MjVoLTMuNzVhLjYyNS42MjUgMCAwIDEgMC0xLjI1aDIuMTRsLTIuMDc3LTEuOTAzLS4wMi0uMDE5YTYuMjUgNi4yNSAwIDEgMC0uMTMgOC45NjcuNjI2LjYyNiAwIDAgMSAuODYuOTA5QTcuNDU2IDcuNDU2IDAgMCAxIDEwIDE3LjVoLS4xMDNhNy41IDcuNSAwIDEgMSA1LjM5Ni0xMi44MTJMMTcuNSA2LjcwM1Y0LjM3NWEuNjI1LjYyNSAwIDAgMSAxLjI1IDBaIi8+PC9zdmc+", Ce = new Image();
453
+ Ce.src = Qe;
454
+ function Ke(n, e, t, a, r) {
455
+ var i = J, o = i / 2;
456
+ n.save(), n.translate(e, t), n.rotate(x.degreesToRadians(r.angle)), n.fillStyle = Xe, n.beginPath(), n.arc(0, 0, o, 0, 2 * Math.PI), n.fill(), n.drawImage(Ce, -16 / 2, -16 / 2, o, o), n.restore();
457
+ }
458
+ var Je = {
459
+ // Угловые точки
460
+ tl: {
461
+ render: z,
462
+ sizeX: b,
463
+ sizeY: b,
464
+ offsetX: 0,
465
+ offsetY: 0
466
+ },
467
+ tr: {
468
+ render: z,
469
+ sizeX: b,
470
+ sizeY: b,
471
+ offsetX: 0,
472
+ offsetY: 0
473
+ },
474
+ bl: {
475
+ render: z,
476
+ sizeX: b,
477
+ sizeY: b,
478
+ offsetX: 0,
479
+ offsetY: 0
480
+ },
481
+ br: {
482
+ render: z,
483
+ sizeX: b,
484
+ sizeY: b,
485
+ offsetX: 0,
486
+ offsetY: 0
487
+ },
488
+ // Середина вертикалей
489
+ ml: {
490
+ render: le,
491
+ sizeX: _,
492
+ sizeY: X,
493
+ offsetX: 0,
494
+ offsetY: 0
495
+ },
496
+ mr: {
497
+ render: le,
498
+ sizeX: _,
499
+ sizeY: X,
500
+ offsetX: 0,
501
+ offsetY: 0
502
+ },
503
+ // Середина горизонталей
504
+ mt: {
505
+ render: ge,
506
+ sizeX: Q,
507
+ sizeY: K,
508
+ offsetX: 0,
509
+ offsetY: 0
510
+ },
511
+ mb: {
512
+ render: ge,
513
+ sizeX: Q,
514
+ sizeY: K,
515
+ offsetX: 0,
516
+ offsetY: 0
517
+ },
518
+ // Специальный «rotate» контрол
519
+ mtr: {
520
+ render: Ke,
521
+ sizeX: J,
522
+ sizeY: J,
523
+ offsetX: 0,
524
+ offsetY: -32
525
+ }
526
+ };
527
+ class $e {
528
+ static apply() {
529
+ var e = Le.createObjectDefaultControls();
530
+ Object.entries(Je).forEach((t) => {
531
+ var [a, r] = t;
532
+ Object.assign(e[a], {
533
+ render: r.render,
534
+ sizeX: r.sizeX,
535
+ sizeY: r.sizeY,
536
+ offsetX: r.offsetX,
537
+ offsetY: r.offsetY
538
+ });
539
+ }), Oe.ownDefaults.controls = e;
540
+ }
541
+ }
542
+ var qe = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNi44NzUgMi41YS42MjUuNjI1IDAgMCAwLS42MjUuNjI0VjYuMjVIMy4xMjVhLjYyNS42MjUgMCAwIDAtLjYyNS42MjV2MTBjMCAuMzQ1LjI4LjYyNS42MjUuNjI1aDEwYy4zNDUgMCAuNjI1LS4yOC42MjUtLjYyNXYtMy4xMjZoMy4xMjVjLjM0NSAwIC42MjUtLjI4LjYyNS0uNjI1di0xMGEuNjI1LjYyNSAwIDAgMC0uNjI1LS42MjVoLTEwWm02Ljg3NSAxMGgyLjVWMy43NUg3LjV2Mi41aDUuNjI1Yy4zNDUgMCAuNjI1LjI4LjYyNS42MjV2NS42MjRabS0xMCAzLjc1VjcuNWg4Ljc1djguNzVIMy43NVoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==", et = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMi41IDcuNWMwLS42OS41Ni0xLjI1IDEuMjUtMS4yNWgxMi41Yy42OSAwIDEuMjUuNTYgMS4yNSAxLjI1djguNzVjMCAuNjktLjU2IDEuMjUtMS4yNSAxLjI1SDMuNzVjLS42OSAwLTEuMjUtLjU2LTEuMjUtMS4yNVY3LjVabTEzLjc1IDBIMy43NXY4Ljc1aDEyLjVWNy41WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTAgMS44NzVhMi4xODggMi4xODggMCAwIDAtMi4xODggMi4xODh2Mi44MTJhLjYyNS42MjUgMCAxIDEtMS4yNSAwVjQuMDYyYTMuNDM3IDMuNDM3IDAgMSAxIDYuODc1IDB2Mi44MTNhLjYyNS42MjUgMCAxIDEtMS4yNSAwVjQuMDYyQTIuMTg4IDIuMTg4IDAgMCAwIDEwIDEuODc2WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTEwIDEyLjgxM2EuOTM3LjkzNyAwIDEgMCAwLTEuODc1LjkzNy45MzcgMCAwIDAgMCAxLjg3NFoiLz48L3N2Zz4=", tt = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE2LjI1IDYuMjVINy41VjQuMzc1YTIuNSAyLjUgMCAwIDEgMi41LTIuNWMxLjIgMCAyLjI4MS44NiAyLjUxMiAyYS42MjUuNjI1IDAgMCAwIDEuMjI2LS4yNWMtLjM1NC0xLjczOC0xLjkyNS0zLTMuNzM4LTNhMy43NTQgMy43NTQgMCAwIDAtMy43NSAzLjc1VjYuMjVoLTIuNUExLjI1IDEuMjUgMCAwIDAgMi41IDcuNXY4Ljc1YTEuMjUgMS4yNSAwIDAgMCAxLjI1IDEuMjVoMTIuNWExLjI1IDEuMjUgMCAwIDAgMS4yNS0xLjI1VjcuNWExLjI1IDEuMjUgMCAwIDAtMS4yNS0xLjI1Wm0wIDEwSDMuNzVWNy41aDEyLjV2OC43NVptLTUuMzEzLTQuMzc1YS45MzcuOTM3IDAgMSAxLTEuODc0IDAgLjkzNy45MzcgMCAwIDEgMS44NzQgMFoiLz48L3N2Zz4K", at = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTIuNSA4LjEyNSAxMCAxMi41bDcuNS00LjM3NUwxMCAzLjc1IDIuNSA4LjEyNVoiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik05LjY4NSAzLjIxYS42MjUuNjI1IDAgMCAxIC42MyAwbDcuNSA0LjM3NWEuNjI1LjYyNSAwIDAgMSAwIDEuMDhsLTcuNSA0LjM3NWEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtNy41LTQuMzc1YS42MjUuNjI1IDAgMCAxIDAtMS4wOGw3LjUtNC4zNzVaTTMuNzQgOC4xMjUgMTAgMTEuNzc2bDYuMjYtMy42NTFMMTAgNC40NzQgMy43NCA4LjEyNVoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTUuNCA5LjQ2YS42MjUuNjI1IDAgMCAxIC42MyAwTDEwIDExLjc3NmwzLjk3LTIuMzE2YS42MjUuNjI1IDAgMCAxIC42MyAwbDMuMjE1IDEuODc1YS42MjUuNjI1IDAgMCAxIDAgMS4wOGwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEgMC0xLjA4TDUuNCA5LjQ2Wm0tMS42NiAyLjQxNUwxMCAxNS41MjZsNi4yNi0zLjY1MS0xLjk3NC0xLjE1MS0zLjk3MSAyLjMxNmEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtMy45Ny0yLjMxNi0xLjk3NSAxLjE1MVoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==", rt = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNOS42ODUgMy4yMWEuNjI1LjYyNSAwIDAgMSAuNjMgMGw3LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEgMCAxLjA4bC03LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEtLjYzIDBsLTcuNS00LjM3NWEuNjI1LjYyNSAwIDAgMSAwLTEuMDhsNy41LTQuMzc1Wk0zLjc0IDguMTI1IDEwIDExLjc3Nmw2LjI2LTMuNjUxTDEwIDQuNDc0IDMuNzQgOC4xMjVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik01LjcxNCAxMCAxMCAxMi41bDQuMjg2LTIuNSAzLjIxNCAxLjg3NUwxMCAxNi4yNWwtNy41LTQuMzc1TDUuNzE0IDEwWiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNS40IDkuNDZhLjYyNS42MjUgMCAwIDEgLjYzIDBMMTAgMTEuNzc2bDMuOTctMi4zMTZhLjYyNS42MjUgMCAwIDEgLjYzIDBsMy4yMTUgMS44NzVhLjYyNS42MjUgMCAwIDEgMCAxLjA4bC03LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEtLjYzIDBsLTcuNS00LjM3NWEuNjI1LjYyNSAwIDAgMSAwLTEuMDhMNS40IDkuNDZabS0xLjY2IDIuNDE1TDEwIDE1LjUyNmw2LjI2LTMuNjUxLTEuOTc0LTEuMTUxLTMuOTcxIDIuMzE2YS42MjUuNjI1IDAgMCAxLS42MyAwbC0zLjk3LTIuMzE2LTEuOTc1IDEuMTUxWiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+", it = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0ibTIuNSA2LjI1IDcuNSA0LjM3NSA3LjUtNC4zNzVMMTAgMS44NzUgMi41IDYuMjVaIi8+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNOS42ODUgMS4zMzVhLjYyNS42MjUgMCAwIDEgLjYzIDBsNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxIDAgMS4wOGwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEgMC0xLjA4bDcuNS00LjM3NVpNMy43NCA2LjI1IDEwIDkuOTAxbDYuMjYtMy42NTFMMTAgMi41OTkgMy43NCA2LjI1WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNS40IDExLjMzNWEuNjI1LjYyNSAwIDAgMSAuNjMgMEwxMCAxMy42NTFsMy45Ny0yLjMxNmEuNjI1LjYyNSAwIDAgMSAuNjMgMGwzLjIxNSAxLjg3NWEuNjI1LjYyNSAwIDAgMSAwIDEuMDhsLTcuNSA0LjM3NWEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtNy41LTQuMzc1YS42MjUuNjI1IDAgMCAxIDAtMS4wOEw1LjQgMTEuMzM1Wk0zLjc0IDEzLjc1IDEwIDE3LjQwMWw2LjI2LTMuNjUxLTEuOTc0LTEuMTUxLTMuOTcxIDIuMzE2YS42MjUuNjI1IDAgMCAxLS42MyAwbC0zLjk3LTIuMzE2TDMuNzQgMTMuNzVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik01LjQgNy41ODVhLjYyNS42MjUgMCAwIDEgLjYzIDBMMTAgOS45MDFsMy45Ny0yLjMxNmEuNjI1LjYyNSAwIDAgMSAuNjMgMGwzLjIxNSAxLjg3NWEuNjI1LjYyNSAwIDAgMSAwIDEuMDhsLTcuNSA0LjM3NWEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtNy41LTQuMzc1YS42MjUuNjI1IDAgMCAxIDAtMS4wOEw1LjQgNy41ODVaTTMuNzQgMTAgMTAgMTMuNjUxIDE2LjI2IDEwbC0xLjk3NC0xLjE1MS0zLjk3MSAyLjMxNmEuNjI1LjYyNSAwIDAgMS0uNjMgMGwtMy45Ny0yLjMxNkwzLjc0IDEwWiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+", nt = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMS45NiAxMy40MzVhLjYyNS42MjUgMCAwIDEgLjg1NS0uMjI1TDEwIDE3LjQwMWw3LjE4NS00LjE5YS42MjUuNjI1IDAgMCAxIC42MyAxLjA3OWwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEtLjIyNS0uODU1Wk05LjY4NSAxLjMzNWEuNjI1LjYyNSAwIDAgMSAuNjMgMGw3LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEgMCAxLjA4bC03LjUgNC4zNzVhLjYyNS42MjUgMCAwIDEtLjYzIDBsLTcuNS00LjM3NWEuNjI1LjYyNSAwIDAgMSAwLTEuMDhsNy41LTQuMzc1Wk0zLjc0IDYuMjUgMTAgOS45MDFsNi4yNi0zLjY1MUwxMCAyLjU5OSAzLjc0IDYuMjVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Im01LjcxNCAxMS44NzUgNC4yODYgMi41IDQuMjg2LTIuNUwxNy41IDEzLjc1IDEwIDE4LjEyNSAyLjUgMTMuNzVsMy4yMTQtMS44NzVaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik01LjQgMTEuMzM1YS42MjUuNjI1IDAgMCAxIC42MyAwTDEwIDEzLjY1MWwzLjk3LTIuMzE2YS42MjUuNjI1IDAgMCAxIC42MyAwbDMuMjE1IDEuODc1YS42MjUuNjI1IDAgMCAxIDAgMS4wOGwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEgMC0xLjA4TDUuNCAxMS4zMzVaTTMuNzQgMTMuNzUgMTAgMTcuNDAxbDYuMjYtMy42NTEtMS45NzQtMS4xNTEtMy45NzEgMi4zMTZhLjYyNS42MjUgMCAwIDEtLjYzIDBsLTMuOTctMi4zMTZMMy43NCAxMy43NVoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTUuNCA3LjU4NWEuNjI1LjYyNSAwIDAgMSAuNjMgMEwxMCA5LjkwMWwzLjk3LTIuMzE2YS42MjUuNjI1IDAgMCAxIC42MyAwbDMuMjE1IDEuODc1YS42MjUuNjI1IDAgMCAxIDAgMS4wOGwtNy41IDQuMzc1YS42MjUuNjI1IDAgMCAxLS42MyAwbC03LjUtNC4zNzVhLjYyNS42MjUgMCAwIDEgMC0xLjA4TDUuNCA3LjU4NVpNMy43NCAxMCAxMCAxMy42NTEgMTYuMjYgMTBsLTEuOTc0LTEuMTUxLTMuOTcxIDIuMzE2YS42MjUuNjI1IDAgMCAxLS42MyAwbC0zLjk3LTIuMzE2TDMuNzQgMTBaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=", ot = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI0VDNEU0MCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNOC4xMjUgMS4yNUExLjg3NSAxLjg3NSAwIDAgMCA2LjI1IDMuMTI1di42MjVIMy4xMjVhLjYyNS42MjUgMCAwIDAgMCAxLjI1aC42MjV2MTEuMjVBMS4yNSAxLjI1IDAgMCAwIDUgMTcuNWgxMGExLjI1IDEuMjUgMCAwIDAgMS4yNS0xLjI1VjVoLjYyNWEuNjI1LjYyNSAwIDAgMCAwLTEuMjVIMTMuNzV2LS42MjVhMS44NzUgMS44NzUgMCAwIDAtMS44NzUtMS44NzVoLTMuNzVabTQuMzc1IDIuNXYtLjYyNWEuNjI1LjYyNSAwIDAgMC0uNjI1LS42MjVoLTMuNzVhLjYyNS42MjUgMCAwIDAtLjYyNS42MjV2LjYyNWg1Wk01IDE2LjI1VjVoMTB2MTEuMjVINVpNOC4xMjUgNy41Yy4zNDUgMCAuNjI1LjI4LjYyNS42MjV2NWEuNjI1LjYyNSAwIDEgMS0xLjI1IDB2LTVjMC0uMzQ1LjI4LS42MjUuNjI1LS42MjVabTQuMzc1IDUuNjI1di01YS42MjUuNjI1IDAgMCAwLTEuMjUgMHY1YS42MjUuNjI1IDAgMSAwIDEuMjUgMFoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==";
543
+ function he(n, e, t, a, r, i, o) {
544
+ try {
545
+ var s = n[i](o), c = s.value;
546
+ } catch (d) {
547
+ return void t(d);
548
+ }
549
+ s.done ? e(c) : Promise.resolve(c).then(a, r);
550
+ }
551
+ function st(n) {
552
+ return function() {
553
+ var e = this, t = arguments;
554
+ return new Promise(function(a, r) {
555
+ var i = n.apply(e, t);
556
+ function o(c) {
557
+ he(i, a, r, o, s, "next", c);
558
+ }
559
+ function s(c) {
560
+ he(i, a, r, o, s, "throw", c);
561
+ }
562
+ o(void 0);
563
+ });
564
+ };
565
+ }
566
+ const E = {
567
+ style: {
568
+ position: "absolute",
569
+ display: "none",
570
+ background: "#2B2D33",
571
+ borderRadius: "8px",
572
+ padding: "0 8px",
573
+ height: "32px",
574
+ gap: "10px",
575
+ zIndex: 10,
576
+ alignItems: "center"
577
+ },
578
+ btnStyle: {
579
+ background: "transparent",
580
+ border: "none",
581
+ display: "flex",
582
+ alignItems: "center",
583
+ justifyContent: "center",
584
+ height: "20px",
585
+ width: "20px",
586
+ cursor: "pointer",
587
+ transition: "background-color 0.2s ease, transform 0.1s ease",
588
+ transform: "scale(1)"
589
+ },
590
+ btnHover: {
591
+ backgroundColor: "rgba(255,255,255,0.15)",
592
+ borderRadius: "50%",
593
+ transform: "scale(1.1)"
594
+ },
595
+ toolbarClass: "fabric-editor-toolbar",
596
+ btnClass: "fabric-editor-toolbar-btn",
597
+ lockedActions: [{
598
+ name: "Разблокировать",
599
+ handle: "unlock"
600
+ }],
601
+ actions: [{
602
+ name: "Создать копию",
603
+ handle: "copyPaste"
604
+ }, {
605
+ name: "Заблокировать",
606
+ handle: "lock"
607
+ }, {
608
+ name: "На передний план",
609
+ handle: "bringToFront"
610
+ }, {
611
+ name: "На задний план",
612
+ handle: "sendToBack"
613
+ }, {
614
+ name: "На один уровень вверх",
615
+ handle: "bringForward"
616
+ }, {
617
+ name: "На один уровень вниз",
618
+ handle: "sendBackwards"
619
+ }, {
620
+ name: "Удалить",
621
+ handle: "delete"
622
+ }],
623
+ offsetTop: 50,
624
+ icons: {
625
+ copyPaste: qe,
626
+ delete: ot,
627
+ lock: et,
628
+ unlock: tt,
629
+ bringToFront: it,
630
+ sendToBack: nt,
631
+ bringForward: at,
632
+ sendBackwards: rt
633
+ },
634
+ handlers: {
635
+ copyPaste: function() {
636
+ var n = st(function* (t) {
637
+ yield t.clipboardManager.copy(), yield t.clipboardManager.paste();
638
+ });
639
+ function e(t) {
640
+ return n.apply(this, arguments);
641
+ }
642
+ return e;
643
+ }(),
644
+ delete: (n) => {
645
+ n.deletionManager.deleteSelectedObjects();
646
+ },
647
+ lock: (n) => {
648
+ n.objectLockManager.lockObject();
649
+ },
650
+ unlock: (n) => {
651
+ n.objectLockManager.unlockObject();
652
+ },
653
+ bringForward: (n) => {
654
+ n.layerManager.bringForward();
655
+ },
656
+ bringToFront: (n) => {
657
+ n.layerManager.bringToFront();
658
+ },
659
+ sendToBack: (n) => {
660
+ n.layerManager.sendToBack();
661
+ },
662
+ sendBackwards: (n) => {
663
+ n.layerManager.sendBackwards();
664
+ }
665
+ }
666
+ };
667
+ function ve(n, e) {
668
+ var t = Object.keys(n);
669
+ if (Object.getOwnPropertySymbols) {
670
+ var a = Object.getOwnPropertySymbols(n);
671
+ e && (a = a.filter(function(r) {
672
+ return Object.getOwnPropertyDescriptor(n, r).enumerable;
673
+ })), t.push.apply(t, a);
674
+ }
675
+ return t;
676
+ }
677
+ function M(n) {
678
+ for (var e = 1; e < arguments.length; e++) {
679
+ var t = arguments[e] != null ? arguments[e] : {};
680
+ e % 2 ? ve(Object(t), !0).forEach(function(a) {
681
+ ct(n, a, t[a]);
682
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(n, Object.getOwnPropertyDescriptors(t)) : ve(Object(t)).forEach(function(a) {
683
+ Object.defineProperty(n, a, Object.getOwnPropertyDescriptor(t, a));
684
+ });
685
+ }
686
+ return n;
687
+ }
688
+ function ct(n, e, t) {
689
+ return (e = ut(e)) in n ? Object.defineProperty(n, e, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : n[e] = t, n;
690
+ }
691
+ function ut(n) {
692
+ var e = dt(n, "string");
693
+ return typeof e == "symbol" ? e : e + "";
694
+ }
695
+ function dt(n, e) {
696
+ if (typeof n != "object" || !n) return n;
697
+ var t = n[Symbol.toPrimitive];
698
+ if (t !== void 0) {
699
+ var a = t.call(n, e);
700
+ if (typeof a != "object") return a;
701
+ throw new TypeError("@@toPrimitive must return a primitive value.");
702
+ }
703
+ return (e === "string" ? String : Number)(n);
704
+ }
705
+ class lt {
706
+ /**
707
+ * @param {object} options
708
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
709
+ */
710
+ constructor(e) {
711
+ var {
712
+ editor: t
713
+ } = e;
714
+ if (this.options = t.options, !!this.options.showToolbar) {
715
+ this.editor = t, this.canvas = t.canvas;
716
+ var a = this.options.toolbar || {};
717
+ this.config = M(M(M({}, E), a), {}, {
718
+ style: M(M({}, E.style), a.style || {}),
719
+ btnStyle: M(M({}, E.btnStyle), a.btnStyle || {}),
720
+ icons: M(M({}, E.icons), a.icons || {}),
721
+ handlers: M(M({}, E.handlers), a.handlers || {})
722
+ }), this.currentTarget = null, this.currentLocked = null, this.isTransforming = !1, this._onMouseDown = this._handleMouseDown.bind(this), this._onObjectMoving = this._startTransform.bind(this), this._onObjectScaling = this._startTransform.bind(this), this._onObjectRotating = this._startTransform.bind(this), this._onMouseUp = this._endTransform.bind(this), this._onObjectModified = this._endTransform.bind(this), this._onSelectionChange = this._updateToolbar.bind(this), this._onSelectionClear = () => {
723
+ this.el.style.display = "none";
724
+ }, this._createDOM(), this._bindEvents();
725
+ }
726
+ }
727
+ /**
728
+ * Создаёт DOM элемент панели инструментов и добавляет его в canvas
729
+ * @private
730
+ */
731
+ _createDOM() {
732
+ var {
733
+ style: e
734
+ } = this.config;
735
+ this.el = document.createElement("div"), Object.assign(this.el.style, e), this.canvas.wrapperEl.appendChild(this.el), this._onBtnOver = (t) => {
736
+ var a = t.target.closest("button");
737
+ a && Object.assign(a.style, this.config.btnHover);
738
+ }, this._onBtnOut = (t) => {
739
+ var a = t.target.closest("button");
740
+ a && Object.assign(a.style, this.config.btnStyle);
741
+ }, this.el.addEventListener("mouseover", this._onBtnOver), this.el.addEventListener("mouseout", this._onBtnOut);
742
+ }
743
+ /**
744
+ * Отрисовывает кнопки панели инструментов
745
+ * @private
746
+ * @param {array} actions - массив действий для отрисовки
747
+ * @param {string} actions[].name - название действия
748
+ * @param {string} actions[].handle - название обработчика
749
+ */
750
+ _renderButtons(e) {
751
+ var t = this;
752
+ this.el.innerHTML = "";
753
+ var a = function() {
754
+ var {
755
+ name: o,
756
+ handle: s
757
+ } = r, {
758
+ icons: c,
759
+ btnStyle: d,
760
+ handlers: l
761
+ } = t.config, u = document.createElement("button");
762
+ u.innerHTML = c[s] ? '<img src="'.concat(c[s], '" title="').concat(o, '" />') : o, Object.assign(u.style, d), u.onclick = () => {
763
+ var g;
764
+ return (g = l[s]) === null || g === void 0 ? void 0 : g.call(l, t.editor);
765
+ }, t.el.appendChild(u);
766
+ };
767
+ for (var r of e)
768
+ a();
769
+ }
770
+ /**
771
+ * Привязывает события к canvas
772
+ * @private
773
+ */
774
+ _bindEvents() {
775
+ this.canvas.on("mouse:down", this._onMouseDown), this.canvas.on("object:moving", this._onObjectMoving), this.canvas.on("object:scaling", this._onObjectScaling), this.canvas.on("object:rotating", this._onObjectRotating), this.canvas.on("mouse:up", this._onMouseUp), this.canvas.on("object:modified", this._onObjectModified), this.canvas.on("selection:created", this._onSelectionChange), this.canvas.on("selection:updated", this._onSelectionChange), this.canvas.on("selection:changed", this._onSelectionChange), this.canvas.on("after:render", this._onSelectionChange), this.canvas.on("selection:cleared", this._onSelectionClear);
776
+ }
777
+ /**
778
+ * На время трансформации скрываем тулбар
779
+ * @private
780
+ * @param {Object} opt - объект события
781
+ */
782
+ _handleMouseDown(e) {
783
+ var t;
784
+ (t = e.transform) !== null && t !== void 0 && t.actionPerformed && this._startTransform();
785
+ }
786
+ /**
787
+ * Начало трансформации объекта
788
+ * @private
789
+ */
790
+ _startTransform() {
791
+ this.isTransforming = !0, this.el.style.display = "none";
792
+ }
793
+ /**
794
+ * Завершение трансформации объекта
795
+ * @private
796
+ */
797
+ _endTransform() {
798
+ this.isTransforming = !1, this._updatePos();
799
+ }
800
+ /**
801
+ * Обновляет панель инструментов в зависимости от выделенного объекта и его состояния
802
+ * @private
803
+ */
804
+ _updateToolbar() {
805
+ if (!this.isTransforming) {
806
+ var e = this.canvas.getActiveObject();
807
+ if (!e) {
808
+ this.el.style.display = "none", this.currentTarget = null;
809
+ return;
810
+ }
811
+ var t = !!e.locked;
812
+ if (e !== this.currentTarget || t !== this.currentLocked) {
813
+ this.currentTarget = e, this.currentLocked = t;
814
+ var a = t ? this.config.lockedActions : this.config.actions;
815
+ this._renderButtons(a);
816
+ }
817
+ this._updatePos();
818
+ }
819
+ }
820
+ /**
821
+ * Обновляет позицию панели инструментов в зависимости от положения выделенного объекта
822
+ * @private
823
+ */
824
+ _updatePos() {
825
+ if (!this.isTransforming) {
826
+ var e = this.canvas.getActiveObject();
827
+ if (!e) {
828
+ this.el.style.display = "none";
829
+ return;
830
+ }
831
+ var {
832
+ el: t,
833
+ config: a,
834
+ canvas: r
835
+ } = this;
836
+ e.setCoords();
837
+ var i = r.getZoom(), [, , , , o, s] = r.viewportTransform, {
838
+ x: c
839
+ } = e.getCenterPoint(), {
840
+ top: d,
841
+ height: l
842
+ } = e.getBoundingRect(!1, !0), u = c * i + o, g = u - t.offsetWidth / 2, h = (d + l) * i + s + a.offsetTop;
843
+ Object.assign(t.style, {
844
+ left: "".concat(g, "px"),
845
+ top: "".concat(h, "px"),
846
+ display: "flex"
847
+ });
848
+ }
849
+ }
850
+ /**
851
+ * Удаляет слушатели событий и DOM элемент панели инструментов
852
+ */
853
+ destroy() {
854
+ this.el.removeEventListener("mouseover", this._onBtnOver), this.el.removeEventListener("mouseout", this._onBtnOut), this.canvas.off("mouse:down", this._onMouseDown), this.canvas.off("object:moving", this._onObjectMoving), this.canvas.off("object:scaling", this._onObjectScaling), this.canvas.off("object:rotating", this._onObjectRotating), this.canvas.off("mouse:up", this._onMouseUp), this.canvas.off("object:modified", this._onObjectModified), this.canvas.off("selection:created", this._onSelectionChange), this.canvas.off("selection:updated", this._onSelectionChange), this.canvas.off("selection:changed", this._onSelectionChange), this.canvas.off("after:render", this._onSelectionChange), this.canvas.off("selection:cleared", this._onSelectionClear), this.el.remove();
855
+ }
856
+ }
857
+ function me(n, e, t, a, r, i, o) {
858
+ try {
859
+ var s = n[i](o), c = s.value;
860
+ } catch (d) {
861
+ return void t(d);
862
+ }
863
+ s.done ? e(c) : Promise.resolve(c).then(a, r);
864
+ }
865
+ function R(n) {
866
+ return function() {
867
+ var e = this, t = arguments;
868
+ return new Promise(function(a, r) {
869
+ var i = n.apply(e, t);
870
+ function o(c) {
871
+ me(i, a, r, o, s, "next", c);
872
+ }
873
+ function s(c) {
874
+ me(i, a, r, o, s, "throw", c);
875
+ }
876
+ o(void 0);
877
+ });
878
+ };
879
+ }
880
+ class gt {
881
+ /**
882
+ * @param {object} options
883
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
884
+ */
885
+ constructor(e) {
886
+ var {
887
+ editor: t
888
+ } = e;
889
+ this.editor = t, this.canvas = t.canvas, this._historySuspendCount = 0, this.baseState = null, this.patches = [], this.currentIndex = 0, this.maxHistoryLength = t.options.maxHistoryLength, this._createDiffPatcher();
890
+ }
891
+ /** Проверка, нужно ли пропускать сохранение истории */
892
+ get skipHistory() {
893
+ return this._historySuspendCount > 0;
894
+ }
895
+ _createDiffPatcher() {
896
+ this.diffPatcher = We({
897
+ objectHash(e) {
898
+ return [e.id, e.format, e.locked, e.left, e.top, e.width, e.height, e.flipX, e.flipY, e.scaleX, e.scaleY, e.angle, e.opacity].join("-");
899
+ },
900
+ arrays: {
901
+ detectMove: !0,
902
+ includeValueOnMove: !1
903
+ },
904
+ textDiff: {
905
+ minLength: 60
906
+ }
907
+ });
908
+ }
909
+ /** Увеличить счётчик приостановки истории */
910
+ suspendHistory() {
911
+ this._historySuspendCount += 1;
912
+ }
913
+ /** Уменьшить счётчик приостановки истории */
914
+ resumeHistory() {
915
+ this._historySuspendCount = Math.max(0, this._historySuspendCount - 1);
916
+ }
917
+ /**
918
+ * Получаем полное состояние, применяя все диффы к базовому состоянию.
919
+ */
920
+ getFullState() {
921
+ for (var {
922
+ baseState: e,
923
+ currentIndex: t,
924
+ patches: a
925
+ } = this, r = JSON.parse(JSON.stringify(e)), i = 0; i < t; i += 1)
926
+ r = this.diffPatcher.patch(r, a[i]);
927
+ return console.log("getFullState state", r), r;
928
+ }
929
+ /**
930
+ * Сохраняем текущее состояние в виде диффа от последнего сохранённого полного состояния.
931
+ */
932
+ saveState() {
933
+ if (console.log("saveState"), !this.skipHistory) {
934
+ console.time("saveState");
935
+ var e = this.canvas.toDatalessObject(["selectable", "evented", "id", "format", "width", "height", "locked"]);
936
+ if (console.timeEnd("saveState"), !this.baseState) {
937
+ this.baseState = e, this.patches = [], this.currentIndex = 0, console.log("Базовое состояние сохранено.");
938
+ return;
939
+ }
940
+ var t = this.getFullState(), a = this.diffPatcher.diff(t, e);
941
+ if (!a) {
942
+ console.log("Нет изменений для сохранения.");
943
+ return;
944
+ }
945
+ console.log("baseState", this.baseState), this.currentIndex < this.patches.length && this.patches.splice(this.currentIndex), console.log("diff", a), this.patches.push(a), this.currentIndex += 1, this.patches.length > this.maxHistoryLength && (this.baseState = this.diffPatcher.patch(this.baseState, this.patches[0]), this.patches.shift(), this.currentIndex -= 1), console.log("Состояние сохранено. Текущий индекс истории:", this.currentIndex);
946
+ }
947
+ }
948
+ /**
949
+ * Функция загрузки состояния в канвас.
950
+ * @param {object} fullState - полное состояние канваса
951
+ * @fires editor:history-state-loaded
952
+ */
953
+ loadStateFromFullState(e) {
954
+ var t = this;
955
+ return R(function* () {
956
+ if (e) {
957
+ console.log("loadStateFromFullState fullState", e), yield t.canvas.loadFromJSON(e);
958
+ var a = t.canvas.getObjects().find((i) => i.id === "montage-area");
959
+ a && (t.editor.montageArea = a);
960
+ var r = t.canvas.getObjects().find((i) => i.id === "overlay-mask");
961
+ r && (t.editor.interactionBlocker.overlayMask = r, t.editor.interactionBlocker.overlayMask.visible = !1), t.canvas.renderAll(), t.canvas.fire("editor:history-state-loaded");
962
+ }
963
+ })();
964
+ }
965
+ /**
966
+ * Undo – отмена последнего действия, восстанавливая состояние по накопленным диффам.
967
+ * @fires editor:undo
968
+ */
969
+ undo() {
970
+ var e = this;
971
+ return R(function* () {
972
+ if (!e.skipHistory) {
973
+ if (e.currentIndex <= 0) {
974
+ console.log("Нет предыдущих состояний для отмены.");
975
+ return;
976
+ }
977
+ e.suspendHistory();
978
+ try {
979
+ e.currentIndex -= 1;
980
+ var t = e.getFullState();
981
+ yield e.loadStateFromFullState(t), console.log("Undo выполнен. Текущий индекс истории:", e.currentIndex), e.canvas.fire("editor:undo");
982
+ } catch (a) {
983
+ console.error("undo. Ошибка отмены действия: ", a), e.canvas.fire("editor:error", {
984
+ message: "Ошибка отмены действия: ".concat(a.message)
985
+ });
986
+ } finally {
987
+ e.resumeHistory();
988
+ }
989
+ }
990
+ })();
991
+ }
992
+ /**
993
+ * Redo – повтор ранее отменённого действия.
994
+ * @fires editor:redo
995
+ */
996
+ redo() {
997
+ var e = this;
998
+ return R(function* () {
999
+ if (!e.skipHistory) {
1000
+ if (e.currentIndex >= e.patches.length) {
1001
+ console.log("Нет состояний для повтора.");
1002
+ return;
1003
+ }
1004
+ e.suspendHistory();
1005
+ try {
1006
+ e.currentIndex += 1;
1007
+ var t = e.getFullState();
1008
+ console.log("fullState", t), yield e.loadStateFromFullState(t), console.log("Redo выполнен. Текущий индекс истории:", e.currentIndex), e.canvas.fire("editor:redo");
1009
+ } catch (a) {
1010
+ console.error("redo. Ошибка повтора действия: ", a), e.canvas.fire("editor:error", {
1011
+ message: "Ошибка повтора действия: ".concat(a.message)
1012
+ });
1013
+ } finally {
1014
+ e.resumeHistory();
1015
+ }
1016
+ }
1017
+ })();
1018
+ }
1019
+ }
1020
+ function W(n) {
1021
+ var {
1022
+ montageArea: e,
1023
+ imageObject: t,
1024
+ scaleType: a = "contain"
1025
+ } = n;
1026
+ if (!e || !t) return 1;
1027
+ var r = e.width, i = e.height, {
1028
+ width: o,
1029
+ height: s
1030
+ } = t;
1031
+ return a === "contain" || a === "image-contain" ? Math.min(r / o, i / s) : a === "cover" || a === "image-cover" ? Math.max(r / o, i / s) : 1;
1032
+ }
1033
+ function ht() {
1034
+ var n = document.createElement("canvas");
1035
+ n.width = 20, n.height = 20;
1036
+ var e = n.getContext("2d");
1037
+ return e.fillStyle = "#ddd", e.fillRect(0, 0, 40, 40), e.fillStyle = "#ccc", e.fillRect(0, 0, 10, 10), e.fillRect(10, 10, 10, 10), new Te({
1038
+ source: n,
1039
+ repeat: "repeat"
1040
+ });
1041
+ }
1042
+ var vt = 0.1, mt = 2, ft = 0.1, Mt = 90, Z = 16, B = 16, N = 4096, D = 4096;
1043
+ function fe(n, e, t, a, r, i, o) {
1044
+ try {
1045
+ var s = n[i](o), c = s.value;
1046
+ } catch (d) {
1047
+ return void t(d);
1048
+ }
1049
+ s.done ? e(c) : Promise.resolve(c).then(a, r);
1050
+ }
1051
+ function Y(n) {
1052
+ return function() {
1053
+ var e = this, t = arguments;
1054
+ return new Promise(function(a, r) {
1055
+ var i = n.apply(e, t);
1056
+ function o(c) {
1057
+ fe(i, a, r, o, s, "next", c);
1058
+ }
1059
+ function s(c) {
1060
+ fe(i, a, r, o, s, "throw", c);
1061
+ }
1062
+ o(void 0);
1063
+ });
1064
+ };
1065
+ }
1066
+ class L {
1067
+ /**
1068
+ * @param {object} options
1069
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
1070
+ */
1071
+ constructor(e) {
1072
+ var {
1073
+ editor: t
1074
+ } = e;
1075
+ this.editor = t, this.options = t.options, this._createdBlobUrls = [];
1076
+ }
1077
+ /**
1078
+ * Импорт изображения
1079
+ * @param {Object} options
1080
+ * @param {File|string} [options.source] - URL изображения или объект File
1081
+ * @param {String} [options.scale] - Если изображение не вписывается в допустимые размеры, то как масштабировать:
1082
+ * 'image-contain' - скейлит картинку, чтобы она вписалась в монтажную область
1083
+ * 'image-cover' - скейлит картинку, чтобы она вписалась в монтажную область
1084
+ * 'scale-montage' - Обновляет backstore-резолюцию монтажной области (масштабирует
1085
+ * экспортный размер канваса под размер изображения)
1086
+ * @param {Boolean} [options.withoutSave] - Не сохранять в историю изменений
1087
+ */
1088
+ importImage(e) {
1089
+ var t = this;
1090
+ return Y(function* () {
1091
+ var {
1092
+ source: a,
1093
+ scale: r = "image-".concat(t.options.scaleType),
1094
+ withoutSave: i = !1,
1095
+ contentType: o = "image/png"
1096
+ } = e;
1097
+ if (a) {
1098
+ var {
1099
+ canvas: s,
1100
+ montageArea: c,
1101
+ transformManager: d,
1102
+ historyManager: l
1103
+ } = t.editor;
1104
+ l.suspendHistory();
1105
+ try {
1106
+ var u, g;
1107
+ if (a instanceof File)
1108
+ u = URL.createObjectURL(a);
1109
+ else if (typeof a == "string") {
1110
+ var h = yield fetch(a, {
1111
+ mode: "cors"
1112
+ }), f = yield h.blob({
1113
+ type: o,
1114
+ quality: 1
1115
+ });
1116
+ u = URL.createObjectURL(f);
1117
+ } else
1118
+ throw new Error("ImportImage. Неверный тип источника изображения. Ожидается URL или объект File.");
1119
+ t._createdBlobUrls.push(u);
1120
+ var v = L.getFormatFromContentType(o);
1121
+ if (v === "svg") {
1122
+ var j = yield Ee(u);
1123
+ g = x.groupSVGElements(j.objects, j.options);
1124
+ } else
1125
+ g = yield ue.fromURL(u, {
1126
+ crossOrigin: "anonymous"
1127
+ });
1128
+ g.set("id", "".concat(g.type, "-").concat(p())), g.set("format", v);
1129
+ var {
1130
+ width: m,
1131
+ height: I
1132
+ } = g;
1133
+ if (I > D || m > N) {
1134
+ var y = yield t.resizeImageToBoundaries(g._element.src, "max"), C = URL.createObjectURL(y);
1135
+ t._createdBlobUrls.push(C), g = yield ue.fromURL(C, {
1136
+ crossOrigin: "anonymous"
1137
+ });
1138
+ }
1139
+ if (r === "scale-montage")
1140
+ t.editor.canvasManager.scaleMontageAreaToImage({
1141
+ object: g,
1142
+ withoutSave: !0
1143
+ });
1144
+ else {
1145
+ var {
1146
+ width: O,
1147
+ height: A
1148
+ } = c, S = W({
1149
+ montageArea: c,
1150
+ imageObject: g,
1151
+ scaleType: r
1152
+ });
1153
+ r === "image-contain" && S < 1 ? d.fitObject({
1154
+ object: g,
1155
+ type: "contain",
1156
+ withoutSave: !0
1157
+ }) : r === "image-cover" && (m > O || I > A) && d.fitObject({
1158
+ object: g,
1159
+ type: "cover",
1160
+ withoutSave: !0
1161
+ });
1162
+ }
1163
+ s.add(g), s.centerObject(g), s.setActiveObject(g), s.renderAll(), l.resumeHistory(), i || l.saveState();
1164
+ } catch (T) {
1165
+ console.error("importImage. Ошибка импорта изображения: ", T), s.fire("editor:error", {
1166
+ message: "Ошибка импорта изображения: ".concat(T.message)
1167
+ }), l.resumeHistory();
1168
+ }
1169
+ }
1170
+ })();
1171
+ }
1172
+ /**
1173
+ * Функция для ресайза изображения до максимальных размеров,
1174
+ * если оно их превышает. Сохраняет пропорции.
1175
+ *
1176
+ * @param {HTMLImageElement} imageEl - HTML элемент изображения
1177
+ * @param {string} [size='max | min'] - максимальный или минимальный размер
1178
+ * @returns {Promise<string>} - возвращает Promise с новым dataURL
1179
+ */
1180
+ resizeImageToBoundaries(e) {
1181
+ var t = arguments, a = this;
1182
+ return Y(function* () {
1183
+ var r = t.length > 1 && t[1] !== void 0 ? t[1] : "max", i = "Размер изображения больше максимального размера канваса, поэтому оно будет уменьшено до максимальных размеров: ".concat(N, "x").concat(D);
1184
+ console.warn("importImage. ".concat(i)), a.editor.canvas.fire("editor:warning", {
1185
+ message: i
1186
+ });
1187
+ var o = yield a.editor.workerManager.post("resizeImage", {
1188
+ dataURL: e,
1189
+ maxWidth: N,
1190
+ maxHeight: D,
1191
+ sizeType: r
1192
+ });
1193
+ return o;
1194
+ })();
1195
+ }
1196
+ /**
1197
+ * Экспорт изображения в файл – экспортируется содержимое монтажной области.
1198
+ * Независимо от текущего зума, экспортируется монтажная область в исходном масштабе. Можно экспортировать как base64.
1199
+ * @param {Object} options - опции
1200
+ * @param {string} options.fileName - имя файла
1201
+ * @param {string} options.contentType - тип контента
1202
+ * @param {Boolean} options.exportAsBase64 - экспортировать как base64
1203
+ * @param {Boolean} options.exportAsBlob - экспортировать как blob
1204
+ * @returns {Promise<File> | String} - файл или base64
1205
+ * @fires editor:canvas-exported
1206
+ */
1207
+ exportCanvasAsImageFile() {
1208
+ var e = arguments, t = this;
1209
+ return Y(function* () {
1210
+ var {
1211
+ fileName: a = "image.png",
1212
+ contentType: r = "image/png",
1213
+ exportAsBase64: i = !1,
1214
+ exportAsBlob: o = !1
1215
+ } = e.length > 0 && e[0] !== void 0 ? e[0] : {}, {
1216
+ canvas: s,
1217
+ montageArea: c,
1218
+ workerManager: d
1219
+ } = t.editor, l = r === "application/pdf", u = l ? "image/jpg" : r, g = L.getFormatFromContentType(u);
1220
+ c.setCoords();
1221
+ var {
1222
+ left: h,
1223
+ top: f,
1224
+ width: v,
1225
+ height: j
1226
+ } = c.getBoundingRect(), m = yield s.clone(["id", "format", "locked"]);
1227
+ ["image/jpg", "image/jpeg"].includes(u) && (m.backgroundColor = "#ffffff");
1228
+ var I = m.getObjects().find((w) => w.id === c.id);
1229
+ I.visible = !1, m.viewportTransform = [1, 0, 0, 1, -h, -f], m.setDimensions({
1230
+ width: v,
1231
+ height: j
1232
+ }, {
1233
+ backstoreOnly: !0
1234
+ }), m.renderAll();
1235
+ var y = m.getObjects().filter((w) => w.format).every((w) => w.format === "svg");
1236
+ if (g === "svg" && y) {
1237
+ var C = m.toSVG();
1238
+ m.dispose();
1239
+ var O = L._exportSVGStringAsFile(C, {
1240
+ exportAsBase64: i,
1241
+ exportAsBlob: o,
1242
+ fileName: a
1243
+ }), A = {
1244
+ image: O,
1245
+ format: "svg",
1246
+ contentType: "image/svg+xml",
1247
+ fileName: a.replace(/\.[^/.]+$/, ".svg")
1248
+ };
1249
+ return s.fire("editor:canvas-exported", A), A;
1250
+ }
1251
+ var S = yield new Promise((w) => {
1252
+ m.getElement().toBlob(w);
1253
+ });
1254
+ if (m.dispose(), o) {
1255
+ var T = {
1256
+ image: S,
1257
+ format: g,
1258
+ contentType: u,
1259
+ fileName: a
1260
+ };
1261
+ return s.fire("editor:canvas-exported", T), T;
1262
+ }
1263
+ var te = yield createImageBitmap(S), ae = yield d.post("toDataURL", {
1264
+ format: g,
1265
+ quality: 1,
1266
+ bitmap: te
1267
+ }, [te]);
1268
+ if (l) {
1269
+ var re = 0.264583, U = v * re, V = j * re, Ae = (yield t.editor.moduleLoader.loadModule("jspdf")).jsPDF, P = new Ae({
1270
+ orientation: U > V ? "landscape" : "portrait",
1271
+ unit: "mm",
1272
+ format: [U, V]
1273
+ });
1274
+ if (P.addImage(ae, "JPG", 0, 0, U, V), i) {
1275
+ var Se = P.output("datauristring"), ie = {
1276
+ image: Se,
1277
+ format: "pdf",
1278
+ contentType: "application/pdf",
1279
+ fileName: a
1280
+ };
1281
+ return s.fire("editor:canvas-exported", ie), ie;
1282
+ }
1283
+ var we = P.output("blob"), Ne = new File([we], a, {
1284
+ type: "application/pdf"
1285
+ }), ne = {
1286
+ image: Ne,
1287
+ format: "pdf",
1288
+ contentType: "application/pdf",
1289
+ fileName: a
1290
+ };
1291
+ return s.fire("editor:canvas-exported", ne), ne;
1292
+ }
1293
+ if (i) {
1294
+ var oe = {
1295
+ image: ae,
1296
+ format: g,
1297
+ contentType: u,
1298
+ fileName: a
1299
+ };
1300
+ return s.fire("editor:canvas-exported", oe), oe;
1301
+ }
1302
+ var se = g === "svg" && !y ? a.replace(/\.[^/.]+$/, ".png") : a, De = new File([S], se, {
1303
+ type: u
1304
+ }), ce = {
1305
+ image: De,
1306
+ format: g,
1307
+ contentType: u,
1308
+ fileName: se
1309
+ };
1310
+ return s.fire("editor:canvas-exported", ce), ce;
1311
+ })();
1312
+ }
1313
+ /**
1314
+ * Экспорт выбранного объекта в виде изображения или base64
1315
+ * @param {Object} options - опции
1316
+ * @param {fabric.Object} options.object - объект для экспорта
1317
+ * @param {String} options.fileName - имя файла
1318
+ * @param {String} options.contentType - тип контента
1319
+ * @param {Boolean} options.exportAsBase64 - экспортировать как base64
1320
+ * @param {Boolean} options.exportAsBlob - экспортировать как blob
1321
+ * @returns {String} base64
1322
+ * @fires editor:object-exported
1323
+ */
1324
+ exportObjectAsImageFile() {
1325
+ var e = arguments, t = this;
1326
+ return Y(function* () {
1327
+ var {
1328
+ object: a,
1329
+ fileName: r = "image.png",
1330
+ contentType: i = "image/png",
1331
+ exportAsBase64: o = !1,
1332
+ exportAsBlob: s = !1
1333
+ } = e.length > 0 && e[0] !== void 0 ? e[0] : {}, {
1334
+ canvas: c,
1335
+ workerManager: d
1336
+ } = t.editor, l = a || c.getActiveObject();
1337
+ if (!l)
1338
+ return console.error("exportObjectAsDataURL. Не выбран объект"), c.fire("editor:error", {
1339
+ message: "Не выбран объект для экспорта"
1340
+ }), "";
1341
+ var u = L.getFormatFromContentType(i);
1342
+ if (u === "svg") {
1343
+ var g = l.toSVG(), h = t._exportSVGStringAsFile(g, {
1344
+ exportAsBase64: o,
1345
+ exportAsBlob: s,
1346
+ fileName: r
1347
+ }), f = {
1348
+ image: h,
1349
+ format: u,
1350
+ contentType: "image/svg+xml",
1351
+ fileName: r.replace(/\.[^/.]+$/, ".svg")
1352
+ };
1353
+ return c.fire("editor:object-exported", f), f;
1354
+ }
1355
+ if (o) {
1356
+ var v = yield createImageBitmap(l._element), j = yield d.post("toDataURL", {
1357
+ format: u,
1358
+ quality: 1,
1359
+ bitmap: v
1360
+ }, [v]), m = {
1361
+ image: j,
1362
+ format: u,
1363
+ contentType: i,
1364
+ fileName: r
1365
+ };
1366
+ return c.fire("editor:object-exported", m), m;
1367
+ }
1368
+ var I = l.toCanvasElement(), y = yield new Promise((S) => {
1369
+ I.toBlob(S);
1370
+ });
1371
+ if (s) {
1372
+ var C = {
1373
+ image: y,
1374
+ format: u,
1375
+ contentType: i,
1376
+ fileName: r
1377
+ };
1378
+ return c.fire("editor:object-exported", C), C;
1379
+ }
1380
+ var O = new File([y], r, {
1381
+ type: i
1382
+ }), A = {
1383
+ image: O,
1384
+ format: u,
1385
+ contentType: i,
1386
+ fileName: r
1387
+ };
1388
+ return c.fire("editor:object-exported", A), A;
1389
+ })();
1390
+ }
1391
+ /**
1392
+ * Удаляет все созданные blobURL
1393
+ * @returns {void}
1394
+ */
1395
+ revokeBlobUrls() {
1396
+ this._createdBlobUrls.forEach(URL.revokeObjectURL), this._createdBlobUrls = [];
1397
+ }
1398
+ /**
1399
+ * Преобразует SVG-строку в Blob, файл, или base64
1400
+ * @param {string} svgString - SVG-строка
1401
+ * @param {Object} options - опции
1402
+ * @param {Boolean} options.exportAsBase64 - экспортировать как base64
1403
+ * @param {Boolean} options.exportAsBlob - экспортировать как blob
1404
+ * @param {String} options.fileName - имя файла
1405
+ * @returns {Blob|String|File} - Blob, base64 или файл
1406
+ * @private
1407
+ * @static
1408
+ */
1409
+ static _exportSVGStringAsFile(e) {
1410
+ var {
1411
+ exportAsBase64: t,
1412
+ exportAsBlob: a,
1413
+ fileName: r
1414
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
1415
+ return a ? new Blob([e], {
1416
+ type: "image/svg+xml"
1417
+ }) : t ? "data:image/svg+xml;base64,".concat(btoa(e)) : new File([e], r.replace(/\.[^/.]+$/, ".svg"), {
1418
+ type: "image/svg+xml"
1419
+ });
1420
+ }
1421
+ /**
1422
+ * Извлекает чистый формат (subtype) из contentType,
1423
+ * отбросив любую часть после «+» или «;»
1424
+ * @param {string} contentType
1425
+ * @returns {string} формат, например 'png', 'jpeg', 'svg'
1426
+ * @static
1427
+ */
1428
+ static getFormatFromContentType() {
1429
+ var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "", t = e.match(/^[^/]+\/([^+;]+)/);
1430
+ return t ? t[1] : "";
1431
+ }
1432
+ }
1433
+ class jt {
1434
+ /**
1435
+ * @param {object} options
1436
+ * @param {ImageEditor} options.editor – экземпляр редактора
1437
+ */
1438
+ constructor(e) {
1439
+ var {
1440
+ editor: t
1441
+ } = e;
1442
+ this.editor = t;
1443
+ }
1444
+ /**
1445
+ * Устанавливаем внутреннюю ширину канваса (для экспорта)
1446
+ * @param {String} width
1447
+ * @param {Object} options
1448
+ * @param {Boolean} options.preserveProportional - Сохранить пропорции
1449
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
1450
+ * @fires editor:resolution-width-changed
1451
+ */
1452
+ setResolutionWidth(e) {
1453
+ var {
1454
+ preserveProportional: t,
1455
+ withoutSave: a,
1456
+ adaptCanvasToContainer: r
1457
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
1458
+ if (e) {
1459
+ var {
1460
+ canvas: i,
1461
+ montageArea: o,
1462
+ options: {
1463
+ canvasBackstoreWidth: s
1464
+ }
1465
+ } = this.editor, {
1466
+ width: c,
1467
+ height: d
1468
+ } = o, l = Number(Math.max(Math.min(e, N), Z));
1469
+ if (!s || s === "auto" || r ? this.adaptCanvasToContainer() : s ? this.setCanvasBackstoreWidth(s) : this.setCanvasBackstoreWidth(l), o.set({
1470
+ width: l
1471
+ }), i.clipPath.set({
1472
+ width: l
1473
+ }), t) {
1474
+ var u = l / c, g = d * u;
1475
+ this.setResolutionHeight(g);
1476
+ return;
1477
+ }
1478
+ var {
1479
+ left: h,
1480
+ top: f
1481
+ } = this.getObjectDefaultCoords(o), v = i.getZoom();
1482
+ i.setViewportTransform([v, 0, 0, v, h, f]), this.centerMontageArea(), a || this.editor.historyManager.saveState(), i == null || i.fire("editor:resolution-width-changed", {
1483
+ width: e
1484
+ });
1485
+ }
1486
+ }
1487
+ /**
1488
+ * Устанавливаем внутреннюю высоту канваса (для экспорта)
1489
+ * @param {String} height
1490
+ * @param {Object} options
1491
+ * @param {Boolean} options.preserveProportional - Сохранить пропорции
1492
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
1493
+ * @fires editor:resolution-height-changed
1494
+ */
1495
+ setResolutionHeight(e) {
1496
+ var {
1497
+ preserveProportional: t,
1498
+ withoutSave: a,
1499
+ adaptCanvasToContainer: r
1500
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
1501
+ if (e) {
1502
+ var {
1503
+ canvas: i,
1504
+ montageArea: o,
1505
+ options: {
1506
+ canvasBackstoreHeight: s
1507
+ }
1508
+ } = this.editor, {
1509
+ width: c,
1510
+ height: d
1511
+ } = o, l = Number(Math.max(Math.min(e, D), B));
1512
+ if (!s || s === "auto" || r ? this.adaptCanvasToContainer() : s ? this.setCanvasBackstoreHeight(s) : this.setCanvasBackstoreHeight(l), o.set({
1513
+ height: l
1514
+ }), i.clipPath.set({
1515
+ height: l
1516
+ }), t) {
1517
+ var u = l / d, g = c * u;
1518
+ this.setResolutionWidth(g);
1519
+ return;
1520
+ }
1521
+ var {
1522
+ left: h,
1523
+ top: f
1524
+ } = this.getObjectDefaultCoords(o), v = i.getZoom();
1525
+ i.setViewportTransform([v, 0, 0, v, h, f]), this.centerMontageArea(), a || this.editor.historyManager.saveState(), i == null || i.fire("editor:resolution-height-changed", {
1526
+ height: e
1527
+ });
1528
+ }
1529
+ }
1530
+ /**
1531
+ * Центрирует монтажную область и ClipPath точно по центру канваса
1532
+ * и устанавливает правильный viewportTransform.
1533
+ */
1534
+ centerMontageArea() {
1535
+ var {
1536
+ canvas: e,
1537
+ montageArea: t
1538
+ } = this.editor, a = e.getWidth(), r = e.getHeight(), i = e.getZoom(), o = new Ze(a / 2, r / 2);
1539
+ t.set({
1540
+ left: a / 2,
1541
+ top: r / 2
1542
+ }), e.clipPath.set({
1543
+ left: a / 2,
1544
+ top: r / 2
1545
+ }), e.renderAll();
1546
+ var s = e.viewportTransform;
1547
+ s[4] = a / 2 - o.x * i, s[5] = r / 2 - o.y * i, e.setViewportTransform(s), e.renderAll();
1548
+ }
1549
+ /**
1550
+ * Метод для получения координат объекта с учетом текущего зума
1551
+ * @param {fabric.Object} object - объект, координаты которого нужно получить
1552
+ * @returns {Object} координаты объекта
1553
+ */
1554
+ getObjectDefaultCoords(e) {
1555
+ var {
1556
+ canvas: t
1557
+ } = this.editor, a = e || t.getActiveObject();
1558
+ if (!a)
1559
+ return console.error("getObjectDefaultCoords. Не выбран объект"), this.editor.canvas.fire("editor:error", {
1560
+ message: "Не выбран объект для получения координат"
1561
+ }), {};
1562
+ var {
1563
+ width: r,
1564
+ height: i
1565
+ } = a, o = t.getZoom(), s = (r - r * o) / 2, c = (i - i * o) / 2;
1566
+ return {
1567
+ left: s,
1568
+ top: c
1569
+ };
1570
+ }
1571
+ setCanvasBackstoreWidth(e) {
1572
+ if (!(!e || typeof e != "number")) {
1573
+ var t = Math.max(Math.min(e, N), Z);
1574
+ this.editor.canvas.setDimensions({
1575
+ width: t
1576
+ }, {
1577
+ backstoreOnly: !0
1578
+ });
1579
+ }
1580
+ }
1581
+ setCanvasBackstoreHeight(e) {
1582
+ if (!(!e || typeof e != "number")) {
1583
+ var t = Math.max(Math.min(e, D), B);
1584
+ this.editor.canvas.setDimensions({
1585
+ height: t
1586
+ }, {
1587
+ backstoreOnly: !0
1588
+ });
1589
+ }
1590
+ }
1591
+ adaptCanvasToContainer() {
1592
+ var {
1593
+ canvas: e
1594
+ } = this.editor, t = e.editorContainer, a = t.clientWidth, r = t.clientHeight, i = Math.max(Math.min(a, N), Z), o = Math.max(Math.min(r, D), B);
1595
+ console.log("adaptCanvasToContainer newWidth", i), console.log("adaptCanvasToContainer newHeight", o), e.setDimensions({
1596
+ width: i,
1597
+ height: o
1598
+ }, {
1599
+ backstoreOnly: !0
1600
+ });
1601
+ }
1602
+ /**
1603
+ * Устанавливаем CSS ширину канваса для отображения
1604
+ * @param {string|number} width
1605
+ * @fires editor:display-canvas-width-changed
1606
+ */
1607
+ setCanvasCSSWidth(e) {
1608
+ this.setDisplayDimension({
1609
+ element: "canvas",
1610
+ dimension: "width",
1611
+ value: e
1612
+ });
1613
+ }
1614
+ /**
1615
+ * Устанавливаем CSS высоту канваса для отображения
1616
+ * @param {string|number} height
1617
+ * @fires editor:display-canvas-height-changed
1618
+ */
1619
+ setCanvasCSSHeight(e) {
1620
+ this.setDisplayDimension({
1621
+ element: "canvas",
1622
+ dimension: "height",
1623
+ value: e
1624
+ });
1625
+ }
1626
+ /**
1627
+ * Устанавливаем CSS ширину обертки канваса для отображения
1628
+ * @param {string|number} width
1629
+ * @fires editor:display-wrapper-width-changed
1630
+ */
1631
+ setCanvasWrapperWidth(e) {
1632
+ this.setDisplayDimension({
1633
+ element: "wrapper",
1634
+ dimension: "width",
1635
+ value: e
1636
+ });
1637
+ }
1638
+ /**
1639
+ * Устанавливаем CSS высоту обертки канваса для отображения
1640
+ * @param {string|number} height
1641
+ * @fires editor:display-wrapper-height-changed
1642
+ */
1643
+ setCanvasWrapperHeight(e) {
1644
+ this.setDisplayDimension({
1645
+ element: "wrapper",
1646
+ dimension: "height",
1647
+ value: e
1648
+ });
1649
+ }
1650
+ /**
1651
+ * Устанавливаем CSS ширину контейнера редактора для отображения
1652
+ * @param {string|number} width
1653
+ * @fires editor:display-container-width-changed
1654
+ */
1655
+ setEditorContainerWidth(e) {
1656
+ this.setDisplayDimension({
1657
+ element: "container",
1658
+ dimension: "width",
1659
+ value: e
1660
+ });
1661
+ }
1662
+ /**
1663
+ * Устанавливаем CSS высоту контейнера редактора для отображения
1664
+ * @param {string|number} height
1665
+ * @fires editor:display-container-height-changed
1666
+ */
1667
+ setEditorContainerHeight(e) {
1668
+ this.setDisplayDimension({
1669
+ element: "container",
1670
+ dimension: "height",
1671
+ value: e
1672
+ });
1673
+ }
1674
+ /**
1675
+ * Устанавливаем CSS ширину или высоту канваса для отображения
1676
+ * @param {Object} options
1677
+ * @param {String} [options.element] - элемент, для которого устанавливаем размеры:
1678
+ * canvas (upper & lower), wrapper, container
1679
+ * @param {('width'|'height')} [options.dimension]
1680
+ * @param {string|number} [options.value]
1681
+ * @fires editor:display-{element}-{dimension}-changed
1682
+ */
1683
+ setDisplayDimension() {
1684
+ var {
1685
+ element: e,
1686
+ dimension: t,
1687
+ value: a
1688
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
1689
+ if (a) {
1690
+ var {
1691
+ canvas: r,
1692
+ options: {
1693
+ editorContainer: i
1694
+ }
1695
+ } = this.editor, o = [];
1696
+ switch (e) {
1697
+ case "canvas":
1698
+ o.push(r.lowerCanvasEl, r.upperCanvasEl);
1699
+ break;
1700
+ case "wrapper":
1701
+ o.push(r.wrapperEl);
1702
+ break;
1703
+ case "container":
1704
+ o.push(i);
1705
+ break;
1706
+ default:
1707
+ o.push(r.lowerCanvasEl, r.upperCanvasEl);
1708
+ }
1709
+ var s = t === "width" ? "width" : "height";
1710
+ if (typeof a == "string") {
1711
+ o.forEach((l) => {
1712
+ l.style[s] = a;
1713
+ });
1714
+ return;
1715
+ }
1716
+ var c = parseFloat(a);
1717
+ if (!isNaN(c)) {
1718
+ var d = "".concat(c, "px");
1719
+ o.forEach((l) => {
1720
+ l.style[s] = d;
1721
+ }), r.fire("editor:display-".concat(e, "-").concat(s, "-changed"), {
1722
+ element: e,
1723
+ value: a
1724
+ });
1725
+ }
1726
+ }
1727
+ }
1728
+ /**
1729
+ * Если изображение вписывается в допустимые значения, то масштабируем под него канвас
1730
+ * @param {Object} options
1731
+ * @param {fabric.Object} [options.object] - Объект с изображением, которое нужно масштабировать
1732
+ * @param {Boolean} [options.withoutSave] - Не сохранять состояние
1733
+ * @param {Boolean} [options.preserveAspectRatio] - Сохранять изначальные пропорции монтажной области
1734
+ * @fires editor:canvas-scaled
1735
+ */
1736
+ scaleMontageAreaToImage() {
1737
+ var {
1738
+ object: e,
1739
+ preserveAspectRatio: t,
1740
+ withoutSave: a
1741
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
1742
+ canvas: r,
1743
+ montageArea: i,
1744
+ transformManager: o,
1745
+ options: {
1746
+ montageAreaWidth: s,
1747
+ montageAreaHeight: c
1748
+ }
1749
+ } = this.editor, d = e || r.getActiveObject();
1750
+ if (!(!d || d.type !== "image" && d.format !== "svg")) {
1751
+ var {
1752
+ width: l,
1753
+ height: u
1754
+ } = d;
1755
+ if (l < Z || u < B) {
1756
+ var g = "Размер изображения меньше минимального размера канваса, поэтому оно будет растянуто до минимальных размеров: ".concat(Z, "x").concat(B);
1757
+ console.warn("scaleMontageAreaToImage. ".concat(g)), r.fire("editor:warning", {
1758
+ message: g
1759
+ });
1760
+ }
1761
+ var h = Math.min(l, N), f = Math.min(u, D);
1762
+ if (t) {
1763
+ var {
1764
+ width: v,
1765
+ height: j
1766
+ } = i, m = l / v, I = u / j, y = Math.max(m, I);
1767
+ h = v * y, f = j * y;
1768
+ }
1769
+ this.setResolutionWidth(h, {
1770
+ withoutSave: !0
1771
+ }), this.setResolutionHeight(f, {
1772
+ withoutSave: !0
1773
+ }), (l > s || u > c) && o.calculateAndApplyDefaultZoom(s, c), o.resetObject(d, {
1774
+ withoutSave: !0
1775
+ }), r.centerObject(d), r.renderAll(), a || this.editor.historyManager.saveState(), r.fire("editor:canvas-scaled", {
1776
+ width: h,
1777
+ height: f
1778
+ });
1779
+ }
1780
+ }
1781
+ /**
1782
+ * Очистка холста
1783
+ * @fires editor:cleared
1784
+ */
1785
+ clearCanvas() {
1786
+ var {
1787
+ canvas: e,
1788
+ montageArea: t,
1789
+ historyManager: a
1790
+ } = this.editor;
1791
+ a.suspendHistory(), e.clear(), e.add(t), e.renderAll(), a.resumeHistory(), a.saveState(), e == null || e.fire("editor:cleared");
1792
+ }
1793
+ /**
1794
+ * Установка зума и масштаба для канваса и сброс трансформации всех объектов
1795
+ * @param {Object} options
1796
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
1797
+ * @fires editor:default-scale-set
1798
+ */
1799
+ setDefaultScale() {
1800
+ var {
1801
+ withoutSave: e
1802
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
1803
+ canvas: t,
1804
+ transformManager: a,
1805
+ historyManager: r,
1806
+ options: {
1807
+ montageAreaWidth: i,
1808
+ montageAreaHeight: o
1809
+ }
1810
+ } = this.editor;
1811
+ a.resetZoom(), this.setResolutionWidth(i, {
1812
+ withoutSave: !0
1813
+ }), this.setResolutionHeight(o, {
1814
+ withoutSave: !0
1815
+ }), t.renderAll(), a.resetObjects(), e || r.saveState(), t.fire("editor:default-scale-set");
1816
+ }
1817
+ /**
1818
+ * Получение всех объектов внутри монтажной области редактора
1819
+ * @returns {Array} массив объектов
1820
+ */
1821
+ getObjects() {
1822
+ var {
1823
+ canvas: e,
1824
+ montageArea: t,
1825
+ interactionBlocker: {
1826
+ overlayMask: a
1827
+ }
1828
+ } = this.editor, r = e.getObjects();
1829
+ return r.filter((i) => i.id !== t.id && i.id !== a.id);
1830
+ }
1831
+ }
1832
+ class yt {
1833
+ /**
1834
+ * @param {object} options
1835
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
1836
+ */
1837
+ constructor(e) {
1838
+ var {
1839
+ editor: t
1840
+ } = e;
1841
+ this.editor = t, this.options = t.options;
1842
+ }
1843
+ /**
1844
+ * Метод рассчитывает дефолтный, максимальный, и минимальный зум таким образом,
1845
+ * чтобы монтажная область визуально занимала переданные размеры.
1846
+ * Если размеры не переданы, то используются дефолтные размеры монтажной области переданные в options.
1847
+ * @param {number} [targetWidth] — желаемая видимая ширина (px)
1848
+ * @param {number} [targetHeight] — желаемая видимая высота (px)
1849
+ */
1850
+ calculateAndApplyDefaultZoom() {
1851
+ var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.options.montageAreaWidth, t = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : this.options.montageAreaHeight, {
1852
+ width: a,
1853
+ height: r
1854
+ } = this.editor.montageArea, i = e / a, o = t / r, s = Math.min(i, o), {
1855
+ minZoom: c,
1856
+ maxZoom: d,
1857
+ maxZoomFactor: l
1858
+ } = this.options;
1859
+ this.minZoom = Math.min(s / l, c), this.maxZoom = Math.max(s * l, d), this.defaultZoom = s, this.setZoom(s);
1860
+ }
1861
+ /**
1862
+ * Увеличение/уменьшение масштаба
1863
+ * @param {Number} scale - Шаг зума
1864
+ * @param {Object} options - Координаты зума (по умолчанию центр канваса)
1865
+ * @param {Number} options.pointX - Координата X точки зума
1866
+ * @param {Number} options.pointY - Координата Y точки зума
1867
+ * @fires editor:zoom-changed
1868
+ * Если передавать координаты курсора, то нужно быть аккуратнее, так как юзер может выйти за пределы рабочей области
1869
+ */
1870
+ zoom() {
1871
+ var e, t, a = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : ft, r = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
1872
+ if (a) {
1873
+ var {
1874
+ canvas: i,
1875
+ minZoom: o,
1876
+ maxZoom: s
1877
+ } = this.editor, c = i.getZoom(), d = (e = r.pointX) !== null && e !== void 0 ? e : i.getWidth() / 2, l = (t = r.pointY) !== null && t !== void 0 ? t : i.getHeight() / 2, u = Number((c + Number(a)).toFixed(2));
1878
+ u > s && (u = s), u < o && (u = o), console.log("currentZoom", c), i.zoomToPoint({
1879
+ x: Number(d),
1880
+ y: Number(l)
1881
+ }, u), i.fire("editor:zoom-changed", {
1882
+ currentZoom: i.getZoom(),
1883
+ zoom: u,
1884
+ pointX: d,
1885
+ pointY: l
1886
+ });
1887
+ }
1888
+ }
1889
+ /**
1890
+ * Установка зума
1891
+ * @param {Number} zoom - Зум
1892
+ * @fires editor:zoom-changed
1893
+ */
1894
+ setZoom() {
1895
+ var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.defaultZoom, {
1896
+ canvas: t,
1897
+ minZoom: a,
1898
+ maxZoom: r
1899
+ } = this.editor, i = t.getWidth() / 2, o = t.getHeight() / 2, s = e;
1900
+ e > r && (s = r), e < a && (s = a), t.zoomToPoint({
1901
+ x: Number(i),
1902
+ y: Number(o)
1903
+ }, s), t.fire("editor:zoom-changed", {
1904
+ currentZoom: t.getZoom(),
1905
+ zoom: s,
1906
+ pointX: i,
1907
+ pointY: o
1908
+ });
1909
+ }
1910
+ /**
1911
+ * Сброс зума
1912
+ * @fires editor:zoom-changed
1913
+ */
1914
+ resetZoom() {
1915
+ var {
1916
+ canvas: e,
1917
+ defaultZoom: t
1918
+ } = this.editor, a = e.getWidth() / 2, r = e.getHeight() / 2;
1919
+ e.zoomToPoint({
1920
+ x: Number(a),
1921
+ y: Number(r)
1922
+ }, t), this.editor.canvas.fire("editor:zoom-changed", {
1923
+ currentZoom: e.getZoom()
1924
+ });
1925
+ }
1926
+ /**
1927
+ * Поворот объекта на заданный угол
1928
+ * @param {number} angle
1929
+ * @param {Object} options
1930
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
1931
+ * @fires editor:object-rotated
1932
+ */
1933
+ rotate() {
1934
+ var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : Mt, {
1935
+ withoutSave: t
1936
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, {
1937
+ canvas: a,
1938
+ historyManager: r
1939
+ } = this.editor, i = a.getActiveObject();
1940
+ if (i) {
1941
+ var o = i.angle + e;
1942
+ i.rotate(o), i.setCoords(), a.renderAll(), t || r.saveState(), a.fire("editor:object-rotated", {
1943
+ angle: o
1944
+ });
1945
+ }
1946
+ }
1947
+ /**
1948
+ * Отразить по горизонтали
1949
+ * @param {Object} options
1950
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
1951
+ * @fires editor:object-flipped-x
1952
+ */
1953
+ flipX() {
1954
+ var {
1955
+ withoutSave: e
1956
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
1957
+ canvas: t,
1958
+ historyManager: a
1959
+ } = this.editor, r = t.getActiveObject();
1960
+ r && (r.flipX = !r.flipX, t.renderAll(), e || a.saveState(), t.fire("editor:object-flipped-x"));
1961
+ }
1962
+ /**
1963
+ * Отразить по вертикали
1964
+ * @param {Object} options
1965
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
1966
+ * @fires editor:object-flipped-y
1967
+ */
1968
+ flipY() {
1969
+ var {
1970
+ withoutSave: e
1971
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
1972
+ canvas: t,
1973
+ historyManager: a
1974
+ } = this.editor, r = t.getActiveObject();
1975
+ r && (r.flipY = !r.flipY, t.renderAll(), e || a.saveState(), t.fire("editor:object-flipped-y"));
1976
+ }
1977
+ /**
1978
+ * Установка прозрачности объекта
1979
+ * @param {Number} opacity - Прозрачность от 0 до 1
1980
+ * @fires editor:object-opacity-changed
1981
+ */
1982
+ setActiveObjectOpacity() {
1983
+ var {
1984
+ object: e,
1985
+ opacity: t = 1,
1986
+ withoutSave: a
1987
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
1988
+ canvas: r,
1989
+ historyManager: i
1990
+ } = this.editor, o = e || r.getActiveObject();
1991
+ o && (o.type === "activeselection" ? o.getObjects().forEach((s) => {
1992
+ s.set("opacity", t);
1993
+ }) : o.set("opacity", t), r.renderAll(), a || i.saveState(), r.fire("editor:object-opacity-changed", t));
1994
+ }
1995
+ /**
1996
+ * Масштабирование изображения
1997
+ * @param {Object} options
1998
+ * @param {fabric.Object} [options.object] - Объект с изображением, которое нужно масштабировать
1999
+ * @param {String} [options.type] - Тип масштабирования
2000
+ * 'contain' - скейлит картинку, чтобы она вмещалась
2001
+ * 'cover' - скейлит картинку, чтобы она вписалась в размер канвас
2002
+ * @param {Boolean} [options.withoutSave] - Не сохранять состояние
2003
+ * @param {Boolean} [options.fitAsOneObject] - Масштабировать все объекты в активной группе как один объект
2004
+ * @fires editor:image-fitted
2005
+ */
2006
+ fitObject() {
2007
+ var {
2008
+ object: e,
2009
+ type: t = this.options.scaleType,
2010
+ withoutSave: a,
2011
+ fitAsOneObject: r
2012
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
2013
+ canvas: i,
2014
+ montageArea: o,
2015
+ historyManager: s
2016
+ } = this.editor, c = e || i.getActiveObject();
2017
+ if (c) {
2018
+ if (["activeselection"].includes(c.type) && !r) {
2019
+ var d = c.getObjects();
2020
+ i.discardActiveObject(), d.forEach((g) => {
2021
+ var h = W({
2022
+ montageArea: o,
2023
+ imageObject: g,
2024
+ scaleType: t
2025
+ });
2026
+ g.scale(h), i.centerObject(g);
2027
+ });
2028
+ var l = new k(d, {
2029
+ canvas: i
2030
+ });
2031
+ i.setActiveObject(l);
2032
+ } else {
2033
+ var u = W({
2034
+ montageArea: o,
2035
+ imageObject: c,
2036
+ scaleType: t
2037
+ });
2038
+ c.scale(u), i.centerObject(c);
2039
+ }
2040
+ i.renderAll(), a || s.saveState(), i.fire("editor:image-fitted", {
2041
+ type: t
2042
+ });
2043
+ }
2044
+ }
2045
+ /**
2046
+ * Установка дефолтного масштаба для всех объектов внутри монтажной области редактора
2047
+ */
2048
+ resetObjects() {
2049
+ this.editor.canvasManager.getObjects().forEach((e) => {
2050
+ this.resetObject(e);
2051
+ });
2052
+ }
2053
+ /**
2054
+ * Сброс масштаба объекта до дефолтного
2055
+ * @param {fabric.Object} object
2056
+ * @param {Boolean} [fitOnlyBigImage] - растягивать только большие изображения
2057
+ * @returns
2058
+ * @fires editor:object-reset
2059
+ */
2060
+ resetObject(e) {
2061
+ var {
2062
+ alwaysFitObject: t = !1,
2063
+ withoutSave: a = !1
2064
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, {
2065
+ canvas: r,
2066
+ montageArea: i,
2067
+ historyManager: o,
2068
+ options: {
2069
+ scaleType: s
2070
+ }
2071
+ } = this.editor, c = e || r.getActiveObject();
2072
+ if (!(!c || c.locked)) {
2073
+ if (o.suspendHistory(), c.type !== "image" && c.format !== "svg" && (c.set({
2074
+ scaleX: 1,
2075
+ scaleY: 1,
2076
+ flipX: !1,
2077
+ flipY: !1,
2078
+ angle: 0
2079
+ }), r.centerObject(c), r.renderAll()), t)
2080
+ this.fitObject({
2081
+ object: c,
2082
+ withoutSave: !0
2083
+ });
2084
+ else {
2085
+ var {
2086
+ width: d,
2087
+ height: l
2088
+ } = i, {
2089
+ width: u,
2090
+ height: g
2091
+ } = c, h = W({
2092
+ montageArea: i,
2093
+ imageObject: c,
2094
+ scaleType: s
2095
+ });
2096
+ s === "contain" && h < 1 || s === "cover" && (u > d || g > l) ? this.fitObject({
2097
+ object: c,
2098
+ withoutSave: !0
2099
+ }) : c.set({
2100
+ scaleX: 1,
2101
+ scaleY: 1
2102
+ });
2103
+ }
2104
+ c.set({
2105
+ flipX: !1,
2106
+ flipY: !1,
2107
+ angle: 0
2108
+ }), r.centerObject(c), r.renderAll(), o.resumeHistory(), a || o.saveState(), r.fire("editor:object-reset");
2109
+ }
2110
+ }
2111
+ }
2112
+ class bt {
2113
+ /**
2114
+ * @param {object} options
2115
+ * @param {ImageEditor} options.editor – экземпляр редактора
2116
+ */
2117
+ constructor(e) {
2118
+ var {
2119
+ editor: t
2120
+ } = e;
2121
+ this.editor = t, this.isBlocked = !1, this.overlayMask = null, this._createOverlay();
2122
+ }
2123
+ /**
2124
+ * Создаёт overlay для блокировки монтажной области
2125
+ * @private
2126
+ * @returns {void}
2127
+ */
2128
+ _createOverlay() {
2129
+ var {
2130
+ historyManager: e,
2131
+ options: {
2132
+ overlayMaskColor: t = "rgba(0,0,0,0.5)"
2133
+ }
2134
+ } = this.editor;
2135
+ e.suspendHistory(), this.overlayMask = this.editor.shapeManager.addRectangle({
2136
+ fill: t,
2137
+ selectable: !1,
2138
+ evented: !0,
2139
+ hoverCursor: "not-allowed",
2140
+ hasBorders: !1,
2141
+ hasControls: !1,
2142
+ visible: !1,
2143
+ id: "overlay-mask"
2144
+ }, {
2145
+ withoutSelection: !0
2146
+ }), e.resumeHistory();
2147
+ }
2148
+ /**
2149
+ * Обновляет размеры и позицию overlay, выносит его на передний план
2150
+ * @returns {void}
2151
+ */
2152
+ refresh() {
2153
+ var {
2154
+ canvas: e,
2155
+ montageArea: t,
2156
+ historyManager: a
2157
+ } = this.editor;
2158
+ if (!(!t || !this.overlayMask)) {
2159
+ a.suspendHistory(), t.setCoords();
2160
+ var {
2161
+ left: r,
2162
+ top: i,
2163
+ width: o,
2164
+ height: s
2165
+ } = t.getBoundingRect();
2166
+ this.overlayMask.set({
2167
+ left: r,
2168
+ top: i,
2169
+ width: o,
2170
+ height: s
2171
+ }), e.discardActiveObject(), this.editor.layerManager.bringToFront(this.overlayMask, {
2172
+ withoutSave: !0
2173
+ }), a.resumeHistory();
2174
+ }
2175
+ }
2176
+ /**
2177
+ * Выключает редактор:
2178
+ * - убирает все селекты, события мыши, скейл/драг–н–дроп
2179
+ * - делает все объекты не‑evented и не‑selectable
2180
+ * - делает видимым overlayMask поверх всех объектов в монтажной области
2181
+ * @returns {void}
2182
+ */
2183
+ block() {
2184
+ if (!this.isBlocked) {
2185
+ var {
2186
+ canvas: e,
2187
+ canvasManager: t,
2188
+ historyManager: a
2189
+ } = this.editor;
2190
+ a.suspendHistory(), this.isBlocked = !0, e.discardActiveObject(), e.selection = !1, e.skipTargetFind = !0, t.getObjects().forEach((r) => {
2191
+ r.evented = !1, r.selectable = !1;
2192
+ }), e.upperCanvasEl.style.pointerEvents = "none", e.lowerCanvasEl.style.pointerEvents = "none", this.overlayMask.visible = !0, this.refresh(), e.fire("editor:disabled"), a.resumeHistory();
2193
+ }
2194
+ }
2195
+ /**
2196
+ * Включает редактор
2197
+ * @returns {void}
2198
+ */
2199
+ unblock() {
2200
+ if (this.isBlocked) {
2201
+ var {
2202
+ canvas: e,
2203
+ canvasManager: t,
2204
+ historyManager: a
2205
+ } = this.editor;
2206
+ a.suspendHistory(), this.isBlocked = !1, e.selection = !0, e.skipTargetFind = !1, t.getObjects().forEach((r) => {
2207
+ r.evented = !0, r.selectable = !0;
2208
+ }), e.upperCanvasEl.style.pointerEvents = "", e.lowerCanvasEl.style.pointerEvents = "", this.overlayMask.visible = !1, e.requestRenderAll(), e.fire("editor:enabled"), a.resumeHistory();
2209
+ }
2210
+ }
2211
+ }
2212
+ class H {
2213
+ /**
2214
+ * @param {object} options
2215
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
2216
+ */
2217
+ constructor(e) {
2218
+ var {
2219
+ editor: t
2220
+ } = e;
2221
+ this.editor = t;
2222
+ }
2223
+ /**
2224
+ * Поднять объект навверх по оси Z
2225
+ * @param {fabric.Object} object
2226
+ * @param {Object} options
2227
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
2228
+ * @fires editor:object-bring-to-front
2229
+ */
2230
+ bringToFront(e) {
2231
+ var {
2232
+ withoutSave: t
2233
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, {
2234
+ canvas: a,
2235
+ historyManager: r
2236
+ } = this.editor;
2237
+ r.suspendHistory();
2238
+ var i = e || a.getActiveObject();
2239
+ i && (i.type === "activeselection" ? i.getObjects().forEach((o) => {
2240
+ a.bringObjectToFront(o);
2241
+ }) : a.bringObjectToFront(i), a.renderAll(), r.resumeHistory(), t || r.saveState(), a.fire("editor:object-bring-to-front"));
2242
+ }
2243
+ /**
2244
+ * Поднять объект на один уровень вверх по оси Z
2245
+ * @param {fabric.Object} object
2246
+ * @param {Object} options
2247
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
2248
+ * @fires editor:object-bring-forward
2249
+ */
2250
+ bringForward(e) {
2251
+ var {
2252
+ withoutSave: t
2253
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, {
2254
+ canvas: a,
2255
+ historyManager: r
2256
+ } = this.editor;
2257
+ r.suspendHistory();
2258
+ var i = e || a.getActiveObject();
2259
+ i && (i.type === "activeselection" ? H._moveSelectionForward(a, i) : a.bringObjectForward(i), a.renderAll(), r.resumeHistory(), t || r.saveState(), a.fire("editor:object-bring-forward"));
2260
+ }
2261
+ /**
2262
+ * Отправить объект на задний план по оси Z
2263
+ * @param {fabric.Object} object
2264
+ * @param {Object} options
2265
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
2266
+ * @fires editor:object-send-to-back
2267
+ */
2268
+ sendToBack(e) {
2269
+ var {
2270
+ withoutSave: t
2271
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, {
2272
+ canvas: a,
2273
+ montageArea: r,
2274
+ historyManager: i,
2275
+ interactionBlocker: {
2276
+ overlayMask: o
2277
+ }
2278
+ } = this.editor;
2279
+ i.suspendHistory();
2280
+ var s = e || a.getActiveObject();
2281
+ if (s) {
2282
+ if (s.type === "activeselection")
2283
+ for (var c = s.getObjects(), d = c.length - 1; d >= 0; d -= 1)
2284
+ a.sendObjectToBack(c[d]);
2285
+ else
2286
+ a.sendObjectToBack(s);
2287
+ a.sendObjectToBack(r), a.sendObjectToBack(o), a.renderAll(), i.resumeHistory(), t || i.saveState(), a.fire("editor:object-send-to-back");
2288
+ }
2289
+ }
2290
+ /**
2291
+ * Отправить объект на один уровень ниже по оси Z
2292
+ * @param {fabric.Object} object
2293
+ * @param {Object} options
2294
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
2295
+ */
2296
+ sendBackwards(e) {
2297
+ var {
2298
+ withoutSave: t
2299
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, {
2300
+ canvas: a,
2301
+ montageArea: r,
2302
+ historyManager: i,
2303
+ interactionBlocker: {
2304
+ overlayMask: o
2305
+ }
2306
+ } = this.editor;
2307
+ i.suspendHistory();
2308
+ var s = e || a.getActiveObject();
2309
+ s && (s.type === "activeselection" ? H._moveSelectionBackwards(a, s) : a.sendObjectBackwards(s), a.sendObjectToBack(r), a.sendObjectToBack(o), a.renderAll(), i.resumeHistory(), t || i.saveState(), a.fire("editor:object-send-backwards"));
2310
+ }
2311
+ /**
2312
+ * Сдвигает выделенные объекты на один уровень вверх относительно ближайшего верхнего объекта
2313
+ * @param {fabric.Canvas} canvas - экземпляр холста
2314
+ * @param {fabric.ActiveSelection} activeSelection - активное выделение
2315
+ * @returns {void}
2316
+ * @private
2317
+ */
2318
+ static _moveSelectionForward(e, t) {
2319
+ for (var a = e.getObjects(), r = t.getObjects(), i = r.length - 1; i >= 0; i -= 1) {
2320
+ for (var o = r[i], s = a.indexOf(o), c = s + 1; c < a.length && r.includes(a[c]); )
2321
+ c += 1;
2322
+ c < a.length && e.moveObjectTo(o, c);
2323
+ }
2324
+ }
2325
+ /**
2326
+ * Сдвигает выделенные объекты на один уровень вниз относительно ближайшего нижнего объекта
2327
+ * @param {fabric.Canvas} canvas - экземпляр холста
2328
+ * @param {fabric.ActiveSelection} activeSelection - активное выделение
2329
+ * @returns {void}
2330
+ * @private
2331
+ */
2332
+ static _moveSelectionBackwards(e, t) {
2333
+ for (var a = e.getObjects(), r = t.getObjects(), i = Math.min(...r.map((s) => a.indexOf(s))), o = r.length - 1; o >= 0; o -= 1)
2334
+ e.moveObjectTo(r[o], i - 1);
2335
+ }
2336
+ }
2337
+ var It = ["id", "left", "top", "width", "height", "fill"], pt = ["id", "left", "top", "radius", "fill"], Ct = ["id", "left", "top", "width", "height", "fill"];
2338
+ function Me(n, e) {
2339
+ var t = Object.keys(n);
2340
+ if (Object.getOwnPropertySymbols) {
2341
+ var a = Object.getOwnPropertySymbols(n);
2342
+ e && (a = a.filter(function(r) {
2343
+ return Object.getOwnPropertyDescriptor(n, r).enumerable;
2344
+ })), t.push.apply(t, a);
2345
+ }
2346
+ return t;
2347
+ }
2348
+ function G(n) {
2349
+ for (var e = 1; e < arguments.length; e++) {
2350
+ var t = arguments[e] != null ? arguments[e] : {};
2351
+ e % 2 ? Me(Object(t), !0).forEach(function(a) {
2352
+ At(n, a, t[a]);
2353
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(n, Object.getOwnPropertyDescriptors(t)) : Me(Object(t)).forEach(function(a) {
2354
+ Object.defineProperty(n, a, Object.getOwnPropertyDescriptor(t, a));
2355
+ });
2356
+ }
2357
+ return n;
2358
+ }
2359
+ function At(n, e, t) {
2360
+ return (e = St(e)) in n ? Object.defineProperty(n, e, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : n[e] = t, n;
2361
+ }
2362
+ function St(n) {
2363
+ var e = wt(n, "string");
2364
+ return typeof e == "symbol" ? e : e + "";
2365
+ }
2366
+ function wt(n, e) {
2367
+ if (typeof n != "object" || !n) return n;
2368
+ var t = n[Symbol.toPrimitive];
2369
+ if (t !== void 0) {
2370
+ var a = t.call(n, e);
2371
+ if (typeof a != "object") return a;
2372
+ throw new TypeError("@@toPrimitive must return a primitive value.");
2373
+ }
2374
+ return (e === "string" ? String : Number)(n);
2375
+ }
2376
+ function F(n, e) {
2377
+ if (n == null) return {};
2378
+ var t, a, r = Nt(n, e);
2379
+ if (Object.getOwnPropertySymbols) {
2380
+ var i = Object.getOwnPropertySymbols(n);
2381
+ for (a = 0; a < i.length; a++) t = i[a], e.indexOf(t) === -1 && {}.propertyIsEnumerable.call(n, t) && (r[t] = n[t]);
2382
+ }
2383
+ return r;
2384
+ }
2385
+ function Nt(n, e) {
2386
+ if (n == null) return {};
2387
+ var t = {};
2388
+ for (var a in n) if ({}.hasOwnProperty.call(n, a)) {
2389
+ if (e.indexOf(a) !== -1) continue;
2390
+ t[a] = n[a];
2391
+ }
2392
+ return t;
2393
+ }
2394
+ class Dt {
2395
+ /**
2396
+ * @param {object} options
2397
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
2398
+ */
2399
+ constructor(e) {
2400
+ var {
2401
+ editor: t
2402
+ } = e;
2403
+ this.editor = t;
2404
+ }
2405
+ /**
2406
+ * Добавление прямоугольника
2407
+ * @param {Object} shapeOptions
2408
+ * @param {Number} shapeOptions.left - Координата X
2409
+ * @param {Number} shapeOptions.top - Координата Y
2410
+ * @param {Number} shapeOptions.width - Ширина
2411
+ * @param {Number} shapeOptions.height - Высота
2412
+ * @param {String} shapeOptions.fill - Цвет заливки
2413
+ * @param {String} shapeOptions.originX - Ориентация по X
2414
+ * @param {String} shapeOptions.originY - Ориентация по Y
2415
+ * @param {Rect} shapeOptions.rest - Остальные параметры
2416
+ *
2417
+ * @param {Object} flags.withoutSelection - Не выделять объект
2418
+ * @param {Object} flags.withoutAdding - Не добавлять объект в canvas
2419
+ */
2420
+ addRectangle() {
2421
+ var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
2422
+ id: t = "rect-".concat(p()),
2423
+ left: a,
2424
+ top: r,
2425
+ width: i = 100,
2426
+ height: o = 100,
2427
+ fill: s = "blue"
2428
+ } = e, c = F(e, It), {
2429
+ withoutSelection: d,
2430
+ withoutAdding: l
2431
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, {
2432
+ canvas: u
2433
+ } = this.editor, g = new Be(G({
2434
+ id: t,
2435
+ left: a,
2436
+ top: r,
2437
+ width: i,
2438
+ height: o,
2439
+ fill: s
2440
+ }, c));
2441
+ return !a && !r && u.centerObject(g), l || (u.add(g), d || u.setActiveObject(g), u.renderAll()), g;
2442
+ }
2443
+ /**
2444
+ * Добавление круга
2445
+ * @param {Object} shapeOptions
2446
+ * @param {Number} shapeOptions.left - Координата X
2447
+ * @param {Number} shapeOptions.top - Координата Y
2448
+ * @param {Number} shapeOptions.radius - Радиус
2449
+ * @param {string} shapeOptions.fill - Цвет заливки
2450
+ * @param {String} shapeOptions.originX - Ориентация по X
2451
+ * @param {String} shapeOptions.originY - Ориентация по Y
2452
+ * @param {Circle} shapeOptions.rest - Остальные параметры
2453
+ *
2454
+ * @param {Object} flags.withoutSelection - Не выделять объект
2455
+ * @param {Object} flags.withoutAdding - Не добавлять объект в canvas
2456
+ */
2457
+ addCircle() {
2458
+ var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
2459
+ id: t = "circle-".concat(p()),
2460
+ left: a,
2461
+ top: r,
2462
+ radius: i = 50,
2463
+ fill: o = "green"
2464
+ } = e, s = F(e, pt), {
2465
+ withoutSelection: c,
2466
+ withoutAdding: d
2467
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, {
2468
+ canvas: l
2469
+ } = this.editor, u = new ke(G({
2470
+ id: t,
2471
+ left: a,
2472
+ top: r,
2473
+ fill: o,
2474
+ radius: i
2475
+ }, s));
2476
+ return !a && !r && l.centerObject(u), d || (l.add(u), c || l.setActiveObject(u), l.renderAll()), u;
2477
+ }
2478
+ /**
2479
+ * Добавление треугольника
2480
+ * @param {Object} shapeOptions
2481
+ * @param {Number} shapeOptions.left - Координата X
2482
+ * @param {Number} shapeOptions.top - Координата Y
2483
+ * @param {Number} shapeOptions.width - Ширина
2484
+ * @param {Number} shapeOptions.height - Высота
2485
+ * @param {String} shapeOptions.originX - Ориентация по X
2486
+ * @param {String} shapeOptions.originY - Ориентация по Y
2487
+ * @param {String} shapeOptions.fill - Цвет заливки
2488
+ * @param {Triangle} shapeOptions.rest - Остальные параметры
2489
+ *
2490
+ * @param {Object} flags.withoutSelection - Не выделять объект
2491
+ * @param {Object} flags.withoutAdding - Не добавлять объект в canvas
2492
+ */
2493
+ addTriangle() {
2494
+ var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
2495
+ id: t = "triangle-".concat(p()),
2496
+ left: a,
2497
+ top: r,
2498
+ width: i = 100,
2499
+ height: o = 100,
2500
+ fill: s = "yellow"
2501
+ } = e, c = F(e, Ct), {
2502
+ withoutSelection: d,
2503
+ withoutAdding: l
2504
+ } = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, {
2505
+ canvas: u
2506
+ } = this.editor, g = new xe(G({
2507
+ id: t,
2508
+ left: a,
2509
+ top: r,
2510
+ fill: s,
2511
+ width: i,
2512
+ height: o
2513
+ }, c));
2514
+ return !a && !r && u.centerObject(g), l || (u.add(g), d || u.setActiveObject(g), u.renderAll()), g;
2515
+ }
2516
+ }
2517
+ function je(n, e, t, a, r, i, o) {
2518
+ try {
2519
+ var s = n[i](o), c = s.value;
2520
+ } catch (d) {
2521
+ return void t(d);
2522
+ }
2523
+ s.done ? e(c) : Promise.resolve(c).then(a, r);
2524
+ }
2525
+ function ye(n) {
2526
+ return function() {
2527
+ var e = this, t = arguments;
2528
+ return new Promise(function(a, r) {
2529
+ var i = n.apply(e, t);
2530
+ function o(c) {
2531
+ je(i, a, r, o, s, "next", c);
2532
+ }
2533
+ function s(c) {
2534
+ je(i, a, r, o, s, "throw", c);
2535
+ }
2536
+ o(void 0);
2537
+ });
2538
+ };
2539
+ }
2540
+ class Lt {
2541
+ /**
2542
+ * @param {object} options
2543
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
2544
+ */
2545
+ constructor(e) {
2546
+ var {
2547
+ editor: t
2548
+ } = e;
2549
+ this.editor = t, this.clipboard = null;
2550
+ }
2551
+ /**
2552
+ * Копирование объекта
2553
+ * @fires editor:object-copied
2554
+ */
2555
+ copy() {
2556
+ var e = this;
2557
+ return ye(function* () {
2558
+ var {
2559
+ canvas: t
2560
+ } = e.editor, a = t.getActiveObject();
2561
+ if (a)
2562
+ try {
2563
+ var r = yield a.clone();
2564
+ if (e.clipboard = r, typeof ClipboardItem == "undefined" || !navigator.clipboard) {
2565
+ console.warn(
2566
+ // eslint-disable-next-line max-len
2567
+ "ClipboardManager. navigator.clipboard не поддерживается в этом браузере или отсутствует соединение по HTTPS-протоколу."
2568
+ ), t.fire("editor:object-copied", {
2569
+ object: r
2570
+ });
2571
+ return;
2572
+ }
2573
+ if (e.clipboard.type !== "image") {
2574
+ yield navigator.clipboard.writeText(["application/image-editor", JSON.stringify(r)]), t.fire("editor:object-copied", {
2575
+ object: r
2576
+ });
2577
+ return;
2578
+ }
2579
+ var i = r.toCanvasElement(), o = yield new Promise((d) => {
2580
+ i.toBlob(d);
2581
+ }), s = new ClipboardItem({
2582
+ [o.type]: o
2583
+ });
2584
+ yield navigator.clipboard.write([s]), t.fire("editor:object-copied", {
2585
+ object: r
2586
+ });
2587
+ } catch (d) {
2588
+ var c = "ClipboardManager. Ошибка записи в системный буфер обмена:";
2589
+ console.error(c, d), t.fire("editor:error", {
2590
+ message: "".concat(c, " ").concat(d.message)
2591
+ });
2592
+ }
2593
+ })();
2594
+ }
2595
+ /**
2596
+ * Вставка объекта
2597
+ * @fires editor:object-pasted
2598
+ */
2599
+ paste() {
2600
+ var e = this;
2601
+ return ye(function* () {
2602
+ var {
2603
+ canvas: t
2604
+ } = e.editor;
2605
+ if (e.clipboard) {
2606
+ var a = yield e.clipboard.clone();
2607
+ t.discardActiveObject(), a.set({
2608
+ id: "".concat(a.type, "-").concat(p()),
2609
+ left: a.left + 10,
2610
+ top: a.top + 10,
2611
+ evented: !0
2612
+ }), a instanceof k ? (a.canvas = t, a.forEachObject((r) => {
2613
+ t.add(r);
2614
+ })) : t.add(a), t.setActiveObject(a), t.requestRenderAll(), t.fire("editor:object-pasted", {
2615
+ object: a
2616
+ });
2617
+ }
2618
+ })();
2619
+ }
2620
+ }
2621
+ class Ot {
2622
+ /**
2623
+ * @param {object} options
2624
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
2625
+ */
2626
+ constructor(e) {
2627
+ var {
2628
+ editor: t
2629
+ } = e;
2630
+ this.editor = t;
2631
+ }
2632
+ /**
2633
+ * Блокирует объект (или группу объектов) на канвасе
2634
+ * @param {Object} options
2635
+ * @param {fabric.Object} [options.object] - объект, который нужно заблокировать
2636
+ * @param {Boolean} [options.withoutSave] - не сохранять состояние
2637
+ * @returns
2638
+ * @fires editor:object-locked
2639
+ */
2640
+ lockObject() {
2641
+ var {
2642
+ object: e,
2643
+ withoutSave: t
2644
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
2645
+ canvas: a,
2646
+ historyManager: r
2647
+ } = this.editor, i = e || a.getActiveObject();
2648
+ if (i) {
2649
+ var o = {
2650
+ lockMovementX: !0,
2651
+ lockMovementY: !0,
2652
+ lockRotation: !0,
2653
+ lockScalingX: !0,
2654
+ lockScalingY: !0,
2655
+ lockSkewingX: !0,
2656
+ lockSkewingY: !0,
2657
+ locked: !0
2658
+ };
2659
+ i.set(o), ["activeselection", "group"].includes(i.type) && i.getObjects().forEach((s) => {
2660
+ s.set(o);
2661
+ }), a.renderAll(), t || r.saveState(), a.fire("editor:object-locked", {
2662
+ object: i
2663
+ });
2664
+ }
2665
+ }
2666
+ /**
2667
+ * Разблокирует объект (или группу объектов) на канвасе
2668
+ * @param {Object} options
2669
+ * @param {fabric.Object} [options.object] - объект, который нужно разблокировать
2670
+ * @param {Boolean} [options.withoutSave] - не сохранять состояние
2671
+ * @returns
2672
+ * @fires editor:object-unlocked
2673
+ */
2674
+ unlockObject() {
2675
+ var {
2676
+ object: e,
2677
+ withoutSave: t
2678
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
2679
+ canvas: a,
2680
+ historyManager: r
2681
+ } = this.editor, i = e || a.getActiveObject();
2682
+ if (i) {
2683
+ var o = {
2684
+ lockMovementX: !1,
2685
+ lockMovementY: !1,
2686
+ lockRotation: !1,
2687
+ lockScalingX: !1,
2688
+ lockScalingY: !1,
2689
+ lockSkewingX: !1,
2690
+ lockSkewingY: !1,
2691
+ locked: !1
2692
+ };
2693
+ i.set(o), ["activeselection", "group"].includes(i.type) && i.getObjects().forEach((s) => {
2694
+ s.set(o);
2695
+ }), a.renderAll(), t || r.saveState(), a.fire("editor:object-unlocked", {
2696
+ object: i
2697
+ });
2698
+ }
2699
+ }
2700
+ }
2701
+ class Tt {
2702
+ /**
2703
+ * @param {object} options
2704
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
2705
+ */
2706
+ constructor(e) {
2707
+ var {
2708
+ editor: t
2709
+ } = e;
2710
+ this.editor = t;
2711
+ }
2712
+ /**
2713
+ * Группировка объектов
2714
+ * @param {Object} options
2715
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
2716
+ * @param {fabric.Object} options.object - массив объектов для группировки
2717
+ * @fires editor:objects-grouped
2718
+ */
2719
+ group() {
2720
+ var {
2721
+ object: e,
2722
+ withoutSave: t
2723
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
2724
+ canvas: a,
2725
+ historyManager: r
2726
+ } = this.editor;
2727
+ r.suspendHistory();
2728
+ var i = e || a.getActiveObject();
2729
+ if (i && i.type === "activeselection") {
2730
+ var o = i.getObjects(), s = new ze(o);
2731
+ o.forEach((c) => a.remove(c)), s.set("id", "".concat(s.type, "-").concat(p())), a.add(s), a.setActiveObject(s), a.renderAll(), r.resumeHistory(), t || r.saveState(), a.fire("editor:objects-grouped");
2732
+ }
2733
+ }
2734
+ /**
2735
+ * Разгруппировка объектов
2736
+ * @param {Object} options
2737
+ * @param {fabric.Group} options.object - объект для разгруппировки
2738
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
2739
+ * @fires editor:objects-ungrouped
2740
+ */
2741
+ ungroup() {
2742
+ var {
2743
+ object: e,
2744
+ withoutSave: t
2745
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
2746
+ canvas: a,
2747
+ historyManager: r
2748
+ } = this.editor;
2749
+ r.suspendHistory();
2750
+ var i = e || a.getActiveObject();
2751
+ if (!(!i || i.type !== "group")) {
2752
+ var o = i.removeAll();
2753
+ a.remove(i), o.forEach((c) => a.add(c));
2754
+ var s = new k(o, {
2755
+ canvas: a
2756
+ });
2757
+ a.setActiveObject(s), a.renderAll(), r.resumeHistory(), t || r.saveState(), a.fire("editor:objects-ungrouped");
2758
+ }
2759
+ }
2760
+ }
2761
+ class Et {
2762
+ /**
2763
+ * @param {object} options
2764
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
2765
+ */
2766
+ constructor(e) {
2767
+ var {
2768
+ editor: t
2769
+ } = e;
2770
+ this.editor = t;
2771
+ }
2772
+ /**
2773
+ * Выделить все объекты
2774
+ * @fires editor:all-objects-selected
2775
+ */
2776
+ selectAll() {
2777
+ var {
2778
+ canvas: e,
2779
+ canvasManager: t
2780
+ } = this.editor;
2781
+ e.discardActiveObject();
2782
+ var a = new k(t.getObjects(), {
2783
+ canvas: e
2784
+ });
2785
+ e.setActiveObject(a), e.requestRenderAll(), e.fire("editor:all-objects-selected", {
2786
+ selected: a
2787
+ });
2788
+ }
2789
+ }
2790
+ class Zt {
2791
+ /**
2792
+ * @param {object} options
2793
+ * @param {ImageEditor} options.editor - экземпляр редактора с доступом к canvas
2794
+ */
2795
+ constructor(e) {
2796
+ var {
2797
+ editor: t
2798
+ } = e;
2799
+ this.editor = t;
2800
+ }
2801
+ /**
2802
+ * Удалить выбранные объекты
2803
+ * @param {Object} options
2804
+ * @param {fabric.Object[]} options.objects - массив объектов для удаления
2805
+ * @param {Boolean} options.withoutSave - Не сохранять состояние
2806
+ * @fires editor:object-deleted
2807
+ */
2808
+ deleteSelectedObjects() {
2809
+ var {
2810
+ objects: e,
2811
+ withoutSave: t
2812
+ } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, {
2813
+ canvas: a,
2814
+ historyManager: r
2815
+ } = this.editor;
2816
+ r.suspendHistory();
2817
+ var i = e || a.getActiveObjects();
2818
+ i != null && i.length && (i.forEach((o) => {
2819
+ if (o.type === "group" && o.format !== "svg") {
2820
+ this.ungroup(o), this.deleteSelectedObjects();
2821
+ return;
2822
+ }
2823
+ a.remove(o);
2824
+ }), a.discardActiveObject(), a.renderAll(), r.resumeHistory(), t || r.saveState(), a.fire("editor:objects-deleted"));
2825
+ }
2826
+ }
2827
+ function be(n, e, t, a, r, i, o) {
2828
+ try {
2829
+ var s = n[i](o), c = s.value;
2830
+ } catch (d) {
2831
+ return void t(d);
2832
+ }
2833
+ s.done ? e(c) : Promise.resolve(c).then(a, r);
2834
+ }
2835
+ function Bt(n) {
2836
+ return function() {
2837
+ var e = this, t = arguments;
2838
+ return new Promise(function(a, r) {
2839
+ var i = n.apply(e, t);
2840
+ function o(c) {
2841
+ be(i, a, r, o, s, "next", c);
2842
+ }
2843
+ function s(c) {
2844
+ be(i, a, r, o, s, "throw", c);
2845
+ }
2846
+ o(void 0);
2847
+ });
2848
+ };
2849
+ }
2850
+ class kt {
2851
+ constructor(e) {
2852
+ var t = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
2853
+ this.options = t;
2854
+ var {
2855
+ defaultScale: a,
2856
+ minZoom: r,
2857
+ maxZoom: i
2858
+ } = t;
2859
+ this.containerId = e, this.editorId = "".concat(e, "-").concat(p()), this.clipboard = null, this.defaultZoom = a, this.minZoom = r || vt, this.maxZoom = i || mt, this.init();
2860
+ }
2861
+ init() {
2862
+ var e = this;
2863
+ return Bt(function* () {
2864
+ var {
2865
+ editorContainerWidth: t,
2866
+ editorContainerHeight: a,
2867
+ canvasWrapperWidth: r,
2868
+ canvasWrapperHeight: i,
2869
+ canvasCSSWidth: o,
2870
+ canvasCSSHeight: s,
2871
+ initialImage: c,
2872
+ initialStateJSON: d,
2873
+ scaleType: l,
2874
+ _onReadyCallback: u
2875
+ } = e.options;
2876
+ if ($e.apply(), e.canvas = new Ye(e.containerId, e.options), e.moduleLoader = new Pe(), e.workerManager = new Re(), e.historyManager = new gt({
2877
+ editor: e
2878
+ }), e.toolbar = new lt({
2879
+ editor: e
2880
+ }), e.transformManager = new yt({
2881
+ editor: e
2882
+ }), e.canvasManager = new jt({
2883
+ editor: e
2884
+ }), e.imageManager = new L({
2885
+ editor: e
2886
+ }), e.layerManager = new H({
2887
+ editor: e
2888
+ }), e.shapeManager = new Dt({
2889
+ editor: e
2890
+ }), e.interactionBlocker = new bt({
2891
+ editor: e
2892
+ }), e.clipboardManager = new Lt({
2893
+ editor: e
2894
+ }), e.objectLockManager = new Ot({
2895
+ editor: e
2896
+ }), e.groupingManager = new Tt({
2897
+ editor: e
2898
+ }), e.selectionManager = new Et({
2899
+ editor: e
2900
+ }), e.deletionManager = new Zt({
2901
+ editor: e
2902
+ }), e._createMonageArea(), e._createClippingArea(), e.listeners = new Ve({
2903
+ editor: e,
2904
+ options: e.options
2905
+ }), e.canvasManager.setEditorContainerWidth(t), e.canvasManager.setEditorContainerHeight(a), e.canvasManager.setCanvasWrapperWidth(r), e.canvasManager.setCanvasWrapperHeight(i), e.canvasManager.setCanvasCSSWidth(o), e.canvasManager.setCanvasCSSHeight(s), c != null && c.source) {
2906
+ var {
2907
+ source: g,
2908
+ scale: h = "image-".concat(l),
2909
+ withoutSave: f = !0,
2910
+ contentType: v
2911
+ } = c;
2912
+ yield e.imageManager.importImage({
2913
+ source: g,
2914
+ scale: h,
2915
+ withoutSave: f,
2916
+ contentType: v
2917
+ });
2918
+ } else
2919
+ e.canvasManager.setDefaultScale({
2920
+ withoutSave: !0
2921
+ });
2922
+ d && e.historyManager.loadStateFromFullState(d), e.historyManager.saveState(), console.log("editor:ready"), e.canvas.fire("editor:ready", e), typeof u == "function" && u(e);
2923
+ })();
2924
+ }
2925
+ /**
2926
+ * Создаёт монтажную область
2927
+ * @private
2928
+ * @returns {void}
2929
+ */
2930
+ _createMonageArea() {
2931
+ var {
2932
+ montageAreaWidth: e,
2933
+ montageAreaHeight: t
2934
+ } = this.options;
2935
+ this.montageArea = this.shapeManager.addRectangle({
2936
+ width: e,
2937
+ height: t,
2938
+ fill: ht(),
2939
+ stroke: null,
2940
+ strokeWidth: 0,
2941
+ selectable: !1,
2942
+ hasBorders: !1,
2943
+ hasControls: !1,
2944
+ evented: !1,
2945
+ id: "montage-area",
2946
+ originX: "center",
2947
+ originY: "center",
2948
+ objectCaching: !1,
2949
+ noScaleCache: !0
2950
+ }, {
2951
+ withoutSelection: !0
2952
+ });
2953
+ }
2954
+ /**
2955
+ * Создаёт область клиппинга
2956
+ * @private
2957
+ * @returns {void}
2958
+ */
2959
+ _createClippingArea() {
2960
+ var {
2961
+ montageAreaWidth: e,
2962
+ montageAreaHeight: t
2963
+ } = this.options;
2964
+ this.canvas.clipPath = this.shapeManager.addRectangle({
2965
+ id: "area-clip",
2966
+ width: e,
2967
+ height: t,
2968
+ stroke: null,
2969
+ fill: null,
2970
+ strokeWidth: 0,
2971
+ hasBorders: !1,
2972
+ hasControls: !1,
2973
+ selectable: !1,
2974
+ evented: !1,
2975
+ originX: "center",
2976
+ originY: "center"
2977
+ }, {
2978
+ withoutSelection: !0,
2979
+ withoutAdding: !0
2980
+ });
2981
+ }
2982
+ /**
2983
+ * Метод для удаления редактора и всех слушателей.
2984
+ */
2985
+ destroy() {
2986
+ this.listeners.destroy(), this.toolbar.destroy(), this.canvas.dispose(), this.workerManager.worker.terminate(), this.imageManager.revokeBlobUrls();
2987
+ }
2988
+ }
2989
+ const xt = {
2990
+ // Cохраняют ли объекты свой текущий порядок (z-index) при выделении
2991
+ preserveObjectStacking: !0,
2992
+ // Возможность взаимодействия с объектом за пределами монтажной области
2993
+ controlsAboveOverlay: !0,
2994
+ // Зум по центру
2995
+ centeredScaling: !0,
2996
+ // Поворот объекта по центру
2997
+ centeredRotation: !0,
2998
+ /*
2999
+ * Кастомные опции
3000
+ */
3001
+ // Canvas Montage Area width and height
3002
+ montageAreaWidth: 512,
3003
+ montageAreaHeight: 512,
3004
+ // Canvas backstore width and height
3005
+ canvasBackstoreWidth: "auto",
3006
+ canvasBackstoreHeight: "auto",
3007
+ // Canvas (upper & lower) CSS width and height
3008
+ canvasCSSWidth: "100%",
3009
+ canvasCSSHeight: "100%",
3010
+ // Wrapper CSS width and height
3011
+ canvasWrapperWidth: "100%",
3012
+ canvasWrapperHeight: "100%",
3013
+ // Container CSS width and height
3014
+ editorContainerWidth: "fit-content",
3015
+ editorContainerHeight: "100%",
3016
+ // Дефолтный тип скейлинга для объектов (cotain/cover)
3017
+ scaleType: "contain",
3018
+ // Показывать панель инструментов для выделенного объекта
3019
+ showToolbar: !0,
3020
+ // Настройки панели инструментов выделенного объекта.
3021
+ // Можно передать массив с названиями действий или объект с настройками, кастомными иконками и обработчиками
3022
+ // ui/toolbar-manager/default-config.js
3023
+ toolbar: {
3024
+ lockedActions: [{
3025
+ name: "Разблокировать",
3026
+ handle: "unlock"
3027
+ }],
3028
+ actions: [{
3029
+ name: "Создать копию",
3030
+ handle: "copyPaste"
3031
+ }, {
3032
+ name: "Заблокировать",
3033
+ handle: "lock"
3034
+ }, {
3035
+ name: "На передний план",
3036
+ handle: "bringToFront"
3037
+ }, {
3038
+ name: "На задний план",
3039
+ handle: "sendToBack"
3040
+ }, {
3041
+ name: "На один уровень вверх",
3042
+ handle: "bringForward"
3043
+ }, {
3044
+ name: "На один уровень вниз",
3045
+ handle: "sendBackwards"
3046
+ }, {
3047
+ name: "Удалить",
3048
+ handle: "delete"
3049
+ }]
3050
+ },
3051
+ // Можно передать JSON объект в виде строки для инициализации редактора
3052
+ initialStateJSON: null,
3053
+ /*
3054
+ * Объект изображения с которым редактор будет инициализирован. Может содержать:
3055
+ * - {String} url - URL изображения (обязательный)
3056
+ * - {String} scaleType - Тип скейлинга (image-contain/image-cover/scale-montage)
3057
+ * - {Boolean} withoutSave - Не сохранять состояние редактора (по умолчанию false)
3058
+ */
3059
+ initialImage: null,
3060
+ // Дефолтный масштаб
3061
+ defaultScale: 1,
3062
+ // Минимальный и максимальный зум
3063
+ minZoom: 0.1,
3064
+ maxZoom: 2,
3065
+ // Максимальная кратность зума относительно текущего defaultZoom
3066
+ maxZoomFactor: 2,
3067
+ // Шаг зума
3068
+ zoomRatio: 0.1,
3069
+ overlayMaskColor: "rgba(136, 136, 136, 0.6)",
3070
+ /*
3071
+ * Настройки слушателей событий
3072
+ */
3073
+ // Адаптировать канвас при изменении размеров контейнера (например, при изменении размеров окна браузера)
3074
+ adaptCanvasToContainer: !0,
3075
+ // Поднимать объект на передний план по оси Z при выделении
3076
+ bringToFrontOnSelection: !1,
3077
+ // Зум по колесику мыши
3078
+ mouseWheelZooming: !0,
3079
+ // Перемещение канваса при зажатой кнопке ALT
3080
+ canvasDragging: !1,
3081
+ // Копирование объектов (Ctrl + C, Ctrl + V)
3082
+ copyObjectsByHotkey: !0,
3083
+ // Вставка изображения из буфера обмена
3084
+ pasteImageFromClipboard: !0,
3085
+ // Отмена/повтор действия по сочетанию клавиш (Ctrl + Z, Ctrl + Y)
3086
+ undoRedoByHotKeys: !0,
3087
+ // Выделение всех объектов по сочетанию клавиш (Ctrl + A)
3088
+ selectAllByHotkey: !0,
3089
+ // Удаление объектов по сочетанию клавиш (Delete)
3090
+ deleteObjectsByHotkey: !0,
3091
+ // Сброс параметров объекта по двойному клику
3092
+ resetObjectFitByDoubleClick: !0
3093
+ };
3094
+ function Ie(n, e) {
3095
+ var t = Object.keys(n);
3096
+ if (Object.getOwnPropertySymbols) {
3097
+ var a = Object.getOwnPropertySymbols(n);
3098
+ e && (a = a.filter(function(r) {
3099
+ return Object.getOwnPropertyDescriptor(n, r).enumerable;
3100
+ })), t.push.apply(t, a);
3101
+ }
3102
+ return t;
3103
+ }
3104
+ function pe(n) {
3105
+ for (var e = 1; e < arguments.length; e++) {
3106
+ var t = arguments[e] != null ? arguments[e] : {};
3107
+ e % 2 ? Ie(Object(t), !0).forEach(function(a) {
3108
+ zt(n, a, t[a]);
3109
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(n, Object.getOwnPropertyDescriptors(t)) : Ie(Object(t)).forEach(function(a) {
3110
+ Object.defineProperty(n, a, Object.getOwnPropertyDescriptor(t, a));
3111
+ });
3112
+ }
3113
+ return n;
3114
+ }
3115
+ function zt(n, e, t) {
3116
+ return (e = Yt(e)) in n ? Object.defineProperty(n, e, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : n[e] = t, n;
3117
+ }
3118
+ function Yt(n) {
3119
+ var e = Wt(n, "string");
3120
+ return typeof e == "symbol" ? e : e + "";
3121
+ }
3122
+ function Wt(n, e) {
3123
+ if (typeof n != "object" || !n) return n;
3124
+ var t = n[Symbol.toPrimitive];
3125
+ if (t !== void 0) {
3126
+ var a = t.call(n, e);
3127
+ if (typeof a != "object") return a;
3128
+ throw new TypeError("@@toPrimitive must return a primitive value.");
3129
+ }
3130
+ return (e === "string" ? String : Number)(n);
3131
+ }
3132
+ function Vt(n) {
3133
+ var e = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, t = pe(pe({}, xt), e), a = document.getElementById(n);
3134
+ if (!a)
3135
+ return Promise.reject(new Error('Контейнер с ID "'.concat(n, '" не найден.')));
3136
+ var r = document.createElement("canvas");
3137
+ return r.id = "".concat(n, "-canvas"), a.appendChild(r), t.editorContainer = a, new Promise((i) => {
3138
+ t._onReadyCallback = i;
3139
+ var o = new kt(r.id, t);
3140
+ window[n] = o;
3141
+ });
3142
+ }
3143
+ export {
3144
+ Vt as default
3145
+ };
3146
+ //# sourceMappingURL=main.js.map