@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.
- package/dist/main.js +3146 -0
- package/package.json +46 -0
- 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
|