@syncfusion/ej2-image-editor 30.2.4 → 31.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/ej2-image-editor.umd.min.js +2 -2
  2. package/dist/ej2-image-editor.umd.min.js.map +1 -1
  3. package/dist/es6/ej2-image-editor.es2015.js +3 -3
  4. package/dist/es6/ej2-image-editor.es2015.js.map +1 -1
  5. package/dist/es6/ej2-image-editor.es5.js +3 -3
  6. package/dist/es6/ej2-image-editor.es5.js.map +1 -1
  7. package/dist/global/ej2-image-editor.min.js +2 -2
  8. package/dist/global/ej2-image-editor.min.js.map +1 -1
  9. package/dist/global/index.d.ts +1 -1
  10. package/dist/ts/image-editor/action/crop.d.ts +44 -0
  11. package/dist/ts/image-editor/action/crop.ts +867 -0
  12. package/dist/ts/image-editor/action/draw.d.ts +187 -0
  13. package/dist/ts/image-editor/action/draw.ts +4924 -0
  14. package/dist/ts/image-editor/action/export.d.ts +29 -0
  15. package/dist/ts/image-editor/action/export.ts +509 -0
  16. package/dist/ts/image-editor/action/filter.d.ts +48 -0
  17. package/dist/ts/image-editor/action/filter.ts +872 -0
  18. package/dist/ts/image-editor/action/freehand-draw.d.ts +68 -0
  19. package/dist/ts/image-editor/action/freehand-draw.ts +1135 -0
  20. package/dist/ts/image-editor/action/index.d.ts +9 -0
  21. package/dist/ts/image-editor/action/index.ts +9 -0
  22. package/dist/ts/image-editor/action/selection.d.ts +178 -0
  23. package/dist/ts/image-editor/action/selection.ts +5241 -0
  24. package/dist/ts/image-editor/action/shape.d.ts +130 -0
  25. package/dist/ts/image-editor/action/shape.ts +3917 -0
  26. package/dist/ts/image-editor/action/transform.d.ts +77 -0
  27. package/dist/ts/image-editor/action/transform.ts +2008 -0
  28. package/dist/ts/image-editor/action/undo-redo.d.ts +52 -0
  29. package/dist/ts/image-editor/action/undo-redo.ts +1169 -0
  30. package/dist/ts/image-editor/base/enum.d.ts +277 -0
  31. package/dist/ts/image-editor/base/enum.ts +288 -0
  32. package/dist/ts/image-editor/base/image-editor-model.d.ts +770 -0
  33. package/dist/ts/image-editor/base/image-editor.d.ts +1928 -0
  34. package/dist/ts/image-editor/base/image-editor.ts +5496 -0
  35. package/dist/ts/image-editor/base/index.d.ts +4 -0
  36. package/dist/ts/image-editor/base/index.ts +4 -0
  37. package/dist/ts/image-editor/base/interface.d.ts +1637 -0
  38. package/dist/ts/image-editor/base/interface.ts +1709 -0
  39. package/dist/ts/image-editor/index.d.ts +3 -0
  40. package/dist/ts/image-editor/index.ts +3 -0
  41. package/dist/ts/image-editor/renderer/index.d.ts +1 -0
  42. package/dist/ts/image-editor/renderer/index.ts +1 -0
  43. package/dist/ts/image-editor/renderer/toolbar.d.ts +171 -0
  44. package/dist/ts/image-editor/renderer/toolbar.ts +6356 -0
  45. package/dist/ts/index.d.ts +4 -0
  46. package/dist/ts/index.ts +4 -0
  47. package/package.json +47 -15
  48. package/src/image-editor/action/undo-redo.js +3 -3
@@ -0,0 +1,867 @@
1
+ import { Browser, extend, isNullOrUndefined } from '@syncfusion/ej2-base';
2
+ import { ActivePoint, Dimension } from '@syncfusion/ej2-inputs';
3
+ import { CropEventArgs, CurrentObject, ImageEditor, Point, SelectionPoint, ImageDimension } from '../index';
4
+
5
+ export class Crop {
6
+ private parent: ImageEditor;
7
+ private lowerContext: CanvasRenderingContext2D;
8
+ private upperContext: CanvasRenderingContext2D;
9
+ private prevCropCurrObj: CurrentObject;
10
+ private croppedDegree: number = 0; // Specifies the degree when crop is performed
11
+ private cropDestPoints: ActivePoint = {startX: 0, startY: 0, width: 0, height: 0} as ActivePoint; // To redraw old image when navigate to crop tab
12
+ private tempFlipPanPoint: Point = {x: 0, y: 0};
13
+ private isPreventScaling: boolean = false;
14
+ private isInitCrop: boolean = false;
15
+ private isTransformCrop: boolean = false;
16
+
17
+ constructor(parent: ImageEditor) {
18
+ this.parent = parent;
19
+ this.addEventListener();
20
+ }
21
+
22
+ public destroy(): void {
23
+ if (this.parent.isDestroyed) { return; }
24
+ this.removeEventListener();
25
+ }
26
+
27
+ private addEventListener(): void {
28
+ this.parent.on('crop', this.cropping, this);
29
+ this.parent.on('destroyed', this.destroy, this);
30
+ }
31
+
32
+ private removeEventListener(): void {
33
+ this.parent.off('crop', this.cropping);
34
+ this.parent.off('destroyed', this.destroy);
35
+ }
36
+
37
+ private cropping(args?: { onPropertyChange: boolean, prop: string, value?: object }): void {
38
+ this.updateCropPvtVar();
39
+ switch (args.prop) {
40
+ case 'cropCircle':
41
+ this.cropCircle(args.value['context'], args.value['isSave'], args.value['isFlip']);
42
+ break;
43
+ case 'setCurrSelPoints':
44
+ this.setCurrSelPoints(args.value['isSetDimension']);
45
+ break;
46
+ case 'updateRotatePan':
47
+ this.updateRotatePan();
48
+ break;
49
+ case 'crop':
50
+ this.crop(args.value['obj']);
51
+ break;
52
+ case 'calcRatio':
53
+ this.calcRatio(args.value['obj'], args.value['dimension']);
54
+ break;
55
+ case 'getCurrFlipState':
56
+ this.getCurrFlipState(args.value['panObj']);
57
+ break;
58
+ case 'getPreviousCropCurrentObj':
59
+ args.value['obj']['prevObj'] = this.prevCropCurrObj;
60
+ break;
61
+ case 'setPreviousCropCurrentObj':
62
+ this.prevCropCurrObj = args.value['obj'];
63
+ break;
64
+ case 'setCropDestPoints':
65
+ this.cropDestPoints = args.value['point'];
66
+ break;
67
+ case 'getTempFlipPanPoint':
68
+ args.value['obj']['point'] = this.tempFlipPanPoint;
69
+ break;
70
+ case 'setTempFlipPanPoint':
71
+ if (isNullOrUndefined(args.value['isAdd'])) {
72
+ this.tempFlipPanPoint = args.value['point'];
73
+ } else {
74
+ this.tempFlipPanPoint.x += args.value['point'].x;
75
+ this.tempFlipPanPoint.y += args.value['point'].y;
76
+ }
77
+ break;
78
+ case 'getPreventScaling':
79
+ args.value['obj']['bool'] = this.isPreventScaling;
80
+ break;
81
+ case 'adjustStraightenForShapes':
82
+ this.adjustStraightenForShapes(args.value['type'], args.value['isInitialRotated']);
83
+ break;
84
+ case 'resizeWrapper':
85
+ this.resizeWrapper();
86
+ break;
87
+ case 'setTransformCrop':
88
+ this.isTransformCrop = args.value['bool'];
89
+ break;
90
+ case 'setInitCrop':
91
+ this.isInitCrop = args.value['bool'];
92
+ break;
93
+ case 'resetZoom':
94
+ this.resetZoom();
95
+ break;
96
+ case 'revertTransform':
97
+ this.revertTransform(args.value['type'], args.value['coll']);
98
+ break;
99
+ case 'reset':
100
+ this.reset();
101
+ break;
102
+ }
103
+ }
104
+
105
+ public getModuleName(): string {
106
+ return 'crop';
107
+ }
108
+
109
+ private updateCropPvtVar(): void {
110
+ const parent: ImageEditor = this.parent;
111
+ if (parent.lowerCanvas) {this.lowerContext = parent.lowerCanvas.getContext('2d'); }
112
+ if (parent.upperCanvas) {this.upperContext = parent.upperCanvas.getContext('2d'); }
113
+ }
114
+
115
+ private reset(): void {
116
+ this.prevCropCurrObj = null; this.croppedDegree = 0;
117
+ this.cropDestPoints = {startX: 0, startY: 0, width: 0, height: 0} as ActivePoint;
118
+ this.tempFlipPanPoint = {x: 0, y: 0}; this.isPreventScaling = false; this.isInitCrop = false;
119
+ this.isTransformCrop = false;
120
+ }
121
+
122
+ private cropImg(isRotateCrop?: boolean): void {
123
+ const parent: ImageEditor = this.parent; const isNullCrop: boolean = isNullOrUndefined(isRotateCrop);
124
+ const resizeIcon: HTMLInputElement = (parent.element.querySelector('#' + parent.element.id + '_nonaspectratio') as HTMLInputElement);
125
+ const actPoint: ActivePoint = parent.activeObj.activePoint; const img: ImageDimension = parent.img; let isRotated: boolean = false;
126
+ for (let i: number = 0, len: number = parent.rotateFlipColl.length; i < len; i++) {
127
+ const currentValue: number = parent.rotateFlipColl[i as number];
128
+ if (currentValue === 90 || currentValue === -90) {
129
+ isRotated = true;
130
+ }
131
+ }
132
+ parent.notify('draw', { prop: 'setImageEdited', onPropertyChange: false });
133
+ if (isNullCrop || resizeIcon) {
134
+ this.croppedDegree = parent.transform.degree;
135
+ }
136
+ if (isNullCrop && (parent.transform.degree !== 0) || isRotated) {
137
+ this.updateCropObj();
138
+ const point: ActivePoint = {startX: img.destLeft, startY: img.destTop, width: img.destWidth, height: img.destHeight};
139
+ parent.notify('transform', { prop: 'setCurrDestinationPoint', onPropertyChange: false, value: {point: point }});
140
+ this.rotateCrop();
141
+ } else if (isNullCrop && parent.transform.currFlipState !== '') {
142
+ this.updateCropObj();
143
+ const point: ActivePoint = {startX: img.destLeft, startY: img.destTop, width: img.destWidth, height: img.destHeight};
144
+ parent.notify('transform', { prop: 'setCurrDestinationPoint', onPropertyChange: false, value: {point: point }});
145
+ this.flipCrop();
146
+ } else {
147
+ this.adjustStraightenForShapes('initial', false);
148
+ parent.notify('draw', { prop: 'setTempZoomFactor', onPropertyChange: false, value: {tempZoomFactor: parent.transform.zoomFactor }});
149
+ const ratio: Dimension = this.calcRatio();
150
+ if (isNullCrop || !isRotateCrop) { // isRotateCrop is NULL or False
151
+ this.updateCropObj();
152
+ parent.notify('draw', { prop: 'resetPanPoints', onPropertyChange: false});
153
+ parent.notify('shape', { prop: 'updImgRatioForActObj', onPropertyChange: false});
154
+ const point: ActivePoint = {startX: img.destLeft, startY: img.destTop, width: img.destWidth, height: img.destHeight};
155
+ parent.notify('transform', { prop: 'setCurrDestinationPoint', onPropertyChange: false, value: {point: point }});
156
+ parent.currSelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
157
+ this.cropDestPoints = {startX: img.destLeft, startY: img.destTop, width: img.destWidth, height: img.destHeight};
158
+ }
159
+ const obj: Object = {width: 0, height: 0 };
160
+ parent.notify('transform', { prop: 'calcMaxDimension', onPropertyChange: false, value: {width: actPoint.width * ratio.width,
161
+ height: actPoint.height * ratio.height, obj: obj, isImgShape: null }});
162
+ const maxDimension: Dimension = obj as Dimension;
163
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
164
+ this.lowerContext.clearRect(0, 0, parent.lowerCanvas.width, parent.lowerCanvas.height);
165
+ parent.img = { srcLeft: (actPoint.startX * ratio.width) - (img.destLeft * ratio.width),
166
+ srcTop: (actPoint.startY * ratio.height) - (img.destTop * ratio.height),
167
+ srcWidth: (actPoint.width * ratio.width), srcHeight: (actPoint.height * ratio.height),
168
+ destLeft: (parent.lowerCanvas.clientWidth - maxDimension.width) / 2,
169
+ destTop: (parent.lowerCanvas.clientHeight - maxDimension.height) / 2,
170
+ destWidth: maxDimension.width, destHeight: maxDimension.height };
171
+ const temp: string = this.lowerContext.filter;
172
+ parent.notify('draw', { prop: 'drawImage', onPropertyChange: false});
173
+ this.lowerContext.filter = 'none';
174
+ const activeObj: SelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
175
+ this.cropObjColl();
176
+ parent.transform.straighten = 0;
177
+ parent.activeObj = activeObj;
178
+ this.cropFreehandDrawColl();
179
+ parent.shapeColl = [];
180
+ parent.notify('shape', { prop: 'updateShapeColl', onPropertyChange: false });
181
+ parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
182
+ value: {ctx: this.lowerContext, shape: 'zoom', pen: 'zoom', isPreventApply: null }});
183
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.lowerContext}});
184
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.upperContext}});
185
+ if (parent.currSelectionPoint && parent.currSelectionPoint.shape === 'crop-circle') {this.cropCircle(this.lowerContext); }
186
+ else {parent.isCircleCrop = false; }
187
+ this.lowerContext.filter = temp;
188
+ parent.notify('shape', { prop: 'refreshActiveObj', onPropertyChange: false});
189
+ parent.currObjType.isCustomCrop = false;
190
+ parent.pan(false);
191
+ parent.transform.defaultZoomFactor = 0;
192
+ }
193
+ }
194
+
195
+ private adjustStraightenForShapes(type: string, isInitialRotated: boolean): void {
196
+ const parent: ImageEditor = this.parent;
197
+ const center: Point = {
198
+ x: parent.img.destLeft + parent.img.destWidth / 2,
199
+ y: parent.img.destTop + parent.img.destHeight / 2
200
+ };
201
+ for (const obj of parent.objColl) {
202
+ if (['rectangle', 'ellipse', 'text', 'image', 'redact'].indexOf(obj.shape) !== -1) {
203
+ if (isInitialRotated || obj.rotatedAngle !== 0) {
204
+ const { startX, startY, width, height } = obj.activePoint;
205
+ const angle: number = type === 'initial' ? obj.rotatedAngle : -obj.rotatedAngle;
206
+ const diffX: number = startX + width / 2 - center.x;
207
+ const diffY: number = startY + height / 2 - center.y;
208
+ const cosAngle: number = Math.cos(angle);
209
+ const sinAngle: number = Math.sin(angle);
210
+ const centerX: number = cosAngle * diffX - sinAngle * diffY + center.x;
211
+ const centerY: number = sinAngle * diffX + cosAngle * diffY + center.y;
212
+ const diffXUpdated: number = centerX - startX - width / 2;
213
+ const diffYUpdated: number = centerY - startY - height / 2;
214
+ obj.activePoint.startX += diffXUpdated; obj.activePoint.startY += diffYUpdated;
215
+ obj.activePoint.endX += diffXUpdated; obj.activePoint.endY += diffYUpdated;
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ private updateCropObj(): void {
222
+ this.parent.afterCropActions = []; const object: Object = {currObj: {} as CurrentObject };
223
+ this.parent.notify('filter', { prop: 'getCurrentObj', onPropertyChange: false, value: {object: object }});
224
+ const obj: CurrentObject = object['currObj']; obj.straighten = this.parent.transform.straighten;
225
+ this.parent.cropObj = extend({}, obj, {}, true) as CurrentObject;
226
+ }
227
+
228
+ private rotateCrop(): void {
229
+ const parent: ImageEditor = this.parent;
230
+ const flipState: string = this.getCurrFlipState();
231
+ const shape: string = parent.activeObj.shape || '';
232
+ parent.notify('shape', { prop: 'updImgRatioForActObj', onPropertyChange: false});
233
+ parent.currSelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
234
+ parent.objColl.push(parent.activeObj);
235
+ parent.activeObj = extend({}, parent.objColl[parent.objColl.length - 1], {}, true) as SelectionPoint;
236
+ let activeObj: SelectionPoint = extend({}, parent.objColl[parent.objColl.length - 1], {}, true) as SelectionPoint;
237
+ const tempCurrSelObj: SelectionPoint = extend({}, parent.currSelectionPoint, {}, true) as SelectionPoint;
238
+ const preventSelObj: Object = {bool: null };
239
+ parent.notify('transform', { prop: 'getPreventSelect', onPropertyChange: false, value: {obj: preventSelObj }});
240
+ parent.notify('transform', { prop: 'setPreventSelect', onPropertyChange: false, value: {bool: true }});
241
+ const coll: string[] | number[] = extend([], parent.rotateFlipColl, [], true) as string[] | number[];
242
+ this.panToSelRangle(true);
243
+ activeObj = extend({}, parent.objColl[parent.objColl.length - 1], {}, true) as SelectionPoint;
244
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
245
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: 'duplicate', obj: activeObj}});
246
+ parent.objColl.pop();
247
+ parent.notify('shape', { prop: 'updImgRatioForActObj', onPropertyChange: false});
248
+ parent.objColl.push(parent.activeObj);
249
+ // For reverse straightening
250
+ const straighten: number = parent.transform.straighten;
251
+ if (straighten !== 0) {
252
+ parent.transform.straighten = 0;
253
+ parent.straightenBaseImageCanvas();
254
+ parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
255
+ value: {ctx: this.lowerContext, shape: 'zoom', pen: 'zoom', isPreventApply: null }});
256
+ parent.notify('shape', { prop: 'refreshActiveObj', onPropertyChange: false });
257
+ parent.notify('draw', { prop: 'render-image', value: { isMouseWheel: false } });
258
+ }
259
+ this.resetZoom();
260
+ const afterCropActions: string[] = extend([], parent.afterCropActions, [], true) as string[];
261
+ this.revertTransform('initial', coll);
262
+ // Perform straighten
263
+ if (straighten !== 0) {
264
+ parent.transform.straighten = (flipState === 'horizontal' || flipState === 'vertical') ? -straighten : straighten;
265
+ parent.straightenBaseImageCanvas();
266
+ parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
267
+ value: {ctx: this.lowerContext, shape: 'zoom', pen: 'zoom', isPreventApply: null }});
268
+ parent.notify('draw', { prop: 'render-image', value: { isMouseWheel: false } });
269
+ parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
270
+ value: {ctx: this.lowerContext, shape: 'zoom', pen: 'zoom', isPreventApply: null }});
271
+ }
272
+ activeObj = extend({}, parent.objColl[parent.objColl.length - 1], {}, true) as SelectionPoint;
273
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
274
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: 'duplicate', obj: activeObj}});
275
+ parent.objColl.pop(); parent.transform.degree = 0;
276
+ // Checking for selection inside image
277
+ const object: Object = {isIntersect: null };
278
+ parent.notify('draw', { prop: 'updateImgCanvasPoints', onPropertyChange: false });
279
+ parent.notify('draw', { prop: 'isLinesIntersect', onPropertyChange: false, value: {obj: object }});
280
+ let count: number = 0;
281
+ while (straighten !== 0 && object['isIntersect']) {
282
+ count++;
283
+ if (count === 50) {break; }
284
+ parent.notify('transform', { prop: 'zoomAction', onPropertyChange: false,
285
+ value: {zoomFactor: 0.025, zoomPoint: null}, isResize: null});
286
+ parent.notify('draw', { prop: 'updateImgCanvasPoints', onPropertyChange: false });
287
+ parent.notify('draw', { prop: 'isLinesIntersect', onPropertyChange: false, value: {obj: object }});
288
+ }
289
+ this.cropImg(true);
290
+ this.revertTransform('reverse', coll);
291
+ parent.afterCropActions = afterCropActions;
292
+ parent.currSelectionPoint = tempCurrSelObj;
293
+ parent.notify('transform', { prop: 'setPreventSelect', onPropertyChange: false, value: {bool: preventSelObj['bool'] }});
294
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.lowerContext}});
295
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.upperContext}});
296
+ if (shape === 'crop-circle') {this.cropCircle(this.lowerContext); }
297
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
298
+ parent.notify('draw', { prop: 'resetPanPoints', onPropertyChange: false});
299
+ }
300
+
301
+ private revertTransform(type: string, coll: string[] | number[]): void {
302
+ const parent: ImageEditor = this.parent;
303
+ const obj: Object = {isRotate: false };
304
+ if (type === 'initial') {
305
+ for (let i: number = coll.length - 1; i >= 0; i--) {
306
+ const value: number = coll[i as number] as number;
307
+ switch (value) {
308
+ case 90:
309
+ parent.notify('transform', {prop: 'rotate', value: { degree: -90, obj: obj }});
310
+ break;
311
+ case -90:
312
+ parent.notify('transform', {prop: 'rotate', value: { degree: 90, obj: obj }});
313
+ break;
314
+ default:
315
+ parent.notify('transform', {prop: 'flipImage', value: { direction: parent.toPascalCase(value.toString()) }});
316
+ break;
317
+ }
318
+ }
319
+ } else {
320
+ this.updateFlipState();
321
+ for (let i: number = 0, len: number = coll.length; i < len; i++) {
322
+ const value: number = coll[i as number] as number;
323
+ switch (value) {
324
+ case 90:
325
+ parent.notify('transform', {prop: 'rotate', value: { degree: 90, obj: obj }});
326
+ break;
327
+ case -90:
328
+ parent.notify('transform', {prop: 'rotate', value: { degree: -90, obj: obj }});
329
+ break;
330
+ default:
331
+ parent.notify('transform', {prop: 'flipImage', value: { direction: parent.toPascalCase(value.toString()) }});
332
+ break;
333
+ }
334
+ }
335
+ }
336
+ }
337
+
338
+ private updateFlipState(): void {
339
+ const parent: ImageEditor = this.parent;
340
+ const objColl: SelectionPoint[] = parent.objColl as SelectionPoint[];
341
+ for (let i: number = 0, len: number = objColl.length; i < len; i++) {
342
+ objColl[i as number].shapeFlip = '';
343
+ }
344
+ // eslint-disable-next-line
345
+ let pointColl: any = parent.pointColl;
346
+ for (let i: number = 0; i < parent.freehandCounter; i++) {
347
+ pointColl[i as number].shapeFlip = '';
348
+ }
349
+ }
350
+
351
+ private resetZoom(): void {
352
+ const parent: ImageEditor = this.parent;
353
+ if (parent.transform.zoomFactor > 0) {
354
+ const zoomFactor: number = parent.transform.zoomFactor;
355
+ const isUndoRedo: boolean = parent.isUndoRedo;
356
+ parent.setProperties({zoomSettings: { zoomFactor: (zoomFactor * 10)}}, true);
357
+ parent.notify('transform', { prop: 'setPreviousZoomValue', onPropertyChange: false,
358
+ value: { previousZoomValue: parent.zoomSettings.zoomFactor } });
359
+ for (let i: number = 0; i < (zoomFactor * 10); i++) {
360
+ parent.isUndoRedo = true;
361
+ parent.notify('transform', { prop: 'zoomAction', onPropertyChange: false,
362
+ value: {zoomFactor: -0.1, zoomPoint: null}, isResize: null});
363
+ }
364
+ parent.isUndoRedo = isUndoRedo;
365
+ parent.notify('draw', { prop: 'resetPanPoints', onPropertyChange: false});
366
+ }
367
+ }
368
+
369
+ private flipCrop(): void {
370
+ const parent: ImageEditor = this.parent;
371
+ parent.notify('transform', { prop: 'setReverseFlip', onPropertyChange: false, value: {isReverseFlip: true }});
372
+ parent.panPoint.totalPannedPoint.x += this.tempFlipPanPoint.x;
373
+ parent.panPoint.totalPannedPoint.y += this.tempFlipPanPoint.y;
374
+ const tempCurrFlipState: string = parent.transform.currFlipState;
375
+ const obj: Object = {flipColl: null };
376
+ parent.notify('transform', { prop: 'getFlipColl', onPropertyChange: false, value: {obj: obj }});
377
+ const tempFlipColl: string[] = obj['flipColl'];
378
+ parent.notify('transform', { prop: 'setFlipColl', onPropertyChange: false, value: {flipColl: [] }});
379
+ parent.notify('shape', { prop: 'updImgRatioForActObj', onPropertyChange: false});
380
+ parent.objColl.push(parent.activeObj);
381
+ if (parent.transform.degree === 0) {
382
+ const panX: number = -parent.cropObj.totalPannedPoint.x; const panY: number = -parent.cropObj.totalPannedPoint.y;
383
+ parent.img.destLeft += panX; parent.img.destTop += panY;
384
+ parent.notify('transform', {prop: 'drawPannImage', value: {point: {x: panX , y: panY }}});
385
+ parent.activeObj = extend({}, parent.objColl[parent.objColl.length - 1], {}, true) as SelectionPoint;
386
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
387
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: { canvas: 'duplicate', obj: parent.activeObj } });
388
+ parent.objColl.pop();
389
+ parent.notify('shape', { prop: 'updImgRatioForActObj', onPropertyChange: false });
390
+ parent.objColl.push(parent.activeObj);
391
+ }
392
+ this.resetZoom();
393
+ parent.currSelectionPoint = extend({}, parent.objColl[parent.objColl.length - 1], {}, true) as SelectionPoint;
394
+ this.lowerContext.clearRect(0, 0, parent.lowerCanvas.width, parent.lowerCanvas.height);
395
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
396
+ const temp: string = this.lowerContext.filter;
397
+ parent.notify('draw', { prop: 'drawImage', onPropertyChange: false});
398
+ this.updateFlipState();
399
+ parent.notify('shape', { prop: 'redrawObj', onPropertyChange: false, value: {degree: this.getCurrFlipState()}});
400
+ parent.notify('freehand-draw', { prop: 'flipFHDColl', onPropertyChange: false,
401
+ value: {value: this.getCurrFlipState()}});
402
+ parent.activeObj = extend({}, parent.objColl[parent.objColl.length - 1], {}, true) as SelectionPoint;
403
+ parent.objColl.pop();
404
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
405
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: 'duplicate'}});
406
+ this.cropImg(true);
407
+ parent.notify('transform', { prop: 'setReverseRotate', onPropertyChange: false, value: {bool: true}});
408
+ this.lowerContext.setTransform(1, 0, 0, 1, 0, 0);
409
+ parent.notify('draw', { prop: 'setDestPoints', onPropertyChange: false});
410
+ parent.notify('draw', { prop: 'currTransState', onPropertyChange: false,
411
+ value: {type: 'initial', isPreventDestination: null, context: null, isPreventCircleCrop: null} });
412
+ parent.notify('draw', { prop: 'drawImage', onPropertyChange: false});
413
+ this.lowerContext.filter = temp;
414
+ parent.notify('draw', { prop: 'setRotateZoom', onPropertyChange: false, value: {isRotateZoom: false }});
415
+ parent.notify('draw', { prop: 'currTransState', onPropertyChange: false,
416
+ value: {type: 'reverse', isPreventDestination: null, context: null, isPreventCircleCrop: null} });
417
+ parent.transform.currFlipState = tempCurrFlipState;
418
+ parent.notify('transform', { prop: 'setFlipColl', onPropertyChange: false, value: {flipColl: tempFlipColl }});
419
+ this.lowerContext.filter = 'none';
420
+ this.updateFlipState();
421
+ parent.notify('shape', { prop: 'redrawObj', onPropertyChange: false, value: {degree: this.getCurrFlipState()}});
422
+ parent.notify('freehand-draw', { prop: 'flipFHDColl', onPropertyChange: false,
423
+ value: {value: this.getCurrFlipState()}});
424
+ parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
425
+ value: {ctx: this.lowerContext, shape: 'zoom', pen: 'zoom', isPreventApply: null }});
426
+ this.lowerContext.filter = temp;
427
+ if ((parent.currSelectionPoint && parent.currSelectionPoint.shape === 'crop-circle') || parent.isCircleCrop) {
428
+ this.cropCircle(this.lowerContext);
429
+ }
430
+ parent.notify('shape', { prop: 'refreshActiveObj', onPropertyChange: false});
431
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.lowerContext}});
432
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.upperContext}});
433
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
434
+ parent.notify('transform', { prop: 'setReverseFlip', onPropertyChange: false, value: {isReverseFlip: false }});
435
+ parent.notify('draw', { prop: 'resetPanPoints', onPropertyChange: false});
436
+ this.tempFlipPanPoint = {x: 0, y: 0};
437
+ }
438
+
439
+ private cropObjColl(): void {
440
+ const parent: ImageEditor = this.parent;
441
+ let point: ActivePoint; let shape: string; let obj: SelectionPoint;
442
+ if (parent.objColl.length > 0) {
443
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
444
+ obj = parent.objColl[i as number];
445
+ point = obj.activePoint;
446
+ const { startX, startY, width, height} = parent.activeObj.activePoint;
447
+ shape = obj.shape;
448
+ obj.imageRatio = {startX: ((point.startX - startX) / width),
449
+ startY: ((point.startY - startY) / height),
450
+ endX: ((point.endX - startX) / width), endY: ((point.endY - startY) / height),
451
+ width: width / point.width, height: height / point.height };
452
+ let degree: number; let size: number;
453
+ switch (shape) {
454
+ case 'text':
455
+ degree = (obj.shapeDegree === 0) ? parent.transform.degree : parent.transform.degree - obj.shapeDegree;
456
+ size = (degree === 0 || Math.abs(degree) === 180) ? point.width : point.height;
457
+ obj.textSettings.fontRatio = size / obj.textSettings.fontSize;
458
+ break;
459
+ case 'line':
460
+ case 'arrow':
461
+ this.cropPointCollection(i);
462
+ if (shape === 'arrow') {
463
+ parent.notify('shape', { prop: 'updateArrowRatio', onPropertyChange: false, value: {obj: obj }});
464
+ }
465
+ break;
466
+ case 'path':
467
+ this.cropPointCollection(i);
468
+ break;
469
+ }
470
+ }
471
+ }
472
+ }
473
+
474
+ private cropPointCollection(i: number): void {
475
+ const parent: ImageEditor = this.parent;
476
+ const shape: string = parent.objColl[i as number].shape;
477
+ let x: number; let y: number; let width: number; let height: number;
478
+ const point: ActivePoint = parent.activeObj.activePoint;
479
+ const { destLeft, destTop, destWidth, destHeight } = parent.img;
480
+ if (shape === 'path') {
481
+ x = point.startX; y = point.startY; width = point.width; height = point.height;
482
+ } else {
483
+ x = destLeft; y = destTop; width = destWidth; height = destHeight;
484
+ }
485
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
486
+ const pointColl: any = parent.objColl[i as number].pointColl;
487
+ for (let n: number = 0, len: number = pointColl.length; n < len; n++) {
488
+ pointColl[n as number].ratioX = (pointColl[n as number].x - x) / width;
489
+ pointColl[n as number].ratioY = (pointColl[n as number].y - y) / height;
490
+ }
491
+ }
492
+
493
+ private cropFreehandDrawColl(): void {
494
+ const parent: ImageEditor = this.parent;
495
+ const { startX, startY, width, height} = parent.activeObj.activePoint;
496
+ for (let n: number = 0; n < parent.freehandCounter; n++) {
497
+ parent.points = extend([], parent.pointColl[n as number].points, []) as Point[];
498
+ parent.notify('freehand-draw', { prop: 'setPointCounter', onPropertyChange: false, value: {value: 0 }});
499
+ const len: number = parent.points.length;
500
+ for (let l: number = 0; l < len; l++) {
501
+ parent.points[l as number].ratioX = (parent.points[l as number].x - startX) / width;
502
+ parent.points[l as number].ratioY = (parent.points[l as number].y - startY) / height;
503
+ }
504
+ }
505
+ parent.notify('freehand-draw', { prop: 'updateCropPtsForSel', onPropertyChange: false});
506
+ }
507
+
508
+ private resetAnnotations(): void {
509
+ const parent: ImageEditor = this.parent; parent.objColl = []; parent.pointColl = []; parent.freehandCounter = 0;
510
+ parent.notify('freehand-draw', { prop: 'resetStraightenPoint' });
511
+ }
512
+
513
+ private setCurrSelPoints(isSetDimension?: boolean): void {
514
+ const parent: ImageEditor = this.parent;
515
+ parent.allowDownScale = false;
516
+ const destPoint: ActivePoint = this.cropDestPoints;
517
+ const filter: string = this.lowerContext.filter;
518
+ const isCropTab: boolean = parent.isCropTab;
519
+ parent.img = { srcLeft: 0, srcTop: 0, srcWidth: parent.baseImgCanvas.width, srcHeight: parent.baseImgCanvas.height,
520
+ destLeft: destPoint.startX, destTop: destPoint.startY, destWidth: destPoint.width, destHeight: destPoint.height };
521
+ const img: ImageDimension = parent.img;
522
+ const currSelPoint: SelectionPoint = parent.currSelectionPoint;
523
+ this.lowerContext.clearRect(0, 0 , parent.lowerCanvas.width, parent.lowerCanvas.height);
524
+ if (isSetDimension) {
525
+ parent.notify('draw', { prop: 'setDestPoints', onPropertyChange: false});
526
+ }
527
+ parent.notify('draw', { prop: 'currTransState', onPropertyChange: false,
528
+ value: {type: 'initial', isPreventDestination: null, context: null, isPreventCircleCrop: null} });
529
+ if (this.croppedDegree === 0 && parent.transform.degree === 0 && currSelPoint
530
+ && currSelPoint.shape !== 'crop-circle' && currSelPoint.shape !== 'crop-square') {
531
+ img.destLeft = destPoint.startX; img.destTop = destPoint.startY;
532
+ img.destWidth = destPoint.width; img.destHeight = destPoint.height;
533
+ }
534
+ if (parent.transform.degree === 0) {
535
+ img.destLeft += parent.panPoint.totalPannedInternalPoint.x;
536
+ img.destTop += parent.panPoint.totalPannedInternalPoint.y;
537
+ }
538
+ parent.notify('draw', { prop: 'drawImage', onPropertyChange: false});
539
+ this.lowerContext.filter = filter;
540
+ parent.notify('draw', { prop: 'currTransState', onPropertyChange: false,
541
+ value: {type: 'reverse', isPreventDestination: null, context: null, isPreventCircleCrop: true} });
542
+ let cropObjColl: SelectionPoint[] = extend([], parent.objColl, null, true) as SelectionPoint[];
543
+ let cropPointColl: Point[] = extend([], parent.pointColl, null, true) as Point[];
544
+ const straightenObj: Object = {straightenPoint: null };
545
+ parent.notify('freehand-draw', { prop: 'getStraightenPoint', onPropertyChange: false,
546
+ value: {obj: straightenObj }});
547
+ this.resetAnnotations();
548
+ if (isNullOrUndefined(parent.activeObj.shape) && parent.cropObj.activeObj.shape) {
549
+ parent.activeObj = extend({}, parent.cropObj.activeObj, null, true) as SelectionPoint;
550
+ }
551
+ this.panToSelRangle();
552
+ parent.isCropTab = isCropTab;
553
+ parent.objColl = cropObjColl; parent.pointColl = cropPointColl; parent.freehandCounter = parent.pointColl.length;
554
+ if (straightenObj['straightenPoint']['x'] && straightenObj['straightenPoint']['y']) {
555
+ parent.notify('freehand-draw', { prop: 'setStraightenPoint', onPropertyChange: false,
556
+ value: {x: straightenObj['straightenPoint']['x'], y: straightenObj['straightenPoint']['y'],
557
+ ratioX: straightenObj['straightenPoint']['ratioX'], ratioY: straightenObj['straightenPoint']['ratioY']}});
558
+ }
559
+ if (parent.cropObj.activeObj.shape) {
560
+ const destPoints: ActivePoint = {startX: img.destLeft, startY: img.destTop, width: img.destWidth, height: img.destHeight};
561
+ if (currSelPoint && currSelPoint.activePoint) {
562
+ const { startX, startY, width, height} = currSelPoint.activePoint;
563
+ img.destLeft = startX; img.destTop = startY;
564
+ img.destWidth = width; img.destHeight = height;
565
+ }
566
+ parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
567
+ value: {ctx: this.lowerContext, shape: 'zoom', pen: 'zoom', isPreventApply: null }});
568
+ img.destLeft = destPoints.startX; img.destTop = destPoints.startY;
569
+ img.destWidth = destPoints.width; img.destHeight = destPoints.height;
570
+ parent.notify('freehand-draw', { prop: 'updateFHDColl', onPropertyChange: false});
571
+ cropObjColl = extend([], parent.objColl, null, true) as SelectionPoint[];
572
+ cropPointColl = extend([], parent.pointColl, null, true) as Point[];
573
+ parent.notify('freehand-draw', { prop: 'getStraightenPoint', onPropertyChange: false, value: {obj: straightenObj }});
574
+ this.resetAnnotations();
575
+ const object: Object = {selPointColl: null };
576
+ parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false, value: {obj: object }});
577
+ const cropSelPointColl: Point[] = object['selPointColl'];
578
+ parent.notify('freehand-draw', { prop: 'setSelPointColl', onPropertyChange: false, value: {obj: {selPointColl: [] } }});
579
+ parent.cropObj.filter = this.lowerContext.filter;
580
+ const actObj: SelectionPoint = extend({}, parent.currSelectionPoint, null, true) as SelectionPoint;
581
+ parent.notify('draw', { prop: 'setCurrentObj', onPropertyChange: false, value: {obj: null}});
582
+ parent.activeObj = extend({}, actObj, null, true) as SelectionPoint;
583
+ const activeObj: SelectionPoint = extend({}, parent.activeObj, null, true) as SelectionPoint;
584
+ parent.notify('shape', { prop: 'refreshActiveObj', onPropertyChange: false});
585
+ parent.currSelectionPoint = null; parent.isCircleCrop = false;
586
+ if (parent.transform.degree !== 0) {
587
+ if (isNullOrUndefined(parent.activeObj.shape) && parent.cropObj.activeObj.shape) {
588
+ parent.activeObj = extend({}, parent.cropObj.activeObj, null, true) as SelectionPoint;
589
+ }
590
+ parent.notify('transform', { prop: 'drawPannedImage', value: { xDiff: 0, yDiff: 0 } });
591
+ parent.panPoint.currentPannedPoint = { x: 0, y: 0 };
592
+ }
593
+ parent.objColl = cropObjColl; parent.pointColl = cropPointColl; parent.freehandCounter = parent.pointColl.length;
594
+ if (straightenObj['straightenPoint']['x'] && straightenObj['straightenPoint']['y']) {
595
+ parent.notify('freehand-draw', { prop: 'setStraightenPoint', onPropertyChange: false,
596
+ value: {x: straightenObj['straightenPoint']['x'], y: straightenObj['straightenPoint']['y'],
597
+ ratioX: straightenObj['straightenPoint']['ratioX'], ratioY: straightenObj['straightenPoint']['ratioY']}});
598
+ }
599
+ parent.notify('freehand-draw', { prop: 'setSelPointColl', onPropertyChange: false,
600
+ value: {obj: {selPointColl: cropSelPointColl } }});
601
+ parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
602
+ value: {ctx: this.lowerContext, shape: 'iterate', pen: 'iterate', isPreventApply: null }});
603
+ this.adjustStraightenForShapes('reverse', false);
604
+ parent.notify('freehand-draw', { prop: 'updateFHDColl', onPropertyChange: false, value: {isPreventApply: true }});
605
+ parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
606
+ value: {ctx: this.lowerContext, shape: 'zoom', pen: 'zoom', isPreventApply: null }});
607
+ if (parent.transform.degree === 0) {
608
+ parent.notify('transform', { prop: 'drawPannImage', onPropertyChange: false,
609
+ value: {point: {x: 0, y: 0}}});
610
+ } else {
611
+ if (isNullOrUndefined(parent.activeObj.shape) && parent.cropObj.activeObj.shape) {
612
+ parent.activeObj = extend({}, parent.cropObj.activeObj, null, true) as SelectionPoint;
613
+ }
614
+ parent.notify('transform', { prop: 'drawPannedImage', value: { xDiff: 0, yDiff: 0 } });
615
+ parent.panPoint.currentPannedPoint = { x: 0, y: 0 };
616
+ }
617
+ parent.activeObj = activeObj;
618
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: 'duplicate'} });
619
+ parent.notify('transform', { prop: 'setTempPanMove', onPropertyChange: false,
620
+ value: {point: null }});
621
+ if (!this.isInitCrop && parent.transform.degree === 0 && parent.cropObj.currFlipState !== '' &&
622
+ parent.cropObj.cropZoom !== 0) {
623
+ this.isInitCrop = true;
624
+ const obj: Object = {activeObj: null };
625
+ parent.notify('draw', { prop: 'getStraightenActObj', onPropertyChange: false, value: {obj: obj }});
626
+ parent.notify('draw', {prop: 'performCancel', value: {isContextualToolbar: null}});
627
+ parent.notify('draw', { prop: 'setStraightenActObj', onPropertyChange: false, value: {activeObj: obj['activeObj'] }});
628
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'croptransform',
629
+ isApplyBtn: false, isCropping: null, isZooming: null, cType: null}});
630
+ } else {this.isInitCrop = false; }
631
+ } else {
632
+ this.adjustStraightenForShapes('reverse', true);
633
+ parent.notify('freehand-draw', { prop: 'updateFHDColl', onPropertyChange: false, value: {isPreventApply: true }});
634
+ const temp: string = this.lowerContext.filter;
635
+ this.lowerContext.filter = 'none';
636
+ parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
637
+ value: {ctx: this.lowerContext, shape: 'iterate', pen: 'iterate', isPreventApply: null }});
638
+ this.lowerContext.filter = temp;
639
+ parent.currSelectionPoint = null;
640
+ }
641
+ if (document.querySelector('.e-ie-straighten-value-span')) {
642
+ document.querySelector('.e-ie-straighten-value-span').innerHTML = parent.transform.straighten.toString() + '&#176';
643
+ }
644
+ }
645
+
646
+ private panToSelRangle(isReverse?: boolean): void {
647
+ const parent: ImageEditor = this.parent;
648
+ const pannedPoint: Point = parent.cropObj.totalPannedClientPoint;
649
+ const panX: number = parent.transform.degree !== 0 ? isReverse ? -pannedPoint.x : pannedPoint.x : 0;
650
+ const panY: number = parent.transform.degree !== 0 ? isReverse ? -pannedPoint.y : pannedPoint.y : 0;
651
+ if (parent.transform.degree !== 0) {
652
+ parent.panPoint.currentPannedPoint = { x: panX, y: panY };
653
+ parent.notify('transform', { prop: 'drawPannedImage', value: { xDiff: panX, yDiff: panY } });
654
+ parent.panPoint.currentPannedPoint = { x: 0, y: 0 };
655
+ }
656
+ }
657
+
658
+ private cropCircle(context: CanvasRenderingContext2D, isSave?: boolean, isFlip?: boolean): void {
659
+ const parent: ImageEditor = this.parent; const { destLeft, destTop, destWidth, destHeight } = parent.img;
660
+ if (isFlip && parent.transform.currFlipState !== '') {
661
+ parent.notify('draw', { prop: 'setTransform', onPropertyChange: false,
662
+ value: {context: context, value: parent.transform.currFlipState, isReverse: null}});
663
+ }
664
+ const temp: string = context.filter;
665
+ context.filter = 'none';
666
+ context.globalCompositeOperation = 'destination-in';
667
+ context.beginPath();
668
+ const centerX: number = isNullOrUndefined(isSave) ? destLeft + (destWidth / 2) : context.canvas.width / 2;
669
+ const centerY: number = isNullOrUndefined(isSave) ? destTop + (destHeight / 2) : context.canvas.height / 2;
670
+ const radius: number = isSave ? context.canvas.width / 2 : destWidth / 2;
671
+ context.arc(centerX, centerY, radius, 0, Math.PI * 2);
672
+ context.closePath(); context.fill(); context.restore();
673
+ context.globalCompositeOperation = 'source-over';
674
+ parent.currObjType.isActiveObj = parent.isCircleCrop = true;
675
+ context.filter = temp;
676
+ if (isFlip && parent.transform.currFlipState !== '') {
677
+ parent.notify('draw', { prop: 'setTransform', onPropertyChange: false,
678
+ value: {context: context, value: parent.transform.currFlipState, isReverse: null}});
679
+ }
680
+ }
681
+
682
+ private getCurrCropState(): string {
683
+ const parent: ImageEditor = this.parent; let flipState: string = '';
684
+ const obj: Object = {flipColl: null };
685
+ parent.notify('transform', { prop: 'getFlipColl', onPropertyChange: false, value: {obj: obj }});
686
+ flipState = this.getCurrFlipState();
687
+ if (parent.transform.degree === -90 || parent.transform.degree === -270) {
688
+ if (flipState === 'horizontal') {flipState = 'vertical'; }
689
+ else if (flipState === 'vertical') {flipState = 'horizontal'; }
690
+ }
691
+ if (flipState === '') {flipState = obj['flipColl'].length > 1 ? this.getCurrFlipState() : parent.transform.currFlipState; }
692
+ return flipState;
693
+ }
694
+
695
+ private updateRotatePan(): void {
696
+ const parent: ImageEditor = this.parent;
697
+ if (isNullOrUndefined(parent.panPoint.currentPannedPoint)) {
698
+ return;
699
+ }
700
+ let panRegion: string = ''; const degree: number = parent.transform.degree;
701
+ const { x, y} = parent.panPoint.currentPannedPoint;
702
+ if (parent.rotateFlipColl.length > 0 && typeof(parent.rotateFlipColl[0]) === 'number'
703
+ && degree < 0) {
704
+ panRegion = this.getCurrCropState();
705
+ } else {
706
+ panRegion = this.getCurrFlipState();
707
+ }
708
+ if (degree % 90 === 0 && degree % 180 !== 0) {
709
+ if (degree === 90 || (degree === -90 && (panRegion === 'horizontal' || panRegion === 'vertical'))
710
+ || (degree === -270 && (panRegion === '' || panRegion === 'verticalHorizontal'
711
+ || panRegion === 'horizontalVertical'))) {
712
+ if (panRegion === 'horizontal' || panRegion === '') {
713
+ parent.img.destLeft += y;
714
+ } else {
715
+ parent.img.destLeft -= y;
716
+ }
717
+ if (panRegion === '' || panRegion === 'vertical') {
718
+ parent.img.destTop -= x;
719
+ } else {
720
+ parent.img.destTop += x;
721
+ }
722
+ }
723
+ else if (degree === 270 || (degree === -270 && (panRegion === 'horizontal' || panRegion === 'vertical'))
724
+ || (degree === -90 && (panRegion === '' || panRegion === 'verticalHorizontal'
725
+ || panRegion === 'horizontalVertical'))) {
726
+ if (panRegion === '' || panRegion === 'horizontal') {
727
+ parent.img.destLeft -= y;
728
+ } else {
729
+ parent.img.destLeft += y;
730
+ }
731
+ if (panRegion === '' || panRegion === 'vertical') {
732
+ parent.img.destTop += x;
733
+ } else {
734
+ parent.img.destTop -= x;
735
+ }
736
+ }
737
+ } else {
738
+ if (degree === 180 || degree === -180) {
739
+ if (panRegion === '' || panRegion === 'vertical') {
740
+ parent.img.destLeft -= x;
741
+ } else {
742
+ parent.img.destLeft += x;
743
+ }
744
+ if (panRegion === '' || panRegion === 'horizontal') {
745
+ parent.img.destTop -= y;
746
+ } else {
747
+ parent.img.destTop += y;
748
+ }
749
+ }
750
+ }
751
+ }
752
+
753
+ private crop(obj: Object): void {
754
+ const parent: ImageEditor = this.parent; const { startX, startY, endX, endY} = parent.activeObj.activePoint;
755
+ if (!parent.disabled && parent.isImageLoaded) {
756
+ const object: Object = {isCropToolbar: parent.isCropToolbar };
757
+ if (parent.currObjType.isUndoAction && !object['isCropToolbar']) {
758
+ parent.notify('undo-redo', {prop: 'refreshUrc', value: {bool: null }});
759
+ }
760
+ const transitionArgs: CropEventArgs = {cancel: false, startPoint: { x: startX, y: startY },
761
+ endPoint: {x: endX, y: endY }, preventScaling: false };
762
+ if (!object['isCropToolbar']) {
763
+ parent.trigger('cropping', transitionArgs);
764
+ parent.editCompleteArgs = transitionArgs;
765
+ }
766
+ this.cropEvent(transitionArgs, obj, object);
767
+ }
768
+ }
769
+
770
+ private cropEvent(transitionArgs: CropEventArgs, obj: Object, object: Object): void {
771
+ const parent: ImageEditor = this.parent;
772
+ let splitWords: string[];
773
+ if (!transitionArgs.cancel) {
774
+ splitWords = parent.activeObj.shape ? parent.activeObj.shape.split('-') : [];
775
+ if (!parent.disabled && parent.activeObj.horTopLine && (parent.currObjType.isCustomCrop || (splitWords.length > 0 &&
776
+ splitWords[0] === 'crop'))) {
777
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
778
+ (obj as any).isCrop = true;
779
+ const prevCropObj: CurrentObject = extend({}, parent.cropObj, {}, true) as CurrentObject;
780
+ const prevObj: CurrentObject = extend({}, this.prevCropCurrObj, {}, true) as CurrentObject;
781
+ if (transitionArgs.preventScaling) {this.isPreventScaling = true; }
782
+ else {this.isPreventScaling = false; }
783
+ this.cropImg();
784
+ if (this.isPreventScaling) {
785
+ parent.aspectWidth = parent.img.destWidth;
786
+ parent.aspectHeight = parent.img.destHeight;
787
+ }
788
+ parent.notify('freehand-draw', { prop: 'resetStraightenPoint' });
789
+ parent.isCropTab = false;
790
+ parent.transform.zoomFactor = 0;
791
+ parent.setProperties({zoomSettings: { zoomFactor: 1}}, true);
792
+ parent.notify('transform', { prop: 'setPreviousZoomValue', onPropertyChange: false,
793
+ value: { previousZoomValue: parent.zoomSettings.zoomFactor } });
794
+ if (!Browser.isDevice) {this.updateUndoRedoColl(prevObj, prevCropObj, object); }
795
+ parent.notify('transform', { prop: 'setCropDimension', onPropertyChange: false,
796
+ value: {width: parent.cropObj.destPoints.width, height: parent.cropObj.destPoints.height }});
797
+ const aspectIcon: HTMLInputElement = (parent.element.querySelector('#' + parent.element.id + '_aspectratio') as HTMLInputElement);
798
+ const nonAspectIcon: HTMLInputElement = (parent.element.querySelector('#' + parent.element.id + '_nonaspectratio') as HTMLInputElement);
799
+ parent.notify('draw', { prop: 'render-image', value: { isMouseWheel: false } });
800
+ if (!object['isCropToolbar'] && (isNullOrUndefined(aspectIcon) && isNullOrUndefined(nonAspectIcon))) {
801
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'main',
802
+ isApplyBtn: false, isCropping: false, isZooming: null, cType: null}});
803
+ }
804
+ this.resizeWrapper();
805
+ if (Browser.isDevice) {this.updateUndoRedoColl(prevObj, prevCropObj, object); }
806
+ }
807
+ }
808
+ }
809
+
810
+ private updateUndoRedoColl(prevObj: CurrentObject, prevCropObj: CurrentObject, object: Object): void {
811
+ const parent: ImageEditor = this.parent;
812
+ const currSelPtObj: Object = {prevCurrSelectionPoint: parent.prevCurrSelectionPoint };
813
+ prevObj.currSelectionPoint = extend({}, currSelPtObj['prevCurrSelectionPoint'], {}, true) as SelectionPoint;
814
+ parent.notify('undo-redo', { prop: 'updateUndoRedoColl', onPropertyChange: false,
815
+ value: {operation: 'crop', previousObj: prevObj, previousObjColl: prevObj.objColl,
816
+ previousPointColl: prevObj.pointColl, previousSelPointColl: prevObj.selPointColl,
817
+ previousCropObj: prevCropObj, previousText: null,
818
+ currentText: null, previousFilter: null, isCircleCrop: parent.isCircleCrop}});
819
+ if (!object['isCropToolbar']) {
820
+ parent.notify('undo-redo', {prop: 'updateCurrUrc', value: {type: 'ok' }});
821
+ }
822
+ }
823
+
824
+ private resizeWrapper(): void {
825
+ const parent: ImageEditor = this.parent;
826
+ if (Browser.isDevice) {
827
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
828
+ const elem: HTMLElement = (parent as any).element;
829
+ const ctxToolbar: HTMLElement = elem.querySelector('#' + elem.id + '_contextualToolbarArea') as HTMLElement;
830
+ if (ctxToolbar && ctxToolbar.style.position === '' && !this.isTransformCrop) {
831
+ ctxToolbar.style.position = 'absolute';
832
+ parent.isStraightening = false;
833
+ parent.update();
834
+ parent.notify('filter', { prop: 'setAdjustmentValue', value: { adjustmentValue: parent.canvasFilter } });
835
+ }
836
+ }
837
+ }
838
+
839
+ private calcRatio(obj?: Object, dimension?: Dimension): Dimension {
840
+ const parent: ImageEditor = this.parent;
841
+ const { degree } = parent.transform;
842
+ const { destWidth, destHeight } = parent.img;
843
+ const { width, height } = dimension || parent.baseImgCanvas;
844
+ const widthRatio: number = (degree === 0 || degree % 180 === 0) ? width / destWidth : height / destWidth;
845
+ const heightRatio: number = (degree === 0 || degree % 180 === 0) ? height / destHeight : width / destHeight;
846
+ if (obj) {
847
+ obj['width'] = widthRatio;
848
+ obj['height'] = heightRatio;
849
+ }
850
+ return { width: widthRatio, height: heightRatio };
851
+ }
852
+
853
+ private getCurrFlipState(panObj?: Object): string {
854
+ const parent: ImageEditor = this.parent;
855
+ const obj: Object = {panRegion: ''};
856
+ const object: Object = {collection: parent.rotateFlipColl};
857
+ parent.notify('shape', { prop: 'alignRotateFlipColl', onPropertyChange: false,
858
+ value: {collection: parent.rotateFlipColl, isRotateFlipCollection: true, obj: object }});
859
+ parent.rotateFlipColl = object['collection'];
860
+ for (let i: number = 0, len: number = parent.rotateFlipColl.length; i < len; i++) {
861
+ parent.notify('transform', { prop: 'setCurrPanRegion', onPropertyChange: false,
862
+ value: {region: obj['panRegion'], type: parent.rotateFlipColl[i as number], obj: obj }});
863
+ }
864
+ if (panObj) { panObj['panRegion'] = obj['panRegion']; }
865
+ return obj['panRegion'];
866
+ }
867
+ }