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