@syncfusion/ej2-image-editor 30.2.5 → 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 (51) 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 +7 -39
  4. package/dist/es6/ej2-image-editor.es2015.js.map +1 -1
  5. package/dist/es6/ej2-image-editor.es5.js +7 -39
  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/export.js +1 -1
  49. package/src/image-editor/action/freehand-draw.d.ts +0 -1
  50. package/src/image-editor/action/freehand-draw.js +3 -25
  51. package/src/image-editor/action/undo-redo.js +3 -13
@@ -0,0 +1,3917 @@
1
+ /* eslint-disable no-constant-condition */
2
+ import { EventHandler, extend, isNullOrUndefined } from '@syncfusion/ej2-base';
3
+ import { CurrentObject, ImageEditor, Point, SelectionPoint, CropSelectionSettings, ShapeChangeEventArgs, ShapeSettings, ShapeType,
4
+ StrokeSettings, TextSettings, RedactType, RedactSettings, ArrowheadType, ActivePoint, TransformationCollection} from '../index';
5
+
6
+ export class Shape {
7
+ private parent: ImageEditor;
8
+ private lowerContext: CanvasRenderingContext2D;
9
+ private upperContext: CanvasRenderingContext2D;
10
+ private textSettings: TextSettings =
11
+ {text: 'Enter Text', fontFamily: '', fontSize: null, fontRatio: null, bold: false, italic: false, underline: false, strikethrough: false};
12
+ private strokeSettings: StrokeSettings = {strokeColor: '#fff', fillColor: '', strokeWidth: null, radius: null, outlineColor: '', outlineWidth: null};
13
+ private keyHistory: string = ''; // text history
14
+ private prevObj: CurrentObject;
15
+ private shapeImg: HTMLImageElement;
16
+ private preventFrameAnnotation: boolean = false;
17
+ private redactType: string = 'blur';
18
+
19
+ constructor(parent: ImageEditor) {
20
+ this.parent = parent;
21
+ this.addEventListener();
22
+ }
23
+
24
+ public destroy(): void {
25
+ if (this.parent.isDestroyed) { return; }
26
+ this.removeEventListener();
27
+ }
28
+
29
+ private addEventListener(): void {
30
+ this.parent.on('shape', this.shape, this);
31
+ this.parent.on('destroyed', this.destroy, this);
32
+ }
33
+
34
+ private removeEventListener(): void {
35
+ this.parent.off('shape', this.shape);
36
+ this.parent.off('destroyed', this.destroy);
37
+ }
38
+
39
+ private shape(args?: { onPropertyChange: boolean, prop: string, value?: object }): void {
40
+ const parent: ImageEditor = this.parent;
41
+ this.initShapePvtProps(); let uploader: HTMLElement;
42
+ switch (args.prop) {
43
+ case 'drawEllipse':
44
+ this.drawEllipse(args.value['x'], args.value['y'], args.value['radiusX'], args.value['radiusY'],
45
+ args.value['strokeWidth'], args.value['strokeColor'], args.value['fillColor'],
46
+ args.value['degree'], args.value['isSelected']);
47
+ break;
48
+ case 'drawLine':
49
+ this.drawLine(args.value['startX'], args.value['startY'], args.value['endX'], args.value['endY'],
50
+ args.value['strokeWidth'], args.value['strokeColor'], args.value['isSelected']);
51
+ break;
52
+ case 'drawArrow':
53
+ this.drawArrow(args.value['startX'], args.value['startY'], args.value['endX'], args.value['endY'],
54
+ args.value['strokeWidth'], args.value['strokeColor'], args.value['arrowStart'],
55
+ args.value['arrowEnd'], args.value['isSelected']);
56
+ break;
57
+ case 'drawPath':
58
+ this.drawPath(args.value['pointColl'], args.value['strokeWidth'], args.value['strokeColor'], args.value['isSelected']);
59
+ break;
60
+ case 'drawRectangle':
61
+ this.drawRectangle(args.value['x'], args.value['y'], args.value['width'], args.value['height'],
62
+ args.value['strokeWidth'], args.value['strokeColor'], args.value['fillColor'],
63
+ args.value['degree'], args.value['isSelected'], args.value['radius']);
64
+ break;
65
+ case 'drawText':
66
+ this.drawText(args.value['x'], args.value['y'], args.value['text'], args.value['fontFamily'],
67
+ args.value['fontSize'], args.value['bold'], args.value['italic'], args.value['color'],
68
+ args.value['isSelected'], args.value['degree'], args.value['fillColor'], args.value['outlineColor'],
69
+ args.value['outlineWidth'], args.value['transformCollection'], args.value['underline'], args.value['strikethrough']);
70
+ break;
71
+ case 'redrawActObj':
72
+ this.redrawActObj(args.value['x'], args.value['y'], args.value['isMouseDown']);
73
+ break;
74
+ case 'apply':
75
+ this.apply(args.value['shape'], args.value['obj'], args.value['canvas']);
76
+ break;
77
+ case 'updateShapeChangeEventArgs':
78
+ this.updateShapeChangeEventArgs(args.value['shapeSettings'], args.value['allowShapeOverflow']);
79
+ break;
80
+ case 'updSelChangeEventArgs':
81
+ this.updSelChangeEventArgs(args.value['selectionSettings']);
82
+ break;
83
+ case 'iterateObjColl':
84
+ this.iterateObjColl();
85
+ break;
86
+ case 'updImgRatioForActObj':
87
+ this.updImgRatioForActObj();
88
+ break;
89
+ case 'redrawObj':
90
+ this.redrawObj(args.value['degree']);
91
+ break;
92
+ case 'redraw-text':
93
+ this.redrawText();
94
+ break;
95
+ case 'draw-shape':
96
+ this.drawShape(args.value['obj'] as string, args.value['strokeWidth'], args.value['strokeColor'],
97
+ args.value['fillColor'], args.value['start'], args.value['width'], args.value['height']);
98
+ break;
99
+ case 'renderTextArea':
100
+ this.renderTextArea(args.value['x'], args.value['y'], args.value['actObj']);
101
+ break;
102
+ case 'setTextBoxWidth':
103
+ this.setTextBoxWidth(args.value['e']);
104
+ break;
105
+ case 'findTextTarget':
106
+ this.findTextTarget(args.value['e']);
107
+ break;
108
+ case 'updateFontStyles':
109
+ this.updateFontStyles(args.value['isTextBox']);
110
+ break;
111
+ case 'applyFontStyle':
112
+ this.applyFontStyle(args.value['item']);
113
+ break;
114
+ case 'updateFontRatio':
115
+ this.updateFontRatio(args.value['obj'], args.value['isTextArea']);
116
+ break;
117
+ case 'updateFontSize':
118
+ this.updateFontSize(args.value['obj']);
119
+ break;
120
+ case 'pushActItemIntoObj':
121
+ this.pushActItemIntoObj();
122
+ break;
123
+ case 'clearActObj':
124
+ this.clearActObj();
125
+ break;
126
+ case 'refreshActiveObj':
127
+ this.refreshActiveObj();
128
+ break;
129
+ case 'applyActObj':
130
+ this.applyActObj(args.value['isMouseDown']);
131
+ break;
132
+ case 'wireEvent':
133
+ EventHandler.add(parent.upperCanvas, 'dblclick', this.findTextTarget, this);
134
+ EventHandler.add(parent.textArea, 'mousedown', this.findTextTarget, this);
135
+ uploader = document.getElementById(parent.element.id + '_fileUpload');
136
+ if (uploader) {
137
+ EventHandler.add(uploader, 'change', this.fileChanged, this);
138
+ }
139
+ break;
140
+ case 'unWireEvent':
141
+ EventHandler.remove(parent.upperCanvas, 'dblclick', this.findTextTarget);
142
+ EventHandler.remove(parent.textArea, 'mousedown', this.findTextTarget);
143
+ uploader = document.getElementById(parent.element.id + '_fileUpload');
144
+ if (uploader) {
145
+ EventHandler.remove(uploader, 'change', this.fileChanged);
146
+ }
147
+ break;
148
+ case 'getShapeSetting':
149
+ this.getShapeSetting(args.value['id'], args.value['obj']);
150
+ break;
151
+ case 'getShapeSettings':
152
+ this.getShapeSettings(args.value['obj']);
153
+ break;
154
+ case 'getRedactSettings':
155
+ this.getRedactSettings(args.value['obj']);
156
+ break;
157
+ case 'isPointsInRange':
158
+ this.isPointsInRange(args.value['x'], args.value['y'], args.value['obj']);
159
+ break;
160
+ case 'alignRotateFlipColl':
161
+ this.alignRotateFlipColl(args.value['collection'], args.value['isRotateFlipCollection'],
162
+ args.value['obj']);
163
+ break;
164
+ case 'selectShape':
165
+ this.selectShape(args.value['id'], args.value['obj']);
166
+ break;
167
+ case 'deleteShape':
168
+ this.deleteShape(args.value['id']);
169
+ break;
170
+ case 'getMaxText':
171
+ this.getMaxText(args.value['isTextBox'], args.value['text'], args.value['obj']);
172
+ break;
173
+ case 'setPointCollForLineArrow':
174
+ args.value['obj'].pointColl = this.getLinePoints(args.value['obj'].activePoint.startX,
175
+ args.value['obj'].activePoint.startY, args.value['obj'].activePoint.endX,
176
+ args.value['obj'].activePoint.endY);
177
+ break;
178
+ case 'setPointCollForShapeRotation':
179
+ this.setPointCollForShapeRotation(args.value['obj']);
180
+ break;
181
+ case 'setTextSettings':
182
+ if (args.value['textSettings']) {
183
+ this.textSettings = args.value['textSettings'];
184
+ } else if (args.value['fontFamily']) {
185
+ this.textSettings.fontFamily = args.value['fontFamily'];
186
+ } else if (args.value['fontSize']) {
187
+ this.textSettings.fontSize = args.value['fontSize'];
188
+ } else if (args.value['radius']) {
189
+ this.strokeSettings.radius = args.value['radius'];
190
+ }
191
+ break;
192
+ case 'setStrokeSettings':
193
+ if (args.value['strokeSettings']) {
194
+ this.strokeSettings = args.value['strokeSettings'];
195
+ } else if (args.value['strokeColor']) {
196
+ this.strokeSettings.strokeColor = args.value['strokeColor'];
197
+ } else if (args.value['fillColor']) {
198
+ this.strokeSettings.fillColor = args.value['fillColor'];
199
+ } else if (args.value['strokeWidth']) {
200
+ this.strokeSettings.strokeWidth = args.value['strokeWidth'];
201
+ } else if (args.value['outlineColor']) {
202
+ this.strokeSettings.outlineColor = args.value['outlineColor'];
203
+ } else if (args.value['radius']) {
204
+ this.strokeSettings.radius = args.value['radius'];
205
+ } else if (args.value['outlineWidth']) {
206
+ this.strokeSettings.outlineWidth = args.value['outlineWidth'];
207
+ }
208
+ break;
209
+ case 'getStrokeSettings':
210
+ args.value['obj']['strokeSettings'] = this.strokeSettings;
211
+ break;
212
+ case 'setKeyHistory':
213
+ this.keyHistory = args.value['keyHistory'];
214
+ break;
215
+ case 'getKeyHistory':
216
+ args.value['obj']['keyHistory'] = this.keyHistory;
217
+ break;
218
+ case 'setTextBoxPos':
219
+ this.setTextBoxPos(args.value['actObj'], args.value['degree'], args.value['flip'], args.value['x'], args.value['y']);
220
+ break;
221
+ case 'setTextBoxPoints':
222
+ this.setTextBoxPoints(args.value['actObj'], args.value['degree'], args.value['flip'], args.value['x'], args.value['y']);
223
+ break;
224
+ case 'alignTextAreaIntoCanvas':
225
+ this.alignTextAreaIntoCanvas();
226
+ break;
227
+ case 'initializeTextShape':
228
+ this.initializeTextShape(args.value['text'], args.value['fontFamily'], args.value['fontSize'],
229
+ args.value['bold'], args.value['italic'], args.value['underline'], args.value['strikethrough'], args.value['strokeColor'],
230
+ args.value['fillColor'], args.value['outlineColor'], args.value['outlineWidth']);
231
+ break;
232
+ case 'stopPathDrawing':
233
+ this.stopPathDrawing(args.value['e'], args.value['isApply']);
234
+ break;
235
+ case 'updateArrowRatio':
236
+ this.updateArrowRatio(args.value['obj']);
237
+ break;
238
+ case 'getSquarePointForRotatedShape':
239
+ this.getSquarePointForRotatedShape(args.value['obj'], args.value['object']);
240
+ break;
241
+ case 'drawImage':
242
+ this.drawImage(args.value['x'], args.value['y'], args.value['width'], args.value['height'],
243
+ args.value['src'], args.value['degree'], args.value['isAspectRatio'], args.value['opacity'],
244
+ args.value['isSelected']);
245
+ break;
246
+ case 'reset':
247
+ this.reset();
248
+ break;
249
+ case 'updateObj':
250
+ this.updateObj(args.value['dimObj'], args.value['x'], args.value['y']);
251
+ break;
252
+ case 'straightenShapes':
253
+ this.straightenShapes();
254
+ break;
255
+ case 'straightenShapePoints':
256
+ this.straightenShapePoints(args.value['obj'], args.value['isReverse']);
257
+ break;
258
+ case 'straightenPath':
259
+ this.straightenPath(args.value['obj']);
260
+ break;
261
+ case 'straightenFHD':
262
+ this.straightenFHD();
263
+ break;
264
+ case 'getTextBoxPosition':
265
+ this.getTextBoxPosition(args.value['obj'], args.value['object']);
266
+ break;
267
+ case 'setFlipState':
268
+ this.setFlipState(args.value['x'], args.value['y'], args.value['obj'], args.value['object']);
269
+ break;
270
+ case 'getNewShapeId':
271
+ args.value['obj']['id'] = this.getNewShapeId();
272
+ break;
273
+ case 'z-order':
274
+ this.updateZOrder(args.value['obj'], args.value['value']);
275
+ break;
276
+ case 'getSmallestIndex':
277
+ args.value['obj']['index'] = this.getSmallestIndex();
278
+ break;
279
+ case 'isIndexInObjColl':
280
+ args.value['obj']['bool'] = this.isIndexInObjColl(args.value['index']);
281
+ break;
282
+ case 'drawAnnotations':
283
+ this.drawAnnotations(args.value['ctx'], args.value['shape'], args.value['pen'],
284
+ args.value['isPreventApply'], args.value['x'], args.value['y'], args.value['panRegion']);
285
+ break;
286
+ case 'updateShapeColl':
287
+ this.updateShapeColl();
288
+ break;
289
+ case 'getNewOrder':
290
+ args.value['obj']['order'] = this.getNewOrder();
291
+ break;
292
+ case 'getHighestOrder':
293
+ args.value['obj']['order'] = this.getHighestOrder();
294
+ break;
295
+ case 'getLowestOrder':
296
+ args.value['obj']['order'] = this.getLowestOrder();
297
+ break;
298
+ case 'drawRedact':
299
+ this.drawRedact(args.value['x'], args.value['y'], args.value['width'], args.value['height'],
300
+ args.value['type'], args.value['value']);
301
+ break;
302
+ case 'setRedactType':
303
+ this.redactType = args.value['redactType'];
304
+ break;
305
+ }
306
+ }
307
+
308
+ public getModuleName(): string {
309
+ return 'shape';
310
+ }
311
+
312
+ private initShapePvtProps(): void {
313
+ const parent: ImageEditor = this.parent;
314
+ if (parent.lowerCanvas) {this.lowerContext = parent.lowerCanvas.getContext('2d'); }
315
+ if (parent.upperCanvas) {this.upperContext = parent.upperCanvas.getContext('2d'); }
316
+ if (isNullOrUndefined(this.shapeImg)) {
317
+ this.shapeImg = parent.createElement('img', {
318
+ id: parent.element.id + '_shapeImg', attrs: { name: 'Image', crossorigin: 'anonymous' }
319
+ });
320
+ }
321
+ if (this.textSettings.fontFamily === '') {
322
+ this.textSettings.fontFamily = parent.fontFamily.default;
323
+ }
324
+ }
325
+
326
+ private reset(): void {
327
+ this.textSettings =
328
+ {text: 'Enter Text', fontFamily: this.parent.fontFamily.default, fontSize: null, fontRatio: null, bold: false, italic: false, underline: false, strikethrough: false};
329
+ this.strokeSettings = {strokeColor: '#fff', fillColor: '', strokeWidth: null, radius: null, outlineColor: '', outlineWidth: null};
330
+ this.preventFrameAnnotation = false;
331
+ }
332
+
333
+ private drawEllipse(x?: number, y?: number, radiusX?: number, radiusY?: number, strokeWidth?: number, strokeColor?: string,
334
+ fillColor?: string, degree?: number, isSelected?: boolean): void {
335
+ this.initializeShape('ellipse');
336
+ const start: Point = x && y ? {x: x, y: y} : null;
337
+ this.drawShape('ellipse', strokeWidth, strokeColor, fillColor, start, radiusX, radiusY,
338
+ null, null, null, degree, null, isSelected);
339
+ }
340
+
341
+ private drawLine(startX?: number, startY?: number, endX?: number, endY?: number, strokeWidth?: number,
342
+ strokeColor?: string, isSelected?: boolean): void {
343
+ this.initializeShape('line');
344
+ const start: Point = startX && startY ? {x: startX, y: startY} : null;
345
+ const width: number = endX - startX; const height: number = endY - startY;
346
+ this.drawShape('line', strokeWidth, strokeColor, null, start, width, height, null, null, null, null, null, isSelected);
347
+ }
348
+
349
+ private drawPath(pointColl: Point[], strokeWidth?: number, strokeColor?: string, isSelected?: boolean): void {
350
+ this.initializeShape('path');
351
+ if (pointColl) {
352
+ this.drawShape('path', strokeWidth, strokeColor, null, null, null, null, pointColl, null, null, null, null, isSelected);
353
+ }
354
+ }
355
+
356
+ private drawArrow(startX?: number, startY?: number, endX?: number, endY?: number, strokeWidth?: number,
357
+ strokeColor?: string, arrowStart?: ArrowheadType, arrowEnd?: ArrowheadType, isSelected?: boolean): void {
358
+ this.initializeShape('arrow');
359
+ const start: Point = startX && startY ? {x: startX, y: startY} : null;
360
+ const width: number = endX - startX; const height: number = endY - startY;
361
+ this.drawShape('arrow', strokeWidth, strokeColor, null, start, width, height, null, arrowStart, arrowEnd, null, null, isSelected);
362
+ }
363
+
364
+ private drawRectangle(x?: number, y?: number, width?: number, height?: number, strokeWidth?: number, strokeColor?: string,
365
+ fillColor?: string, degree?: number, isSelected?: boolean, radius?: number): void {
366
+ this.initializeShape('rectangle');
367
+ const start: Point = x && y ? {x: x, y: y} : null;
368
+ this.drawShape('rectangle', strokeWidth, strokeColor, fillColor, start, width, height, null,
369
+ null, null, degree, null, isSelected, radius);
370
+ }
371
+
372
+ // eslint-disable-next-line @typescript-eslint/tslint/config
373
+ private drawRedact(x?: number, y?: number, width?: number, height?: number, type?: RedactType, value?: number) {
374
+ this.initializeShape('redact');
375
+ const start: Point = x && y ? {x: x, y: y} : null;
376
+ this.drawShape('redact', null, null, null, start, width, height, null,
377
+ null, null, null, null, null, null, type, value);
378
+ }
379
+
380
+ private drawText(x?: number, y?: number, text?: string, fontFamily?: string, fontSize?: number, bold?: boolean, italic?: boolean,
381
+ color?: string, isSelected?: boolean, degree?: number, fillColor?: string, outlineColor?: string,
382
+ outlineWidth?: number, transformCollection?: TransformationCollection[], underline?: boolean,
383
+ strikethrough?: boolean): void {
384
+ this.drawShapeText(text, fontFamily, fontSize, bold, italic, color, x, y, isSelected, degree,
385
+ fillColor, outlineColor, outlineWidth, transformCollection, underline, strikethrough);
386
+ }
387
+
388
+ private initializeShape(type: string): void {
389
+ const parent: ImageEditor = this.parent;
390
+ this.redrawActObj();
391
+ parent.activeObj.shape = type;
392
+ parent.currObjType.isCustomCrop = false;
393
+ }
394
+
395
+ private updateWidthHeight(obj: SelectionPoint): SelectionPoint {
396
+ obj.activePoint.width = obj.activePoint.endX - obj.activePoint.startX;
397
+ obj.activePoint.height = obj.activePoint.endY - obj.activePoint.startY;
398
+ return obj;
399
+ }
400
+
401
+ private setDimension(width: number, height: number): void {
402
+ const parent: ImageEditor = this.parent;
403
+ const shape: string = parent.activeObj.shape;
404
+ if ((width && height) || ((shape === 'line' || shape === 'arrow') && (width || height))) {
405
+ parent.activeObj.activePoint.width = width; parent.activeObj.activePoint.height = height;
406
+ if (parent.currObjType.shape.toLowerCase() === 'ellipse') {
407
+ parent.activeObj.activePoint.width = 2 * width;
408
+ parent.activeObj.activePoint.height = 2 * height;
409
+ }
410
+ }
411
+ }
412
+
413
+ private getArrowType(type: ArrowheadType): string {
414
+ let arrowType: string = type;
415
+ if (type) {
416
+ const typeToArrowType: Object = {'None': 'none', 'Arrow': 'arrow', 'SolidArrow': 'arrowSolid',
417
+ 'Circle': 'circle', 'SolidCircle': 'circleSolid', 'Square': 'square', 'SolidSquare': 'squareSolid', 'Bar': 'bar' };
418
+ arrowType = typeToArrowType[`${type}`];
419
+ }
420
+ return arrowType;
421
+ }
422
+
423
+ private drawShape(type: string, strokeWidth?: number, strokeColor?: string, fillColor?: string, start?: Point, width?: number,
424
+ height?: number, pointColl?: Point[], arrowStart?: ArrowheadType, arrowEnd?: ArrowheadType, degree?: number,
425
+ opacity?: number, isSelected?: boolean, radius?: number, redactType?: RedactType, value?: number): void {
426
+ const parent: ImageEditor = this.parent;
427
+ if (!parent.disabled && parent.isImageLoaded) {
428
+ parent.notify('draw', { prop: 'setImageEdited', onPropertyChange: false });
429
+ this.redrawActObj();
430
+ const objColl: SelectionPoint[] = extend([], parent.objColl, [], true) as SelectionPoint[];
431
+ parent.togglePen = false; this.keyHistory = '';
432
+ parent.upperCanvas.style.display = 'block'; this.refreshActiveObj();
433
+ parent.currObjType.shape = type = type.toLowerCase();
434
+ if (type !== 'freehanddraw' && type !== '') {
435
+ parent.activeObj.shape = type;
436
+ let strokeSettings: StrokeSettings = parent.activeObj.strokeSettings;
437
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
438
+ if (isNullOrUndefined(strokeSettings)) {
439
+ strokeSettings = this.strokeSettings;
440
+ }
441
+ if (type === 'path' && pointColl) {
442
+ parent.activeObj.pointColl = pointColl;
443
+ }
444
+ if (opacity !== null && opacity !== undefined) {parent.activeObj.opacity = opacity; }
445
+ strokeSettings.strokeWidth = strokeWidth ? strokeWidth : strokeSettings.strokeWidth;
446
+ const shape: string = parent.activeObj.shape;
447
+ if ((shape === 'rectangle' || shape === 'ellipse') && strokeWidth === 0) {
448
+ strokeSettings.strokeWidth = 0;
449
+ }
450
+ strokeSettings.strokeColor = strokeColor ? strokeColor : strokeSettings.strokeColor;
451
+ strokeSettings.fillColor = fillColor || fillColor === '' ? fillColor : strokeSettings.fillColor;
452
+ strokeSettings.radius = radius ? radius : strokeSettings.radius;
453
+ const tempWidth: number = parent.img.destWidth > 100 ? 100 : parent.img.destWidth / 2;
454
+ const tempHeight: number = parent.img.destHeight > 100 ? 100 : parent.img.destHeight / 2;
455
+ parent.activeObj.activePoint.width = tempWidth; parent.activeObj.activePoint.height = tempHeight;
456
+ if (type === 'line' || type === 'arrow') {
457
+ parent.activeObj.lineDraw = 'horizontal'; parent.activeObj.activePoint.height = 0;
458
+ if (type === 'arrow') {
459
+ parent.activeObj.activePoint.width += 50;
460
+ parent.activeObj.start = this.getArrowType(arrowStart); parent.activeObj.end = this.getArrowType(arrowEnd);
461
+ }
462
+ } else if (type === 'rectangle') {
463
+ parent.activeObj.activePoint.width += parent.activeObj.activePoint.width / 2;
464
+ } else if (type === 'redact') {
465
+ if (redactType) {
466
+ parent.activeObj.redactType = redactType.toLowerCase();
467
+ if (redactType === RedactType.Blur) {
468
+ if (value) {
469
+ parent.activeObj.redactBlur = value;
470
+ }
471
+ } else {
472
+ if (value) {
473
+ parent.activeObj.redactPixelate = value;
474
+ }
475
+ }
476
+ parent.activeObj.redactImage = parent.createElement('canvas');
477
+ }
478
+ }
479
+ this.setDimension(width, height);
480
+ if (start) {
481
+ parent.activeObj.activePoint.startX = start.x; parent.activeObj.activePoint.startY = start.y;
482
+ parent.activeObj.activePoint.endX = parent.activeObj.activePoint.startX +
483
+ parent.activeObj.activePoint.width;
484
+ parent.activeObj.activePoint.endY = parent.activeObj.activePoint.startY +
485
+ parent.activeObj.activePoint.height;
486
+ } else {
487
+ this.setCenterPoints();
488
+ }
489
+ this.setPointCollForLineAndArrow();
490
+ if (type === 'arrow') {
491
+ parent.activeObj.triangleDirection = 'right';
492
+ }
493
+ parent.currObjType.isDragging = parent.currObjType.isCustomCrop = false;
494
+ this.initShapeProps();
495
+ const obj: Object = {shapeSettingsObj: {} as ShapeSettings };
496
+ parent.notify('selection', { prop: 'updatePrevShapeSettings', onPropertyChange: false, value: {obj: obj}});
497
+ const shapeSettings: ShapeSettings = obj['shapeSettingsObj'];
498
+ const shapeChangingArgs: ShapeChangeEventArgs = {cancel: false, action: 'insert', previousShapeSettings: shapeSettings,
499
+ currentShapeSettings: shapeSettings};
500
+ parent.trigger('shapeChanging', shapeChangingArgs);
501
+ parent.editCompleteArgs = shapeChangingArgs;
502
+ this.updateShapeChangeEventArgs(shapeChangingArgs.currentShapeSettings, shapeChangingArgs.allowShapeOverflow);
503
+ this.setDimension(width, height);
504
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: 'duplicate'}});
505
+ if (degree) {
506
+ parent.activeObj.rotatedAngle = degree * (Math.PI / 180);
507
+ parent.notify('selection', {prop: 'updPtCollForShpRot', onPropertyChange: false, value: {obj: parent.activeObj }});
508
+ }
509
+ parent.notify('toolbar', { prop: 'renderQAT', onPropertyChange: false, value: {isPenEdit: null} });
510
+ parent.notify('selection', { prop: 'isShapeInserted', onPropertyChange: false, value: {bool: true} });
511
+ parent.notify('undo-redo', { prop: 'updateUrObj', onPropertyChange: false, value: {objColl: objColl}});
512
+ if (type === 'redact') {
513
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'redact',
514
+ isApplyBtn: null, isCropping: null, isZooming: null, cType: null}});
515
+ } else {
516
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'shapes',
517
+ isApplyBtn: null, isCropping: null, isZooming: null, cType: null}});
518
+ }
519
+ parent.notify('toolbar', { prop: 'update-toolbar-items', onPropertyChange: false});
520
+ if (parent.isPublicMethod && !isSelected) {
521
+ parent.notify('undo-redo', {prop: 'updateUndoRedo', value: {operation: 'shapeInsert'}, onPropertyChange: false});
522
+ }
523
+ parent.isPublicMethod = false;
524
+ }
525
+ }
526
+ }
527
+
528
+ private initShapeProps(): void {
529
+ const parent: ImageEditor = this.parent;
530
+ parent.activeObj.shapeDegree = parent.transform.degree;
531
+ parent.activeObj.shapeFlip = parent.transform.currFlipState;
532
+ parent.activeObj.textFlip = parent.transform.currFlipState;
533
+ parent.activeObj.flipObjColl = [];
534
+ parent.activeObj.order = this.getNewOrder();
535
+ }
536
+
537
+ private setPointCollForLineAndArrow(): void {
538
+ const parent: ImageEditor = this.parent;
539
+ const shape: string = parent.activeObj.shape;
540
+ const {startX, startY, endX, endY} : ActivePoint = parent.activeObj.activePoint;
541
+ if (shape === 'line' || shape === 'arrow') {
542
+ parent.activeObj.pointColl = this.getLinePoints(startX, startY, endX, endY);
543
+ if (parent.activeObj.pointColl) {
544
+ for (let i: number = 0, len: number = parent.activeObj.pointColl.length; i < len; i++) {
545
+ parent.activeObj.pointColl[i as number].ratioX = (parent.activeObj.pointColl[i as number].x -
546
+ parent.img.destLeft) / parent.img.destWidth;
547
+ parent.activeObj.pointColl[i as number].ratioY = (parent.activeObj.pointColl[i as number].y -
548
+ parent.img.destTop) / parent.img.destHeight;
549
+ }
550
+ }
551
+ }
552
+ }
553
+
554
+ private prevObjColl(): void {
555
+ const parent: ImageEditor = this.parent;
556
+ const object: Object = {currObj: {} as CurrentObject };
557
+ parent.notify('filter', { prop: 'getCurrentObj', onPropertyChange: false, value: {object: object }});
558
+ this.prevObj = object['currObj'];
559
+ this.prevObj.objColl = extend([], parent.objColl, [], true) as SelectionPoint[];
560
+ this.prevObj.pointColl = extend([], parent.pointColl, [], true) as Point[];
561
+ this.prevObj.afterCropActions = extend([], parent.afterCropActions, [], true) as string[];
562
+ const selPointCollObj: Object = {selPointColl: null };
563
+ parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false,
564
+ value: {obj: selPointCollObj }});
565
+ this.prevObj.selPointColl = extend([], selPointCollObj['selPointColl'], [], true) as Point[];
566
+ }
567
+
568
+ private drawShapeText(text?: string, fontFamily?: string, fontSize?: number, bold?: boolean, italic?: boolean,
569
+ strokeColor?: string, x?: number, y?: number, isSelected?: boolean, degree?: number, fillColor?: string,
570
+ outlineColor?: string, outlineWidth?: number, transformCollection?: TransformationCollection[],
571
+ underline?: boolean, strikethrough?: boolean): void {
572
+ const parent: ImageEditor = this.parent;
573
+ if (!parent.disabled && parent.isImageLoaded) {
574
+ if (parent.currObjType.shape === 'freehanddraw') {
575
+ this.apply();
576
+ parent.upperCanvas.style.cursor = parent.cursor = 'default';
577
+ parent.currObjType.shape = '';
578
+ }
579
+ parent.notify('draw', { prop: 'setImageEdited', onPropertyChange: false });
580
+ parent.togglePen = false; this.redrawActObj();
581
+ this.prevObjColl();
582
+ this.refreshActiveObj(); parent.activeObj.shape = parent.currObjType.shape = 'text';
583
+ parent.currObjType.isCustomCrop = false;
584
+ this.initializeTextShape(text, fontFamily, fontSize, bold, italic, underline, strikethrough, strokeColor, fillColor,
585
+ outlineColor, outlineWidth);
586
+ parent.currObjType.isText = parent.currObjType.isInitialText = true;
587
+ if (isNullOrUndefined(parent.activeObj.textSettings.fontSize)) {
588
+ parent.getFontSizes();
589
+ parent.activeObj.textSettings.fontSize = parseInt(parent.fontSizeColl[(parseInt('3', 10) - 1)].text, 10);
590
+ }
591
+ if (parent.img.destWidth < 100) {
592
+ parent.activeObj.textSettings.fontSize = Math.floor((parent.img.destWidth / 20));
593
+ } else if (parent.img.destHeight < 100) {
594
+ parent.activeObj.textSettings.fontSize = Math.floor((parent.img.destHeight / 20));
595
+ }
596
+ parent.activeObj.shapeDegree = parent.transform.degree;
597
+ parent.activeObj.shapeFlip = parent.transform.currFlipState;
598
+ parent.activeObj.flipObjColl = []; this.updateFontStyles();
599
+ parent.activeObj.order = this.getNewOrder();
600
+ let width: number = this.upperContext.measureText(parent.activeObj.textSettings.text).width +
601
+ parent.activeObj.textSettings.fontSize * 0.5;
602
+ let height: number = parent.activeObj.textSettings.fontSize;
603
+ if (text) {
604
+ parent.activeObj.keyHistory = text;
605
+ let maxText: string = this.getMaxText();
606
+ maxText = maxText ? maxText : parent.activeObj.textSettings.text;
607
+ width = this.upperContext.measureText(maxText).width + parent.activeObj.textSettings.fontSize * 0.5;
608
+ const rows: string[] = text.split('\n');
609
+ if (rows.length > 1) {
610
+ height = rows.length * parent.activeObj.textSettings.fontSize;
611
+ height += (fontSize * 0.25);
612
+ }
613
+ }
614
+ if (!isNullOrUndefined(x) && !isNullOrUndefined(y)) {
615
+ parent.activeObj.activePoint.startX = x; parent.activeObj.activePoint.startY = y;
616
+ parent.activeObj.activePoint.endX = parent.activeObj.activePoint.startX + width;
617
+ parent.activeObj.activePoint.endY = parent.activeObj.activePoint.startY + height;
618
+ } else {
619
+ this.setCenterPoints(true, width, height);
620
+ }
621
+ if (transformCollection) {
622
+ parent.notify('selection', { prop: 'setTransformedShape', onPropertyChange: false, value: {bool: true}});
623
+ this.setTransformColl(transformCollection);
624
+ const actObj: SelectionPoint = parent.activeObj;
625
+ actObj.shapeDegree = 0;
626
+ actObj.shapeFlip = '';
627
+ let tempDegree: number = 0;
628
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
629
+ const coll: any = actObj.rotateFlipColl;
630
+ for (let i: number = 0; i < coll.length; i++) {
631
+ if (typeof(coll[i as number]) === 'number') {
632
+ tempDegree += coll[i as number];
633
+ }
634
+ }
635
+ if (tempDegree % 90 === 0 && Math.abs(tempDegree) % 180 === 90) {
636
+ actObj.activePoint.endX = actObj.activePoint.startX + height;
637
+ actObj.activePoint.endY = actObj.activePoint.startY + width;
638
+ actObj.activePoint.width = actObj.activePoint.endX - actObj.activePoint.startX;
639
+ actObj.activePoint.height = actObj.activePoint.endY - actObj.activePoint.startY;
640
+ }
641
+ }
642
+ const obj: Object = {shapeSettingsObj: {} as ShapeSettings };
643
+ parent.notify('selection', { prop: 'updatePrevShapeSettings', onPropertyChange: false, value: {obj: obj}});
644
+ const shapeSettings: ShapeSettings = obj['shapeSettingsObj'];
645
+ const shapeChangingArgs: ShapeChangeEventArgs = {cancel: false, action: 'insert', previousShapeSettings: shapeSettings,
646
+ currentShapeSettings: shapeSettings};
647
+ parent.trigger('shapeChanging', shapeChangingArgs);
648
+ parent.editCompleteArgs = shapeChangingArgs;
649
+ this.drawShapeTextEvent(shapeChangingArgs);
650
+ if (degree) {
651
+ parent.activeObj.rotatedAngle = degree * (Math.PI / 180);
652
+ parent.notify('selection', { prop: 'updPtCollForShpRot', onPropertyChange: false, value: { obj: parent.activeObj } });
653
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
654
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: { canvas: 'duplicate', obj: parent.activeObj, isCropRatio: null,
655
+ points: null, isPreventDrag: true, saveContext: null, isPreventSelection: null } });
656
+ parent.notify('toolbar', { prop: 'destroy-qa-toolbar', onPropertyChange: false });
657
+ parent.notify('toolbar', { prop: 'renderQAT', onPropertyChange: false, value: { isPenEdit: null } });
658
+ }
659
+ if (text && text.indexOf('\n') > -1 && parent.isPublicMethod) {
660
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
661
+ const fontSizeInd: string = String((parent.fontSizeColl as any).findIndex(
662
+ (item: { text: string; }) => item.text === String(parent.activeObj.textSettings.fontSize)) + 1);
663
+ parent.noPushUndo = true;
664
+ parent.updateFontSize('5');
665
+ if (parseInt(fontSizeInd, 10) > 0) {
666
+ parent.updateFontSize(fontSizeInd);
667
+ }
668
+ parent.noPushUndo = false;
669
+ }
670
+ if (parent.isPublicMethod && !isSelected) {
671
+ parent.notify('undo-redo', {prop: 'updateUndoRedo', value: {operation: 'shapeInsert'}, onPropertyChange: false});
672
+ }
673
+ parent.isPublicMethod = false;
674
+ }
675
+ }
676
+
677
+ private drawShapeImageEvent(shapeChangingArgs: ShapeChangeEventArgs, isSelect: boolean): void {
678
+ const parent: ImageEditor = this.parent;
679
+ this.updateShapeChangeEventArgs(shapeChangingArgs.currentShapeSettings, shapeChangingArgs.allowShapeOverflow);
680
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: 'duplicate' }});
681
+ parent.objColl.push(parent.activeObj);
682
+ const prevCropObj: CurrentObject = extend({}, parent.cropObj, {}, true) as CurrentObject;
683
+ parent.notify('undo-redo', { prop: 'updateUndoRedoColl', onPropertyChange: false,
684
+ value: {operation: 'shapeInsert', previousObj: this.prevObj, previousObjColl: this.prevObj.objColl,
685
+ previousPointColl: this.prevObj.pointColl, previousSelPointColl: this.prevObj.selPointColl, previousCropObj: prevCropObj,
686
+ previousText: null, currentText: null, previousFilter: null, isCircleCrop: null}});
687
+ parent.notify('selection', { prop: 'redrawShape', onPropertyChange: false,
688
+ value: {obj: parent.objColl[parent.objColl.length - 1]}});
689
+ if (isSelect) {
690
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'shapes',
691
+ isApplyBtn: null, isCropping: null, isZooming: null, cType: null}});
692
+ parent.notify('toolbar', { prop: 'update-toolbar-items', onPropertyChange: false});
693
+ parent.notify('toolbar', { prop: 'renderQAT', onPropertyChange: false, value: {isPenEdit: null} });
694
+ } else {
695
+ parent.okBtn(null, true);
696
+ }
697
+ parent.notify('selection', { prop: 'isShapeInserted', onPropertyChange: false, value: {bool: true} });
698
+ }
699
+
700
+ private setTransformColl(transformCollection: TransformationCollection[]): void {
701
+ const parent: ImageEditor = this.parent;
702
+ parent.activeObj.rotateFlipColl = [];
703
+ if (transformCollection) {
704
+ for (let i: number = 0; i < transformCollection.length; i++) {
705
+ if (transformCollection[i as number].degree) {
706
+ parent.activeObj.rotateFlipColl.push(transformCollection[i as number].degree);
707
+ } else {
708
+ parent.activeObj.rotateFlipColl.push(transformCollection[i as number].flip.toLowerCase());
709
+ }
710
+ }
711
+ }
712
+ }
713
+
714
+ private drawShapeTextEvent(shapeChangingArgs: ShapeChangeEventArgs): void {
715
+ const parent: ImageEditor = this.parent;
716
+ this.updateShapeChangeEventArgs(shapeChangingArgs.currentShapeSettings, shapeChangingArgs.allowShapeOverflow);
717
+ this.addLetter(parent.activeObj.textSettings.text);
718
+ parent.activeObj.textFlip = parent.transform.currFlipState;
719
+ this.updateFontRatio(parent.activeObj);
720
+ parent.objColl.push(parent.activeObj);
721
+ const prevCropObj: CurrentObject = extend({}, parent.cropObj, {}, true) as CurrentObject;
722
+ parent.notify('undo-redo', { prop: 'updateUndoRedoColl', onPropertyChange: false,
723
+ value: {operation: 'shapeInsert', previousObj: this.prevObj, previousObjColl: this.prevObj.objColl,
724
+ previousPointColl: this.prevObj.pointColl, previousSelPointColl: this.prevObj.selPointColl,
725
+ previousCropObj: prevCropObj, previousText: null, currentText: null, previousFilter: null, isCircleCrop: null}});
726
+ parent.notify('selection', { prop: 'redrawShape', onPropertyChange: false,
727
+ value: {obj: parent.objColl[parent.objColl.length - 1]}});
728
+ parent.notify('toolbar', { prop: 'renderQAT', onPropertyChange: false, value: {isPenEdit: null} });
729
+ parent.notify('selection', { prop: 'isShapeInserted', onPropertyChange: false, value: {bool: true} });
730
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'text',
731
+ isApplyBtn: null, isCropping: null, isZooming: null, cType: null}});
732
+ parent.notify('toolbar', { prop: 'update-toolbar-items', onPropertyChange: false});
733
+ }
734
+
735
+ private initializeTextShape(
736
+ text?: string, fontFamily?: string, fontSize?: number, bold?: boolean, italic?: boolean,
737
+ underline?: boolean, strikethrough?: boolean, strokeColor?: string, fillColor?: string, outlineColor?: string, outlineWidth?: number
738
+ ): void {
739
+ const parent: ImageEditor = this.parent;
740
+ this.keyHistory = ''; parent.upperCanvas.style.display = 'block';
741
+ parent.activeObj.strokeSettings.strokeColor = strokeColor || parent.activeObj.strokeSettings.strokeColor;
742
+ parent.activeObj.strokeSettings.fillColor = fillColor || parent.activeObj.strokeSettings.fillColor;
743
+ parent.activeObj.textSettings.text = text || parent.activeObj.textSettings.text;
744
+ parent.activeObj.textSettings.fontFamily = fontFamily || parent.activeObj.textSettings.fontFamily;
745
+ parent.activeObj.textSettings.fontSize = fontSize || parent.activeObj.textSettings.fontSize;
746
+ parent.activeObj.textSettings.bold = bold || parent.activeObj.textSettings.bold;
747
+ parent.activeObj.textSettings.italic = italic || parent.activeObj.textSettings.italic;
748
+ parent.activeObj.textSettings.underline = underline || parent.activeObj.textSettings.underline;
749
+ parent.activeObj.textSettings.strikethrough = strikethrough || parent.activeObj.textSettings.strikethrough;
750
+ parent.activeObj.strokeSettings.outlineColor = outlineColor || parent.activeObj.strokeSettings.outlineColor;
751
+ parent.activeObj.strokeSettings.outlineWidth = outlineWidth || parent.activeObj.strokeSettings.outlineWidth;
752
+ }
753
+
754
+ private drawImage(x: number, y: number, width: number, height: number, src: string | ImageData, degree: number,
755
+ isAspectRatio: boolean, opacity?: number, isSelected?: boolean): void {
756
+ this.initializeShape('image');
757
+ this.onLoadImgShape(x, y, width, height, src, null, degree, isAspectRatio, opacity, isSelected);
758
+ }
759
+
760
+ private redrawActObj(x?: number, y?: number, isMouseDown?: boolean): void {
761
+ let splitWords: string[];
762
+ const parent: ImageEditor = this.parent;
763
+ if (parent.activeObj.shape) {splitWords = parent.activeObj.shape.split('-'); }
764
+ if (parent.activeObj.horTopLine && (parent.activeObj.shape && splitWords[0] !== 'crop')) {
765
+ if (parent.textArea.style.display === 'block' || parent.textArea.style.display === 'inline-block') {
766
+ parent.notify('selection', { prop: 'setTextBoxStylesToActObj', onPropertyChange: false });
767
+ this.updateFontRatio(parent.activeObj, true);
768
+ if (x && y) {
769
+ if ((x !== parent.activeObj.activePoint.startX) && (y !== parent.activeObj.activePoint.startY)) {
770
+ this.updateTextFromTextArea();
771
+ }
772
+ } else {
773
+ this.updateTextFromTextArea();
774
+ parent.textArea.style.transform = '';
775
+ parent.notify('toolbar', { prop: 'refresh-main-toolbar', onPropertyChange: false});
776
+ }
777
+ this.refreshActiveObj();
778
+ } else {
779
+ this.applyActObj(isMouseDown);
780
+ }
781
+ }
782
+ }
783
+
784
+ private apply(shape?: string, obj?: SelectionPoint, canvas?: string): void {
785
+ const parent: ImageEditor = this.parent;
786
+ if (!parent.disabled) {
787
+ if (parent.togglePen && !parent.currObjType.isCustomCrop) {
788
+ const destLeft: number = parent.img.destLeft; const destTop: number = parent.img.destTop;
789
+ const destWidth: number = parent.img.destWidth; const destHeight: number = parent.img.destHeight;
790
+ parent.notify('draw', { prop: 'callUpdateCurrTransState', onPropertyChange: false});
791
+ const temp: string = this.lowerContext.filter; this.lowerContext.filter = 'none';
792
+ parent.togglePen = false;
793
+ if (parent.isCircleCrop || (parent.currSelectionPoint &&
794
+ parent.currSelectionPoint.shape === 'crop-circle')) {
795
+ parent.notify('crop', { prop: 'cropCircle', onPropertyChange: false,
796
+ value: {context: this.lowerContext, isSave: null, isFlip: null}});
797
+ }
798
+ parent.img.destLeft = destLeft; parent.img.destTop = destTop; parent.img.destWidth = destWidth;
799
+ parent.img.destHeight = destHeight; this.lowerContext.filter = temp;
800
+ }
801
+ else {
802
+ canvas = canvas ? canvas : 'original';
803
+ if (isNullOrUndefined(parent.activeObj.shape) && isNullOrUndefined(shape)) {
804
+ parent.currObjType.shape = '';
805
+ } else {
806
+ parent.currObjType.shape = shape || parent.currObjType.shape;
807
+ }
808
+ if (parent.currObjType.shape !== '') {
809
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
810
+ if (parent.activeObj.shape === 'text') {
811
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: canvas, obj: obj, isCropRatio: null,
812
+ points: null, isPreventDrag: true, saveContext: null, isPreventSelection: null} });
813
+ } else {
814
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: canvas, obj: obj} });
815
+ }
816
+ parent.activeObj.shape = parent.currObjType.shape.toLowerCase();
817
+ if (!shape && parent.currObjType.shape !== '' && !parent.currObjType.isCustomCrop) {
818
+ parent.objColl.push(extend({}, parent.activeObj, {}, true) as SelectionPoint);
819
+ }
820
+ this.keyHistory = '';
821
+ }
822
+ }
823
+ }
824
+ }
825
+
826
+ private setCenterPoints(text?: boolean, width?: number, height?: number): void {
827
+ const parent: ImageEditor = this.parent;
828
+ let renderWidth: number; let renderHeight: number;
829
+ if (text && width && height) { renderWidth = width; renderHeight = height; }
830
+ else {renderWidth = parent.activeObj.activePoint.width; renderHeight = parent.activeObj.activePoint.height; }
831
+ parent.activeObj.activePoint.startX = (parent.lowerCanvas.width / 2) - renderWidth / 2;
832
+ parent.activeObj.activePoint.startY = (parent.lowerCanvas.height / 2) - renderHeight / 2;
833
+ parent.activeObj.activePoint.endX = (parent.lowerCanvas.width / 2) + renderWidth / 2;
834
+ parent.activeObj.activePoint.endY = (parent.lowerCanvas.height / 2) + renderHeight / 2;
835
+ }
836
+
837
+ private updSelChangeEventArgs(selectionSettings: CropSelectionSettings): void {
838
+ const parent: ImageEditor = this.parent;
839
+ parent.activeObj.activePoint = { startX: selectionSettings.startX, startY: selectionSettings.startY,
840
+ endX: parent.activeObj.activePoint.startX + parent.activeObj.activePoint.width,
841
+ endY: parent.activeObj.activePoint.startY + parent.activeObj.activePoint.height,
842
+ width: selectionSettings.width, height: selectionSettings.height };
843
+ parent.activeObj.activePoint.endX = parent.activeObj.activePoint.startX + parent.activeObj.activePoint.width;
844
+ parent.activeObj.activePoint.endY = parent.activeObj.activePoint.startY + parent.activeObj.activePoint.height;
845
+ }
846
+
847
+ private updateShapeChangeEventArgs(shapeSettings: ShapeSettings, allowShapeOverflow: boolean): void {
848
+ const parent: ImageEditor = this.parent; let shapeId: number;
849
+ if (shapeSettings.id && shapeSettings.id.indexOf('shape_') === -1 &&
850
+ shapeSettings.id.indexOf('pen_') === -1) {
851
+ if (parent.activeObj.currIndex) {
852
+ parent.activeObj.currIndex = 'shape_' + shapeSettings.id;
853
+ } else {
854
+ parent.pointColl[shapeId as number].id = 'pen_' + shapeSettings.id;
855
+ }
856
+ }
857
+ if (shapeSettings.id && shapeSettings.id.split('_')[0] && shapeSettings.id.split('_')[0] === 'pen') {
858
+ shapeId = parseInt(shapeSettings.id.split('_')[1], 10) - 1;
859
+ parent.pointColl[shapeId as number].points = shapeSettings.points;
860
+ parent.pointColl[shapeId as number].strokeColor = shapeSettings.strokeColor;
861
+ parent.pointColl[shapeId as number].strokeWidth = shapeSettings.strokeWidth;
862
+ parent.pointColl[shapeId as number].opacity = shapeSettings.opacity;
863
+ if (shapeSettings.index) {
864
+ parent.pointColl[shapeId as number].order = shapeSettings.index;
865
+ }
866
+ } else {
867
+ parent.activeObj.activePoint.startX = shapeSettings.startX;
868
+ parent.activeObj.activePoint.startY = shapeSettings.startY;
869
+ if (shapeSettings.width && shapeSettings.height) {
870
+ parent.activeObj.activePoint.width = shapeSettings.width;
871
+ parent.activeObj.activePoint.height = shapeSettings.height;
872
+ parent.activeObj.activePoint.endX = parent.activeObj.activePoint.startX + parent.activeObj.activePoint.width;
873
+ parent.activeObj.activePoint.endY = parent.activeObj.activePoint.startY + parent.activeObj.activePoint.height;
874
+ }
875
+ if (parent.activeObj.shape !== 'text') {
876
+ parent.activeObj.strokeSettings.strokeColor = shapeSettings.strokeColor;
877
+ parent.activeObj.strokeSettings.strokeWidth = shapeSettings.strokeWidth;
878
+ }
879
+ parent.activeObj.strokeSettings.fillColor = shapeSettings.fillColor;
880
+ parent.activeObj.opacity = shapeSettings.opacity;
881
+ if (shapeSettings.index) {
882
+ parent.activeObj.order = shapeSettings.index;
883
+ }
884
+ parent.activeObj.preventShapeDragOut = !allowShapeOverflow;
885
+ if (isNullOrUndefined(shapeSettings.degree)) { shapeSettings.degree = 0; }
886
+ switch (parent.activeObj.shape) {
887
+ case 'ellipse':
888
+ parent.activeObj.activePoint.width = shapeSettings.radiusX * 2;
889
+ parent.activeObj.activePoint.height = shapeSettings.radiusY * 2;
890
+ parent.activeObj.activePoint.endX = parent.activeObj.activePoint.startX + parent.activeObj.activePoint.width;
891
+ parent.activeObj.activePoint.endY = parent.activeObj.activePoint.startY + parent.activeObj.activePoint.height;
892
+ if (shapeSettings.degree) {
893
+ parent.activeObj.rotatedAngle = shapeSettings.degree * (Math.PI / 180);
894
+ }
895
+ break;
896
+ case 'line':
897
+ case 'arrow':
898
+ parent.activeObj.activePoint.width = shapeSettings.length;
899
+ parent.activeObj.activePoint.endX = shapeSettings.endX;
900
+ parent.activeObj.activePoint.endY = shapeSettings.endY;
901
+ parent.activeObj.activePoint.width = parent.activeObj.activePoint.startX + parent.activeObj.activePoint.width;
902
+ parent.activeObj.activePoint.height = parent.activeObj.activePoint.startY + parent.activeObj.activePoint.height;
903
+ if (parent.activeObj.shape === 'arrow') {
904
+ parent.activeObj.start = this.getArrowType(shapeSettings.arrowHead);
905
+ parent.activeObj.end = this.getArrowType(shapeSettings.arrowTail);
906
+ }
907
+ break;
908
+ case 'text':
909
+ parent.activeObj.keyHistory = parent.activeObj.textSettings.text = shapeSettings.text;
910
+ parent.activeObj.textSettings.fontSize = shapeSettings.fontSize;
911
+ parent.activeObj.strokeSettings.strokeColor = shapeSettings.color;
912
+ parent.activeObj.strokeSettings.outlineColor = shapeSettings.strokeColor;
913
+ parent.activeObj.strokeSettings.outlineWidth = shapeSettings.strokeWidth;
914
+ parent.activeObj.strokeSettings.fillColor = shapeSettings.fillColor;
915
+ parent.activeObj.textSettings.fontFamily = shapeSettings.fontFamily;
916
+ this.setTransformColl(shapeSettings.transformCollection);
917
+ if (shapeSettings.degree) {
918
+ parent.activeObj.rotatedAngle = shapeSettings.degree * (Math.PI / 180);
919
+ }
920
+ this.updateFontRatio(parent.activeObj);
921
+ break;
922
+ case 'rectangle':
923
+ case 'image':
924
+ if (shapeSettings.degree) {
925
+ parent.activeObj.rotatedAngle = shapeSettings.degree * (Math.PI / 180);
926
+ }
927
+ // Prevented setting image src as it cannot be set in canvas
928
+ break;
929
+ case 'path':
930
+ parent.activeObj.pointColl = shapeSettings.points;
931
+ break;
932
+ }
933
+ if (parent.activeObj.shape === 'text' && parent.activeObj.textSettings) {
934
+ parent.activeObj.textSettings.bold = false; parent.activeObj.textSettings.italic = false;
935
+ parent.activeObj.textSettings.underline = false; parent.activeObj.textSettings.strikethrough = false;
936
+ for (let i: number = 0; i < shapeSettings.fontStyle.length; i++) {
937
+ switch (shapeSettings.fontStyle[i as number]) {
938
+ case 'bold':
939
+ parent.activeObj.textSettings.bold = true;
940
+ break;
941
+ case 'italic':
942
+ parent.activeObj.textSettings.italic = true;
943
+ break;
944
+ case 'underline':
945
+ parent.activeObj.textSettings.underline = true;
946
+ break;
947
+ case 'strikethrough':
948
+ parent.activeObj.textSettings.strikethrough = true;
949
+ break;
950
+ }
951
+ }
952
+ }
953
+ }
954
+ }
955
+
956
+ private addLetter(letter: string): void {
957
+ const parent: ImageEditor = this.parent;
958
+ if (parent.textArea.style.display === 'none' && (parent.currObjType.isText || parent.activeObj.shape === 'text')) {
959
+ const {fontSize} : TextSettings = parent.activeObj.textSettings;
960
+ if (letter === 'Backspace') {this.keyHistory = this.keyHistory.slice(0, -1); }
961
+ else {this.keyHistory += letter; }
962
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
963
+ this.updateFontStyles();
964
+ const width: number = this.upperContext.measureText(this.keyHistory).width + fontSize * 0.5;
965
+ const height: number = fontSize * 1.18;
966
+ this.upperContext.fillText(this.keyHistory, parent.activeObj.activePoint.startX,
967
+ parent.activeObj.activePoint.startY + fontSize);
968
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
969
+ parent.currObjType.isText = true;
970
+ parent.notify('selection', { prop: 'setActivePoint', onPropertyChange: false,
971
+ value: {startX: width, startY: height}});
972
+ }
973
+ }
974
+
975
+ private redrawText(): void {
976
+ const parent: ImageEditor = this.parent;
977
+ const {fontSize, fontFamily, bold, italic } : TextSettings = parent.activeObj.textSettings;
978
+ let fontStyle: string = '';
979
+ if (bold) {
980
+ fontStyle += 'bold ';
981
+ }
982
+ if (italic) {
983
+ fontStyle += 'italic ';
984
+ }
985
+ this.upperContext.font = fontStyle + fontSize + 'px ' + fontFamily;
986
+ const rows: string[] = parent.activeObj.keyHistory.split('\n');
987
+ const text: string = (parent.textArea.style.display === 'block' || parent.textArea.style.display === 'inline-block') ?
988
+ this.getMaxText(true) : this.getMaxText();
989
+ const width: number = this.upperContext.measureText(text).width + fontSize * 0.5;
990
+ let height: number = rows.length * fontSize * 1.18;
991
+ if (rows.length > 1) {height += (fontSize * 0.50); }
992
+ parent.notify('selection', { prop: 'setTextSelection', onPropertyChange: false,
993
+ value: {width: width, height: height}});
994
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value: {actPoint: parent.activeObj.activePoint, obj: parent.activeObj,
995
+ isMouseMove: null, x: null, y: null}});
996
+ parent.notify('selection', { prop: 'redrawShape', onPropertyChange: false,
997
+ value: {obj: parent.activeObj}});
998
+ }
999
+
1000
+ private updateTextFromTextArea(): void {
1001
+ const parent: ImageEditor = this.parent; let allowUndoRedo: boolean = false;
1002
+ const { fontSize } : TextSettings = parent.activeObj.textSettings;
1003
+ const tempActiveObj: SelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
1004
+ const prevCropObj: CurrentObject = extend({}, parent.cropObj, {}, true) as CurrentObject;
1005
+ const object: Object = {currObj: {} as CurrentObject };
1006
+ parent.notify('filter', { prop: 'getCurrentObj', onPropertyChange: false, value: {object: object }});
1007
+ const prevObj: CurrentObject = object['currObj'];
1008
+ prevObj.objColl = extend([], parent.objColl, [], true) as SelectionPoint[];
1009
+ prevObj.pointColl = extend([], parent.pointColl, [], true) as Point[];
1010
+ prevObj.afterCropActions = extend([], parent.afterCropActions, [], true) as string[];
1011
+ const selPointCollObj: Object = {selPointColl: null };
1012
+ parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false,
1013
+ value: {obj: selPointCollObj }});
1014
+ prevObj.selPointColl = extend([], selPointCollObj['selPointColl'], [], true) as Point[];
1015
+ if (parent.activeObj.keyHistory !== parent.textArea.value) {
1016
+ allowUndoRedo = true;
1017
+ }
1018
+ parent.activeObj.keyHistory = parent.textArea.value; parent.textArea.style.display = 'none';
1019
+ parent.textArea.value = ''; this.updateFontStyles();
1020
+ let width: number = this.upperContext.measureText(parent.activeObj.keyHistory).width + fontSize * 0.5;
1021
+ let height: number = fontSize * 1.18;
1022
+ const rows: string[] = parent.activeObj.keyHistory.split('\n');
1023
+ if (rows.length > 1) {
1024
+ height *= rows.length;
1025
+ height += (fontSize * 0.1 * rows.length);
1026
+ const widthColl: number[] = [];
1027
+ for (let i: number = 0, len: number = rows.length; i < len; i++) {
1028
+ widthColl.push(this.upperContext.measureText(rows[i as number]).width + fontSize * 0.5);
1029
+ }
1030
+ width = Math.max(...widthColl);
1031
+ }
1032
+ parent.notify('selection', { prop: 'setTextSelection', onPropertyChange: false,
1033
+ value: {width: width, height: height}});
1034
+ if (parent.activeObj.rotatedAngle !== 0) {
1035
+ const width: number = parent.activeObj.activePoint.width - tempActiveObj.activePoint.width;
1036
+ const height: number = parent.activeObj.activePoint.height - tempActiveObj.activePoint.height;
1037
+ let value: string = '';
1038
+ if (width > 0 && height > 0) {
1039
+ value = 'widthHeight';
1040
+ } else if (width !== 0) {
1041
+ value = 'width';
1042
+ } else if (height !== 0) {
1043
+ value = 'height';
1044
+ }
1045
+ parent.activeObj.activePoint = extend({}, tempActiveObj.activePoint, {}, true) as ActivePoint;
1046
+ parent.notify('selection', { prop: 'adjustRotationPoints', onPropertyChange: false, value: { rectangle: parent.activeObj.activePoint,
1047
+ x: width, y: height, angle: parent.activeObj.rotatedAngle, type: 'text', elem: value }});
1048
+ parent.notify('shape', { prop: 'updateFontSize', onPropertyChange: false,
1049
+ value: {obj: parent.activeObj}});
1050
+ }
1051
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value: {actPoint: parent.activeObj.activePoint, obj: parent.activeObj,
1052
+ isMouseMove: null, x: null, y: null}});
1053
+ this.updImgRatioForActObj();
1054
+ if (parent.activeObj.rotatedAngle !== 0) {
1055
+ parent.notify('selection', {prop: 'updPtCollForShpRot', onPropertyChange: false, value: {obj: parent.activeObj }});
1056
+ }
1057
+ if (allowUndoRedo) {
1058
+ this.apply(parent.activeObj.shape, parent.activeObj);
1059
+ parent.objColl.push(extend({}, parent.activeObj, {}, true) as SelectionPoint);
1060
+ parent.notify('undo-redo', { prop: 'updateUndoRedoColl', onPropertyChange: false,
1061
+ value: {operation: 'text', previousObj: prevObj, previousObjColl: prevObj.objColl,
1062
+ previousPointColl: prevObj.pointColl, previousSelPointColl: prevObj.selPointColl,
1063
+ previousCropObj: prevCropObj, previousText: parent.activeObj.keyHistory,
1064
+ currentText: parent.textArea.value, previousFilter: null, isCircleCrop: null}});
1065
+ } else {
1066
+ this.apply(parent.activeObj.shape, parent.activeObj);
1067
+ parent.objColl.push(extend({}, parent.activeObj, {}, true) as SelectionPoint);
1068
+ }
1069
+ }
1070
+
1071
+ private iterateObjColl(): void {
1072
+ const parent: ImageEditor = this.parent;
1073
+ if (parent.objColl.length > 0) {
1074
+ let index: number = this.getSmallestIndex();
1075
+ const objColl: SelectionPoint[] = extend([], parent.objColl, [], true) as SelectionPoint[];
1076
+ while (objColl.length > 0) {
1077
+ let found: boolean = false;
1078
+ for (let i: number = 0; i < objColl.length; i++) {
1079
+ const currentObj: SelectionPoint = objColl[i as number];
1080
+ if (isNullOrUndefined(currentObj.order)) {
1081
+ objColl.splice(i, 1);
1082
+ i--;
1083
+ continue;
1084
+ }
1085
+ if (currentObj.order === index) {
1086
+ this.apply(currentObj.shape, currentObj);
1087
+ if (currentObj.shape === 'redact' && JSON.stringify(currentObj.activePoint) === JSON.stringify(parent.activeObj.activePoint) &&
1088
+ currentObj.redactImage !== parent.activeObj.redactImage) {
1089
+ currentObj.redactImage = parent.activeObj.redactImage;
1090
+ if (parent.objColl[i as number] && JSON.stringify(parent.objColl[i as number].activePoint) ===
1091
+ JSON.stringify(currentObj.activePoint)) {
1092
+ parent.objColl[i as number].redactImage = parent.activeObj.redactImage;
1093
+ }
1094
+ }
1095
+ this.refreshActiveObj();
1096
+ index++;
1097
+ if (!this.isIndexInObjColl(index)) {index++; }
1098
+ objColl.splice(i, 1);
1099
+ found = true;
1100
+ break; // Exit the loop to start from the beginning
1101
+ }
1102
+ }
1103
+ if (!found) {
1104
+ break; // If no matching order was found, exit the loop
1105
+ }
1106
+ }
1107
+ }
1108
+ }
1109
+
1110
+ private getSmallestIndex(): number {
1111
+ const parent: ImageEditor = this.parent;
1112
+ let smallestIndex: number;
1113
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
1114
+ const currentObj: SelectionPoint = parent.objColl[i as number];
1115
+ if (isNullOrUndefined(currentObj.order)) {
1116
+ continue;
1117
+ }
1118
+ if (isNullOrUndefined(smallestIndex) || currentObj.order < smallestIndex) {
1119
+ smallestIndex = currentObj.order;
1120
+ }
1121
+ }
1122
+ return smallestIndex;
1123
+ }
1124
+
1125
+ private isIndexInObjColl(index: number): boolean {
1126
+ const parent: ImageEditor = this.parent;
1127
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
1128
+ const currentObj: SelectionPoint = parent.objColl[i as number];
1129
+ if (isNullOrUndefined(currentObj.order)) {
1130
+ continue;
1131
+ }
1132
+ if (currentObj.order === index) {
1133
+ return true;
1134
+ }
1135
+ }
1136
+ return false;
1137
+ }
1138
+
1139
+ private updImgRatioForActObj(): void {
1140
+ const parent: ImageEditor = this.parent;
1141
+ const destPoints: ActivePoint = {startX: parent.img.destLeft, startY: parent.img.destTop,
1142
+ width: parent.img.destWidth, height: parent.img.destHeight};
1143
+ this.straightenShapes();
1144
+ const { destLeft, destTop, destWidth, destHeight } = parent.img;
1145
+ const activePoint: ActivePoint = parent.activeObj.activePoint;
1146
+ parent.activeObj.imageRatio = { startX: ((activePoint.startX - destLeft) /
1147
+ destWidth), startY: ((activePoint.startY - destTop) / destHeight),
1148
+ endX: ((activePoint.endX - destLeft) / destWidth),
1149
+ endY: ((activePoint.endY - destTop) / destHeight),
1150
+ width: destWidth / activePoint.width, height: destHeight / activePoint.height };
1151
+ if (parent.activeObj.rotationCirclePointColl) {
1152
+ parent.activeObj.rotationCirclePointColl.ratioX = (parent.activeObj.rotationCirclePointColl.x -
1153
+ destLeft) / destWidth;
1154
+ parent.activeObj.rotationCirclePointColl.ratioY = (parent.activeObj.rotationCirclePointColl.y -
1155
+ destTop) / destHeight;
1156
+ }
1157
+ if (parent.activeObj.shape === 'path') {this.updatePathRatio(parent.activeObj); }
1158
+ else if (parent.activeObj.shape === 'arrow') {this.updateArrowRatio(parent.activeObj); }
1159
+ parent.img.destLeft = destPoints.startX; parent.img.destTop = destPoints.startY;
1160
+ parent.img.destWidth = destPoints.width; parent.img.destHeight = destPoints.height;
1161
+ }
1162
+
1163
+ private zoomObjColl(preventApply?: boolean): void {
1164
+ const parent: ImageEditor = this.parent;
1165
+ const destPoints: ActivePoint = {startX: parent.img.destLeft, startY: parent.img.destTop,
1166
+ width: parent.img.destWidth, height: parent.img.destHeight};
1167
+ this.straightenShapes();
1168
+ if (parent.objColl.length > 0) {
1169
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
1170
+ let currObj: SelectionPoint = parent.objColl[i as number];
1171
+ if (currObj.imageRatio) {
1172
+ currObj.activePoint.startX = (currObj.imageRatio.startX * parent.img.destWidth) + parent.img.destLeft;
1173
+ currObj.activePoint.startY = (currObj.imageRatio.startY * parent.img.destHeight) + parent.img.destTop;
1174
+ currObj.activePoint.endX = (currObj.imageRatio.endX * parent.img.destWidth) + parent.img.destLeft;
1175
+ currObj.activePoint.endY = (currObj.imageRatio.endY * parent.img.destHeight) + parent.img.destTop;
1176
+ }
1177
+ currObj = this.updateWidthHeight(currObj);
1178
+ if (currObj.shape === 'text') {
1179
+ this.updateFontSize(currObj);
1180
+ } else if (currObj.shape === 'line' || currObj.shape === 'arrow') {
1181
+ currObj.pointColl = this.getLinePoints(currObj.activePoint.startX, currObj.activePoint.startY, currObj.activePoint.endX,
1182
+ currObj.activePoint.endY);
1183
+ for (let n: number = 0, len: number = currObj.pointColl.length; n < len; n++) {
1184
+ currObj.pointColl[n as number].ratioX =
1185
+ (currObj.pointColl[n as number].x - parent.img.destLeft) / parent.img.destWidth;
1186
+ currObj.pointColl[n as number].ratioY =
1187
+ (currObj.pointColl[n as number].y - parent.img.destTop) / parent.img.destHeight;
1188
+ }
1189
+ if (currObj.shape === 'arrow') {
1190
+ this.updateArrowSize(currObj);
1191
+ }
1192
+ if (parent.transform.straighten !== 0 && (currObj.shape === 'line' || currObj.shape === 'arrow')) {
1193
+ this.straightenShapePoints(currObj);
1194
+ }
1195
+ } else if (currObj.shape === 'path') {
1196
+ for (let l: number = 0, len: number = currObj.pointColl.length; l < len; l++) {
1197
+ currObj.pointColl[l as number].x = (currObj.pointColl[l as number].ratioX * parent.img.destWidth) +
1198
+ parent.img.destLeft;
1199
+ currObj.pointColl[l as number].y = (currObj.pointColl[l as number].ratioY * parent.img.destHeight) +
1200
+ parent.img.destTop;
1201
+ }
1202
+ this.updatePathRatio(currObj);
1203
+ if (parent.transform.straighten !== 0) {
1204
+ this.straightenPath(currObj);
1205
+ }
1206
+ }
1207
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value: {actPoint: currObj.activePoint,
1208
+ obj: currObj}});
1209
+ if (currObj.shape !== 'line' && currObj.shape !== 'arrow' && currObj.shape !== 'path' && currObj.rotatedAngle !== 0) {
1210
+ this.setPointCollForShapeRotation(currObj);
1211
+ currObj.rotationCirclePoint.x =
1212
+ (currObj.rotationCirclePoint.ratioX * parent.img.destWidth) + parent.img.destLeft;
1213
+ currObj.rotationCirclePoint.y =
1214
+ (currObj.rotationCirclePoint.ratioY * parent.img.destHeight) + parent.img.destTop;
1215
+ if (currObj.rotationCirclePointColl) {
1216
+ currObj.rotationCirclePointColl.x =
1217
+ (currObj.rotationCirclePointColl.ratioX * parent.img.destWidth) + parent.img.destLeft;
1218
+ currObj.rotationCirclePointColl.y =
1219
+ (currObj.rotationCirclePointColl.ratioY * parent.img.destHeight) + parent.img.destTop;
1220
+ }
1221
+ }
1222
+ }
1223
+ if (isNullOrUndefined(preventApply)) {
1224
+ const temp: string = this.lowerContext.filter; this.lowerContext.filter = 'none';
1225
+ this.iterateObjColl();
1226
+ this.lowerContext.filter = temp;
1227
+ }
1228
+ }
1229
+ parent.img.destLeft = destPoints.startX; parent.img.destTop = destPoints.startY;
1230
+ parent.img.destWidth = destPoints.width; parent.img.destHeight = destPoints.height;
1231
+ }
1232
+
1233
+ private straightenPath(obj: SelectionPoint): void {
1234
+ let point: Point;
1235
+ for (let j: number = 0, len: number = obj.pointColl.length; j < len; j++) {
1236
+ point = this.straightenPoints(obj.pointColl[j as number].x, obj.pointColl[j as number].y);
1237
+ obj.pointColl[j as number].x = point.x;
1238
+ obj.pointColl[j as number].y = point.y;
1239
+ }
1240
+ }
1241
+
1242
+ private straightenFHD(): void {
1243
+ const parent: ImageEditor = this.parent;
1244
+ for (let i: number = 0, fLen: number = parent.freehandCounter; i < fLen; i++) {
1245
+ parent.points = extend([], parent.pointColl[i as number].points, []) as Point[];
1246
+ const len: number = parent.points.length; let point: Point;
1247
+ for (let l: number = 0; l < len; l++) {
1248
+ point = this.straightenPoints(parent.points[l as number].x, parent.points[l as number].y);
1249
+ parent.points[l as number].x = point.x; parent.points[l as number].y = point.y;
1250
+ }
1251
+ }
1252
+ const selPointCollObj: Object = {selPointColl: null };
1253
+ parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false, value: {obj: selPointCollObj }});
1254
+ for (let i: number = 0, fLen: number = parent.freehandCounter; i < fLen; i++) {
1255
+ if (selPointCollObj['selPointColl'][i as number] && selPointCollObj['selPointColl'][i as number].points) {
1256
+ const len: number = selPointCollObj['selPointColl'][i as number].points.length; let point: Point;
1257
+ for (let l: number = 0; l < len; l++) {
1258
+ point = this.straightenPoints(selPointCollObj['selPointColl'][i as number].points[l as number].x,
1259
+ selPointCollObj['selPointColl'][i as number].points[l as number].y);
1260
+ selPointCollObj['selPointColl'][i as number].points[l as number].x = point.x;
1261
+ selPointCollObj['selPointColl'][i as number].points[l as number].y = point.y;
1262
+ }
1263
+ }
1264
+ }
1265
+ const straightenObj: Object = { straightenPoint: null };
1266
+ parent.notify('freehand-draw', { prop: 'getStraightenPoint', onPropertyChange: false, value: {obj: straightenObj }});
1267
+ if (straightenObj['straightenPoint']['x'] && straightenObj['straightenPoint']['y']) {
1268
+ const obj: Object = {angle: 0 };
1269
+ parent.notify('freehand-draw', { prop: 'getStraightenPointAngle', onPropertyChange: false, value: {obj: obj }});
1270
+ const angle: number = (((parent.transform.straighten === 360 ? 0 : parent.transform.straighten) - obj['angle']) * (Math.PI / 180));
1271
+ const point: Point = this.straightenPoints(straightenObj['straightenPoint']['x'], straightenObj['straightenPoint']['y'], angle);
1272
+ if (angle === 0) {
1273
+ point.x = straightenObj['straightenPoint']['x']; point.y = straightenObj['straightenPoint']['y'];
1274
+ }
1275
+ parent.notify('freehand-draw', { prop: 'setStraightenPoint', onPropertyChange: false, value: {x: point.x, y: point.y }});
1276
+ }
1277
+ }
1278
+
1279
+ private straightenPoints(x: number, y: number, angle?: number): Point {
1280
+ const parent: ImageEditor = this.parent;
1281
+ const center: Point = {x: parent.img.destLeft + (parent.img.destWidth / 2), y: parent.img.destTop + (parent.img.destHeight / 2)};
1282
+ angle = angle ? angle : ((parent.transform.straighten) * (Math.PI / 180));
1283
+ const point: Point = { x: Math.cos(angle) * (x - center.x) - Math.sin(angle) * (y - center.y) + center.x,
1284
+ y: Math.sin(angle) * (x - center.x) + Math.cos(angle) * (y - center.y) + center.y };
1285
+ return point;
1286
+ }
1287
+
1288
+ private straightenShapes(): void {
1289
+ const parent: ImageEditor = this.parent;
1290
+ const { destLeft, destTop, destWidth, destHeight } = parent.img;
1291
+ const straightenObj: Object = {bool: parent.isStraightening };
1292
+ if (!straightenObj['bool'] || parent.transform.straighten === 0) {
1293
+ return;
1294
+ }
1295
+ parent.notify('draw', {prop: 'updateImgCanvasPoints'});
1296
+ const object: Object = {points: null };
1297
+ parent.notify('draw', {prop: 'getImageCanvasPoints', value: {obj: object }});
1298
+ const center: Point = {x: destLeft + (destWidth / 2), y: destTop + (destHeight / 2)};
1299
+ const angle: number = -((parent.transform.straighten) * (Math.PI / 180));
1300
+ const p1: Point = { x: Math.cos(angle) * (object['points'][0]['x'] - center.x) - Math.sin(angle) *
1301
+ (object['points'][0]['y'] - center.y) + center.x,
1302
+ y: Math.sin(angle) * (object['points'][0]['x'] - center.x) + Math.cos(angle) *
1303
+ (object['points'][0]['y'] - center.y) + center.y };
1304
+ const p2: Point = { x: Math.cos(angle) * (object['points'][1]['x'] - center.x) - Math.sin(angle) *
1305
+ (object['points'][1]['y'] - center.y) + center.x,
1306
+ y: Math.sin(angle) * (object['points'][1]['x'] - center.x) + Math.cos(angle) * (object['points'][1]['y']
1307
+ - center.y) + center.y };
1308
+ const p3: Point = { x: Math.cos(angle) * (object['points'][2]['x'] - center.x) - Math.sin(angle) *
1309
+ (object['points'][2]['y'] - center.y) + center.x,
1310
+ y: Math.sin(angle) * (object['points'][2]['x'] - center.x) + Math.cos(angle) * (object['points'][2]['y']
1311
+ - center.y) + center.y };
1312
+ parent.img.destWidth = p2.x - p1.x; parent.img.destHeight = p3.y - p2.y;
1313
+ parent.img.destLeft = p1.x; parent.img.destTop = p1.y;
1314
+ }
1315
+
1316
+ private straightenShapePoints(obj: SelectionPoint, isReverse?: boolean): void {
1317
+ const parent: ImageEditor = this.parent;
1318
+ const { destLeft, destTop, destWidth, destHeight } = parent.img;
1319
+ const straightenObj: Object = {bool: parent.isStraightening };
1320
+ if (!straightenObj['bool']) {
1321
+ return;
1322
+ }
1323
+ if (obj.shape === 'line' || obj.shape === 'arrow') {
1324
+ obj.activePoint.width = obj.activePoint.endX > obj.activePoint.startX ? obj.activePoint.endX -
1325
+ obj.activePoint.startX : obj.activePoint.startX - obj.activePoint.endX;
1326
+ obj.activePoint.height = obj.activePoint.endY > obj.activePoint.startY ? obj.activePoint.endY -
1327
+ obj.activePoint.startY : obj.activePoint.startY - obj.activePoint.endY;
1328
+ const center: Point = {x: destLeft + (destWidth / 2), y: destTop + (destHeight / 2)};
1329
+ const angle: number = (isReverse ? -parent.transform.straighten : parent.transform.straighten) * (Math.PI / 180);
1330
+ const start: Point = { x: Math.cos(angle) * (obj.activePoint.startX - center.x) - Math.sin(angle) *
1331
+ (obj.activePoint.startY - center.y) + center.x, y: Math.sin(angle) * (obj.activePoint.startX - center.x) + Math.cos(angle)
1332
+ * (obj.activePoint.startY - center.y) + center.y };
1333
+ const end: Point = { x: Math.cos(angle) * (obj.activePoint.endX - center.x) -
1334
+ Math.sin(angle) * (obj.activePoint.endY - center.y) + center.x, y: Math.sin(angle) * (obj.activePoint.endX - center.x) +
1335
+ Math.cos(angle) * (obj.activePoint.endY - center.y) + center.y };
1336
+ obj.activePoint.startX = start.x; obj.activePoint.startY = start.y;
1337
+ obj.activePoint.endX = end.x; obj.activePoint.endY = end.y;
1338
+ obj.activePoint.width = obj.activePoint.endX > obj.activePoint.startX ? obj.activePoint.endX -
1339
+ obj.activePoint.startX : obj.activePoint.startX - obj.activePoint.endX;
1340
+ obj.activePoint.height = obj.activePoint.endY > obj.activePoint.startY ? obj.activePoint.endY -
1341
+ obj.activePoint.startY : obj.activePoint.startY - obj.activePoint.endY;
1342
+ parent.notify('selection', { prop: 'adjustActObjForLineArrow', onPropertyChange: false, value: {obj: obj }});
1343
+ }
1344
+ }
1345
+
1346
+ private redrawObj(degree?: number | string): void {
1347
+ const parent: ImageEditor = this.parent;
1348
+ let isShape: boolean = false;
1349
+ if (parent.objColl.length > 0) {
1350
+ if (degree === 'horizontal' || degree === 'vertical' || degree === 'Horizontal' || degree === 'Vertical' ||
1351
+ degree === 'horizontalVertical' || degree === 'verticalHorizontal') {
1352
+ this.updateCurrentActiveObjPoint((degree as string).toLowerCase());
1353
+ } else if (typeof(degree) === 'number') {
1354
+ this.updateCurrentActiveObjPoint(degree); const tempFilter: string = this.lowerContext.filter;
1355
+ this.lowerContext.filter = 'brightness(' + 1 + ') ' + 'contrast(' + 100 + '%) ' + 'hue-rotate(' + 0 + 'deg) ' +
1356
+ 'saturate(' + 100 + '%) ' + 'opacity(' + 1 + ') ' + 'blur(' + 0 + 'px) ' + 'sepia(0%) ' + 'grayscale(0%) ' + 'invert(0%)';
1357
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
1358
+ const splitWords: string[] = parent.objColl[i as number].shape.split('-');
1359
+ if (splitWords[0] !== 'crop') {
1360
+ this.apply(parent.objColl[i as number].shape, parent.objColl[i as number]);
1361
+ isShape = true;
1362
+ }
1363
+ }
1364
+ if (isShape) {
1365
+ parent.notify('draw', {prop: 'applyFrame', value: {ctx: this.lowerContext, frame: parent.frameObj.type, preventImg: true}});
1366
+ }
1367
+ this.lowerContext.filter = tempFilter;
1368
+ }
1369
+ }
1370
+ }
1371
+
1372
+ private updateCurrentActiveObjPoint(degree: number | string): void {
1373
+ const parent: ImageEditor = this.parent;
1374
+ let currActObjIndex: number; const { destLeft, destTop, destWidth, destHeight } = parent.img;
1375
+ for (let index: number = 0, len: number = parent.objColl.length; index < len; index++) {
1376
+ const currObj: SelectionPoint = parent.objColl[index as number];
1377
+ if (parent.activeObj.shape === currObj.shape &&
1378
+ parent.activeObj.activePoint.startX === currObj.activePoint.startX &&
1379
+ parent.activeObj.activePoint.startY === currObj.activePoint.startY &&
1380
+ parent.activeObj.activePoint.endX === currObj.activePoint.endX &&
1381
+ parent.activeObj.activePoint.endY === currObj.activePoint.endY &&
1382
+ parent.activeObj.currIndex === currObj.currIndex) {
1383
+ currActObjIndex = index;
1384
+ break;
1385
+ }
1386
+ }
1387
+ if (degree === 'horizontal' || degree === 'vertical' || degree === 'Horizontal' || degree === 'Vertical' ||
1388
+ degree === 'horizontalvertical' || degree === 'verticalhorizontal') {
1389
+ if (degree === 'horizontal' || degree === 'Horizontal') {
1390
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
1391
+ const currObj: SelectionPoint = parent.objColl[i as number];
1392
+ if (currObj.shapeFlip !== parent.transform.currFlipState) {
1393
+ if (currObj.activePoint.startX <= destLeft + (destWidth / 2)) {
1394
+ currObj.activePoint.endX = (destLeft + destWidth) - (currObj.activePoint.startX - destLeft);
1395
+ currObj.activePoint.startX = currObj.activePoint.endX - currObj.activePoint.width;
1396
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value: {actPoint:
1397
+ currObj.activePoint, obj: currObj}});
1398
+ } else if (currObj.activePoint.startX >= destLeft + (destWidth / 2)) {
1399
+ currObj.activePoint.startX = destLeft + (destLeft + destWidth - currObj.activePoint.endX);
1400
+ currObj.activePoint.endX = currObj.activePoint.startX + currObj.activePoint.width;
1401
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value:
1402
+ {actPoint: currObj.activePoint, obj: currObj}});
1403
+ }
1404
+ if (currObj.shape === 'line' || currObj.shape === 'arrow' || currObj.shape === 'path') {
1405
+ this.flipLineArrowObj(currObj, 'horizontal');
1406
+ } else if (currObj.rotatedAngle !== 0) {
1407
+ currObj.rotatedAngle = currObj.rotatedAngle + (Math.PI - currObj.rotatedAngle) * 2;
1408
+ if (currObj.rotationCirclePointColl.x <= destLeft + (destWidth / 2)) {
1409
+ currObj.rotationCirclePointColl.x = (destLeft + destWidth) -
1410
+ (currObj.rotationCirclePointColl.x - destLeft);
1411
+ } else if (currObj.rotationCirclePointColl.x >= destLeft + (destWidth / 2)) {
1412
+ currObj.rotationCirclePointColl.x = destLeft +
1413
+ (destLeft + destWidth - currObj.rotationCirclePointColl.x);
1414
+ }
1415
+ currObj.rotationCirclePointColl.ratioX =
1416
+ (currObj.rotationCirclePointColl.x - destLeft) / destWidth;
1417
+ }
1418
+ currObj.shapeFlip = parent.transform.currFlipState;
1419
+ currObj.imageRatio = {startX: ((currObj.activePoint.startX - destLeft) / destWidth),
1420
+ startY: ((currObj.activePoint.startY - destTop) / destHeight),
1421
+ endX: ((currObj.activePoint.endX - destLeft) / destWidth),
1422
+ endY: ((currObj.activePoint.endY - destTop) / destHeight),
1423
+ width: destWidth / currObj.activePoint.width,
1424
+ height: destHeight / currObj.activePoint.height };
1425
+ }
1426
+ }
1427
+ }
1428
+ else if (degree === 'vertical' || degree === 'Vertical') {
1429
+ for (let i: number = 0; i < parent.objColl.length; i++) {
1430
+ const currObj: SelectionPoint = parent.objColl[i as number];
1431
+ if (currObj.shapeFlip !== parent.transform.currFlipState) {
1432
+ if (currObj.activePoint.startY <= destTop + (destHeight / 2)) {
1433
+ currObj.activePoint.endY = (destTop + destHeight) - (currObj.activePoint.startY - destTop);
1434
+ currObj.activePoint.startY = currObj.activePoint.endY - currObj.activePoint.height;
1435
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value: {actPoint: currObj.activePoint,
1436
+ obj: currObj}});
1437
+ } else if (currObj.activePoint.startY >= parent.lowerCanvas.height / 2) {
1438
+ currObj.activePoint.startY = destTop + (destTop + destHeight - currObj.activePoint.endY);
1439
+ currObj.activePoint.endY = currObj.activePoint.startY + currObj.activePoint.height;
1440
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value: {actPoint: currObj.activePoint,
1441
+ obj: currObj}});
1442
+ }
1443
+ if (currObj.shape === 'line' || currObj.shape === 'arrow' ||
1444
+ currObj.shape === 'path') {
1445
+ this.flipLineArrowObj(currObj, 'vertical');
1446
+ } else if (currObj.rotatedAngle !== 0) {
1447
+ currObj.rotatedAngle = -currObj.rotatedAngle;
1448
+ if (currObj.rotationCirclePointColl.y <= destTop + (destHeight / 2)) {
1449
+ currObj.rotationCirclePointColl.y = (destTop + destHeight) - (currObj.rotationCirclePointColl.y - destTop);
1450
+ } else if (currObj.rotationCirclePointColl.y >= destTop +
1451
+ (destHeight / 2)) {
1452
+ currObj.rotationCirclePointColl.y = destTop + (destTop + destHeight - currObj.rotationCirclePointColl.y);
1453
+ }
1454
+ currObj.rotationCirclePointColl.ratioY =
1455
+ (currObj.rotationCirclePointColl.y - destTop) / destHeight;
1456
+ }
1457
+ currObj.shapeFlip = parent.transform.currFlipState;
1458
+ currObj.imageRatio = {startX: ((currObj.activePoint.startX - destLeft) / destWidth),
1459
+ startY: ((currObj.activePoint.startY - destTop) / destHeight),
1460
+ endX: ((currObj.activePoint.endX - destLeft) / destWidth),
1461
+ endY: ((currObj.activePoint.endY - destTop) / destHeight),
1462
+ width: destWidth / currObj.activePoint.width,
1463
+ height: destHeight / currObj.activePoint.height };
1464
+ }
1465
+ }
1466
+ }
1467
+ else if (degree === 'verticalhorizontal' || degree === 'horizontalvertical') {
1468
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
1469
+ const currObj: SelectionPoint = parent.objColl[i as number];
1470
+ if (currObj.shapeFlip !== parent.transform.currFlipState) {
1471
+ if (currObj.activePoint.startX <= destLeft + (destWidth / 2)) {
1472
+ currObj.activePoint.endX = (destLeft + destWidth) - (currObj.activePoint.startX -
1473
+ destLeft);
1474
+ currObj.activePoint.startX = currObj.activePoint.endX - currObj.activePoint.width;
1475
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value:
1476
+ {actPoint: currObj.activePoint, obj: currObj}});
1477
+ } else if (currObj.activePoint.startX >= destLeft + (destWidth / 2)) {
1478
+ currObj.activePoint.startX = destLeft + (destLeft +
1479
+ destWidth - currObj.activePoint.endX);
1480
+ currObj.activePoint.endX = currObj.activePoint.startX + currObj.activePoint.width;
1481
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value: {actPoint:
1482
+ currObj.activePoint, obj: currObj}});
1483
+ }
1484
+ if (currObj.activePoint.startY <= destTop + (destHeight / 2)) {
1485
+ currObj.activePoint.endY = (destTop + destHeight) -
1486
+ (currObj.activePoint.startY - destTop);
1487
+ currObj.activePoint.startY = currObj.activePoint.endY -
1488
+ currObj.activePoint.height;
1489
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value: {actPoint:
1490
+ currObj.activePoint, obj: currObj}});
1491
+ } else if (currObj.activePoint.startY >= parent.lowerCanvas.height / 2) {
1492
+ currObj.activePoint.startY = destTop + (destTop +
1493
+ destHeight - currObj.activePoint.endY);
1494
+ currObj.activePoint.endY = currObj.activePoint.startY +
1495
+ currObj.activePoint.height;
1496
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value:
1497
+ {actPoint: currObj.activePoint, obj: currObj}});
1498
+ }
1499
+ if (currObj.shape === 'line' || currObj.shape === 'arrow' || currObj.shape === 'path') {
1500
+ this.flipLineArrowObj(currObj, degree);
1501
+ }
1502
+ currObj.shapeFlip = parent.transform.currFlipState;
1503
+ currObj.imageRatio = {startX: ((currObj.activePoint.startX - destLeft) / destWidth),
1504
+ startY: ((currObj.activePoint.startY - destTop) / destHeight),
1505
+ endX: ((currObj.activePoint.endX - destLeft) / destWidth),
1506
+ endY: ((currObj.activePoint.endY - destTop) / destHeight),
1507
+ width: destWidth / currObj.activePoint.width,
1508
+ height: destHeight / currObj.activePoint.height };
1509
+ }
1510
+ }
1511
+ }
1512
+ if (currActObjIndex !== undefined) {
1513
+ parent.activeObj = extend({}, parent.objColl[currActObjIndex as number], {}, true) as SelectionPoint;
1514
+ }
1515
+ }
1516
+ else if (degree === 90) {
1517
+ this.rotateObjColl();
1518
+ }
1519
+ else if (degree === -90) {
1520
+ for (let i: number = 0; i < 3; i++) {
1521
+ this.rotateObjColl();
1522
+ }
1523
+ } else if (typeof(degree) === 'number') {
1524
+ if (degree > 0) {this.rotateObjColl(); }
1525
+ else {
1526
+ for (let i: number = 0; i < 3; i++) {
1527
+ this.rotateObjColl();
1528
+ }
1529
+ }
1530
+ }
1531
+ }
1532
+
1533
+ private rotateObjColl(): void {
1534
+ const parent: ImageEditor = this.parent;
1535
+ const { destWidth, destHeight, destLeft, destTop } = parent.img;
1536
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
1537
+ let currObj: SelectionPoint = parent.objColl[i as number];
1538
+ const shape: string = currObj.shape;
1539
+ currObj.activePoint.startY = destTop + (destHeight * currObj.imageRatio.startX);
1540
+ currObj.activePoint.endY = destTop + (destHeight * currObj.imageRatio.endX);
1541
+ currObj.activePoint.startX = (destLeft + destWidth) - (destWidth * currObj.imageRatio.endY);
1542
+ currObj.activePoint.endX = (destLeft + destWidth) - (destWidth * currObj.imageRatio.startY);
1543
+ currObj = this.updateWidthHeight(parent.objColl[i as number]);
1544
+ this.updateFontSize(currObj);
1545
+ if (shape === 'line' || shape === 'arrow' || shape === 'path') {
1546
+ this.rotateLineArrowObj(currObj);
1547
+ if (shape === 'arrow') {
1548
+ this.updateArrowSize(currObj);
1549
+ }
1550
+ } else if (currObj.rotatedAngle !== 0) {
1551
+ currObj.rotationCirclePointColl.y = destTop + (destHeight * currObj.rotationCirclePointColl.ratioX);
1552
+ currObj.rotationCirclePointColl.x = (destLeft + destWidth) -
1553
+ (destWidth * currObj.rotationCirclePointColl.ratioY);
1554
+ currObj.rotationCirclePointColl.ratioX = (currObj.rotationCirclePointColl.x - destLeft) / destWidth;
1555
+ currObj.rotationCirclePointColl.ratioY = (currObj.rotationCirclePointColl.y - destTop) / destHeight;
1556
+ }
1557
+ }
1558
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
1559
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value: {actPoint:
1560
+ parent.objColl[i as number].activePoint, obj: parent.objColl[i as number]}});
1561
+ }
1562
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
1563
+ const currObj: SelectionPoint = parent.objColl[i as number];
1564
+ currObj.imageRatio = {startX: ((currObj.activePoint.startX - destLeft) / destWidth),
1565
+ startY: ((currObj.activePoint.startY - destTop) / destHeight),
1566
+ endX: ((currObj.activePoint.endX - destLeft) / destWidth),
1567
+ endY: ((currObj.activePoint.endY - destTop) / destHeight),
1568
+ width: destWidth / currObj.activePoint.width,
1569
+ height: destHeight / currObj.activePoint.height };
1570
+ }
1571
+ }
1572
+
1573
+ private rotateLineArrowObj(obj: SelectionPoint): void {
1574
+ if (isNullOrUndefined(obj.pointColl)) {
1575
+ return;
1576
+ }
1577
+ const parent: ImageEditor = this.parent;
1578
+ const { destWidth, destHeight, destLeft, destTop } = parent.img;
1579
+ if (obj.pointColl.length > 0) {
1580
+ for (let n: number = 0; n < obj.pointColl.length; n++) {
1581
+ obj.pointColl[n as number].y = destTop + (destHeight * obj.pointColl[n as number].ratioX);
1582
+ obj.pointColl[n as number].x = (destLeft + destWidth) - (destWidth *
1583
+ obj.pointColl[n as number].ratioY);
1584
+ }
1585
+ for (let n: number = 0; n < obj.pointColl.length; n++) {
1586
+ obj.pointColl[n as number].ratioX = (obj.pointColl[n as number].x - destLeft) / destWidth;
1587
+ obj.pointColl[n as number].ratioY = (obj.pointColl[n as number].y - destTop) / destHeight;
1588
+ }
1589
+ let prevPoint: Point;
1590
+ if (isNullOrUndefined(obj.pointColl[obj.pointColl.length - 2])) {prevPoint = {x: 0, y: 0 }; }
1591
+ else {prevPoint = {x: obj.pointColl[obj.pointColl.length - 2].x, y: obj.pointColl[obj.pointColl.length - 2].y }; }
1592
+ const diffX: number = obj.pointColl[obj.pointColl.length - 1].x - prevPoint.x;
1593
+ const diffY: number = obj.pointColl[obj.pointColl.length - 1].y - prevPoint.y;
1594
+ obj.activePoint.startX = obj.pointColl[0].x; obj.activePoint.startY = obj.pointColl[0].y;
1595
+ obj.activePoint.endX = obj.pointColl[obj.pointColl.length - 1].x + (diffX / 2);
1596
+ obj.activePoint.endY = obj.pointColl[obj.pointColl.length - 1].y + (diffY / 2);
1597
+ obj = this.updateWidthHeight(obj);
1598
+ }
1599
+ }
1600
+
1601
+ private flipLineArrowObj(obj: SelectionPoint, value: string): void {
1602
+ value = value.toLowerCase();
1603
+ if (isNullOrUndefined(obj.pointColl)) {return; }
1604
+ if (value === 'horizontal') {this.lineArrowHorizontalFlip(obj); }
1605
+ else if (value === 'vertical') {this.lineArrowVerticalFlip(obj); }
1606
+ else {this.lineArrowHorizontalFlip(obj); obj.shapeFlip = ''; this.lineArrowVerticalFlip(obj); }
1607
+ obj.activePoint.startX = obj.pointColl[0].x; obj.activePoint.startY = obj.pointColl[0].y;
1608
+ obj.activePoint.endX = obj.pointColl[obj.pointColl.length - 1].x;
1609
+ obj.activePoint.endY = obj.pointColl[obj.pointColl.length - 1].y;
1610
+ if (obj.activePoint.startX > obj.activePoint.endX) {
1611
+ let temp: number = obj.activePoint.startX; obj.activePoint.startX = obj.activePoint.endX;
1612
+ obj.activePoint.endX = temp; temp = obj.activePoint.startY;
1613
+ obj.activePoint.startY = obj.activePoint.endY; obj.activePoint.endY = temp;
1614
+ }
1615
+ }
1616
+
1617
+ private lineArrowHorizontalFlip(obj: SelectionPoint): void {
1618
+ const parent: ImageEditor = this.parent;
1619
+ const { destWidth, destHeight, destLeft, destTop } = parent.img;
1620
+ if (obj.shapeFlip !== parent.transform.currFlipState) {
1621
+ for (let l: number = 0, len: number = obj.pointColl.length; l < len; l++) {
1622
+ const currPoint: Point = obj.pointColl[l as number];
1623
+ if (currPoint.x <= destLeft + (destWidth / 2)) {
1624
+ currPoint.x = (destLeft + destWidth) - (currPoint.x - destLeft);
1625
+ } else if (currPoint.x >= destLeft + (destWidth / 2)) {
1626
+ currPoint.x = destLeft + (destLeft + destWidth - currPoint.x);
1627
+ }
1628
+ currPoint.ratioX = (currPoint.x - destLeft) / destWidth;
1629
+ currPoint.ratioY = (currPoint.y - destTop) / destHeight;
1630
+ }
1631
+ if (obj.shape === 'arrow') {
1632
+ const value: string = obj.start; obj.start = obj.end; obj.end = value;
1633
+ }
1634
+ obj.shapeFlip = parent.transform.currFlipState;
1635
+ }
1636
+ }
1637
+
1638
+ private lineArrowVerticalFlip(obj: SelectionPoint): void {
1639
+ const parent: ImageEditor = this.parent;
1640
+ const { destWidth, destHeight, destLeft, destTop } = parent.img;
1641
+ if (obj.shapeFlip !== parent.transform.currFlipState) {
1642
+ for (let l: number = 0, len: number = obj.pointColl.length; l < len; l++) {
1643
+ const currPoint: Point = obj.pointColl[l as number];
1644
+ if (currPoint.y <= destTop + (destHeight / 2)) {
1645
+ currPoint.y = (destTop + destHeight) - (currPoint.y - destTop);
1646
+ } else if (currPoint.y >= destTop + (destHeight / 2)) {
1647
+ currPoint.y = destTop + (destTop + destHeight - currPoint.y);
1648
+ }
1649
+ currPoint.ratioX = (currPoint.x - destLeft) / destWidth;
1650
+ currPoint.ratioY = (currPoint.y - destTop) / destHeight;
1651
+ }
1652
+ obj.shapeFlip = parent.transform.currFlipState;
1653
+ }
1654
+ }
1655
+
1656
+ private getRotDegOfShape(obj: SelectionPoint, value?: boolean): number {
1657
+ const parent: ImageEditor = this.parent;
1658
+ let degree: number;
1659
+ if (obj.shapeDegree === 0) {degree = this.parent.transform.degree; }
1660
+ else {degree = this.parent.transform.degree - obj.shapeDegree; }
1661
+ if (degree < 0) {degree = 360 + degree; }
1662
+ const transformObj: Object = {bool: false };
1663
+ parent.notify('selection', { prop: 'getTransformedShape', onPropertyChange: false, value: {obj: transformObj}});
1664
+ if (transformObj['bool'] && !value && parent.activeObj.rotateFlipColl) {
1665
+ degree = 0;
1666
+ for (let i: number = 0; i < parent.activeObj.rotateFlipColl.length; i++) {
1667
+ if (typeof(parent.activeObj.rotateFlipColl[i as number]) === 'number') {
1668
+ degree += (parent.activeObj.rotateFlipColl[i as number]);
1669
+ }
1670
+ }
1671
+ }
1672
+ return degree;
1673
+ }
1674
+
1675
+ private renderTextArea(x: number, y: number, actObj: SelectionPoint): void {
1676
+ const parent: ImageEditor = this.parent;
1677
+ const shapeObj: Object = {shapeSettingsObj: {} as ShapeSettings };
1678
+ parent.notify('selection', { prop: 'updatePrevShapeSettings', onPropertyChange: false, value: {obj: shapeObj}});
1679
+ const shapeSettings: ShapeSettings = shapeObj['shapeSettingsObj'];
1680
+ const shapeChangingArgs: ShapeChangeEventArgs = {cancel: false, action: 'text-edit', previousShapeSettings: shapeSettings,
1681
+ currentShapeSettings: shapeSettings};
1682
+ parent.trigger('shapeChanging', shapeChangingArgs);
1683
+ this.updateShapeChangeEventArgs(shapeChangingArgs.currentShapeSettings, shapeChangingArgs.allowShapeOverflow);
1684
+ const degree: number = this.getRotDegOfShape(parent.activeObj);
1685
+ this.transformTextArea();
1686
+ parent.notify('toolbar', { prop: 'destroy-qa-toolbar', onPropertyChange: false});
1687
+ const zOrderElem: HTMLElement = parent.element.querySelector('#' + parent.element.id + '_zOrderBtn');
1688
+ const dupElem: HTMLElement = parent.element.querySelector('#' + parent.element.id + '_duplicate');
1689
+ const removeElem: HTMLElement = parent.element.querySelector('#' + parent.element.id + '_remove');
1690
+ const editTextElem: HTMLElement = parent.element.querySelector('#' + parent.element.id + '_editText');
1691
+ const shadowColor: string = actObj.strokeSettings.outlineColor;
1692
+ const outlineWidth: number = actObj.strokeSettings.outlineWidth;
1693
+ const shadows: string[] = [];
1694
+ if (zOrderElem) {zOrderElem.classList.add('e-overlay'); }
1695
+ if (dupElem) {dupElem.classList.add('e-overlay'); }
1696
+ if (removeElem) {removeElem.classList.add('e-overlay'); }
1697
+ if (editTextElem) {editTextElem.classList.add('e-overlay'); }
1698
+ if (actObj.strokeSettings.fillColor !== '') {
1699
+ parent.textArea.style.backgroundColor = actObj.strokeSettings.fillColor;
1700
+ } else {
1701
+ parent.textArea.style.backgroundColor = 'transparent';
1702
+ }
1703
+ parent.textArea.style.display = 'block'; parent.textArea.style.left = x + 'px';
1704
+ parent.textArea.style.top = y + 'px'; parent.textArea.style.fontFamily = actObj.textSettings.fontFamily;
1705
+ parent.textArea.style.fontSize = actObj.textSettings.fontSize + 'px';
1706
+ parent.textArea.style.color = actObj.strokeSettings.strokeColor;
1707
+ const fontSize: number = actObj.textSettings.fontSize;
1708
+ const baseWidth: number = Math.max(1, outlineWidth / 2);
1709
+ const adjustedOutlineWidth: number = baseWidth * (Math.floor((fontSize - 1) / 16) * 0.5 + 0.5);
1710
+ if (/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$|^[a-zA-Z]+$/.test(actObj.strokeSettings.outlineColor)) {
1711
+ for (let x: number = -adjustedOutlineWidth; x <= adjustedOutlineWidth; x++) {
1712
+ for (let y: number = -adjustedOutlineWidth; y <= adjustedOutlineWidth; y++) {
1713
+ if (x !== 0 || y !== 0) {
1714
+ shadows.push(`${x / 2}px ${y / 2}px 0 ${shadowColor}`);
1715
+ }
1716
+ }
1717
+ }
1718
+ parent.textArea.style.textShadow = shadows.join(', ');
1719
+ } else {
1720
+ parent.textArea.style.textShadow = null;
1721
+ }
1722
+ parent.textArea.style.fontWeight = actObj.textSettings.bold ? 'bold' : 'normal';
1723
+ parent.textArea.style.fontStyle = actObj.textSettings.italic ? 'italic' : 'normal';
1724
+ parent.textArea.style.textDecoration = (actObj.textSettings.underline && actObj.textSettings.strikethrough) ? 'underline line-through' :
1725
+ (actObj.textSettings.underline) ? 'underline' :
1726
+ (actObj.textSettings.strikethrough) ? 'line-through' : 'none';
1727
+ parent.textArea.style.border = '2px solid ' + parent.themeColl[parent.theme]['primaryColor'];
1728
+ parent.textArea.value = actObj.keyHistory; parent.textArea.style.overflow = 'hidden';
1729
+ parent.textArea.style.width = 'auto'; parent.textArea.style.height = 'auto';
1730
+ parent.textArea.focus();
1731
+ const { width, height } = actObj.activePoint;
1732
+ if (degree % 90 === 0 && degree % 180 !== 0 && degree !== 0) {
1733
+ parent.textArea.style.width = height + (height * 0.25) + 'px';
1734
+ parent.textArea.style.height = width + (width * 0.25) + 'px';
1735
+ } else {
1736
+ parent.textArea.style.width = width + (width * 0.25) + 'px';
1737
+ parent.textArea.style.height = height + (height * 0.25) + 'px';
1738
+ }
1739
+ this.setTextBoxWidth(); const obj: Object = {flipColl: null };
1740
+ parent.notify('transform', { prop: 'getFlipColl', onPropertyChange: false, value: {obj: obj }});
1741
+ if (obj['flipColl'].length <= 1) {this.setTextBoxHeight(); }
1742
+ if (parseFloat(parent.textArea.style.maxHeight) < parent.activeObj.textSettings.fontSize) {
1743
+ parent.textArea.style.maxHeight = parent.activeObj.textSettings.fontSize + 'px';
1744
+ }
1745
+ if (degree % 90 === 0 && degree % 180 !== 0) {
1746
+ if (parseFloat(parent.textArea.style.left) + parseFloat(parent.textArea.style.width) > parent.img.destTop +
1747
+ parent.img.destHeight) {this.alignTextAreaIntoCanvas(); }
1748
+ } else {
1749
+ if (parseFloat(parent.textArea.style.left) + parseFloat(parent.textArea.style.width) > parent.img.destLeft +
1750
+ parent.img.destWidth) {this.alignTextAreaIntoCanvas(); }
1751
+ }
1752
+ // Limit text area
1753
+ if (actObj.rotatedAngle !== 0) {
1754
+ let tempLeft: number = parseFloat(parent.textArea.style.left); let tempTop: number = parseFloat(parent.textArea.style.top);
1755
+ if (actObj.flipObjColl.length > 0) {
1756
+ const panObj: Object = {panRegion: '' };
1757
+ const { clientWidth, clientHeight } = parent.lowerCanvas;
1758
+ let center: Point = {x: 0, y: 0};
1759
+ parent.notify('crop', { prop: 'getCurrFlipState', onPropertyChange: false,
1760
+ value: {panObj: panObj }});
1761
+ if (panObj['panRegion'] !== '') {
1762
+ if (panObj['panRegion'] === 'horizontal') {
1763
+ center.x = clientWidth - (clientWidth / 2);
1764
+ tempLeft = (center.x - tempLeft) + center.x;
1765
+ } else if (panObj['panRegion'] === 'vertical') {
1766
+ center.y = clientHeight - (clientHeight / 2);
1767
+ tempTop = (center.y - tempTop) + center.y;
1768
+ } else {
1769
+ center = {x: clientWidth - (clientWidth / 2), y: clientHeight - (clientHeight / 2)};
1770
+ tempLeft = (center.x - tempLeft) + center.x;
1771
+ tempTop = (center.y - tempTop) + center.y;
1772
+ }
1773
+ }
1774
+ }
1775
+ let left: number = tempLeft + parseFloat(parent.textArea.style.width);
1776
+ const top: number = tempTop + parseFloat(parent.textArea.style.height);
1777
+ let width1: number = parseFloat(parent.textArea.style.width);
1778
+ const height1: number = parseFloat(parent.textArea.style.height);
1779
+ let center: Point = {x: left - (width1 / 2), y: top - (height1 / 2)};
1780
+ const cosAngle: number = Math.cos(actObj.rotatedAngle);
1781
+ const sinAngle: number = Math.sin(actObj.rotatedAngle);
1782
+ let p1: Point = { x: cosAngle * (left - center.x) - sinAngle * (top - center.y) + center.x,
1783
+ y: sinAngle * (left - center.x) + cosAngle * (top - center.y) + center.y };
1784
+ if (p1.x > parent.img.destLeft && p1.x < parent.img.destLeft + parent.img.destWidth &&
1785
+ // eslint-disable-next-line max-len
1786
+ p1.y > parent.img.destTop && p1.y + parseFloat(parent.textArea.style.fontSize) < parent.img.destTop + parent.img.destHeight) {
1787
+ // eslint-disable-next-line no-self-assign
1788
+ parent.textArea.style.width = parent.textArea.style.width;
1789
+ } else {
1790
+ let count: number = 0;
1791
+ const width2: number = parseFloat(parent.textArea.style.width);
1792
+ while (true) {
1793
+ count++;
1794
+ width1 -= 1;
1795
+ left = tempLeft + width1;
1796
+ center = {x: left - (width1 / 2), y: top - (height1 / 2)};
1797
+ p1 = { x: cosAngle * (left - center.x) - sinAngle * (top - center.y) + center.x,
1798
+ y: sinAngle * (left - center.x) + cosAngle * (top - center.y) + center.y };
1799
+ if ((p1.x > parent.img.destLeft && p1.x < parent.img.destLeft + parent.img.destWidth &&
1800
+ // eslint-disable-next-line max-len
1801
+ p1.y > parent.img.destTop && p1.y + parseFloat(parent.textArea.style.fontSize) < parent.img.destTop + parent.img.destHeight) ||
1802
+ count === width2) {
1803
+ parent.textArea.style.width = width1 + 'px';
1804
+ break;
1805
+ }
1806
+ }
1807
+ }
1808
+ }
1809
+ parent.notify('selection', { prop: 'clearUpperCanvas', onPropertyChange: false});
1810
+ }
1811
+
1812
+ private setTextBoxWidth(e?: KeyboardEvent): void {
1813
+ const parent: ImageEditor = this.parent;
1814
+ if (parent.activeObj.rotatedAngle !== 0) {
1815
+ parent.textArea.style.whiteSpace = 'nowrap';
1816
+ parent.textArea.style.textOverflow = 'ellipsis';
1817
+ parent.textArea.style.display = 'inline-block';
1818
+ return;
1819
+ } else {
1820
+ parent.textArea.style.whiteSpace = '';
1821
+ parent.textArea.style.textOverflow = '';
1822
+ if (parent.textArea.style.display === 'inline-block') {
1823
+ parent.textArea.style.display = 'block';
1824
+ }
1825
+ }
1826
+ const text: string = this.getMaxText(true);
1827
+ if (parent.textArea.style.display === 'block' || parent.textArea.style.display === 'inline-block') {this.updateFontStyles(true); }
1828
+ else {this.updateFontStyles(); }
1829
+ const textAreaWidth: number = (this.upperContext.measureText(text).width + (parseFloat(parent.textArea.style.fontSize) / 2));
1830
+ const letterWidth: number = e ? this.upperContext.measureText(String.fromCharCode(e.which)).width : 0;
1831
+ const actObj: SelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
1832
+ let flip: string = ''; const degree: number = this.getRotDegOfShape(actObj);
1833
+ if (actObj.shapeFlip !== parent.transform.currFlipState) {flip = ''; }
1834
+ else {flip = parent.transform.currFlipState; }
1835
+ if ((e && parseFloat(parent.textArea.style.width) < (textAreaWidth + letterWidth)) || isNullOrUndefined(e)) {
1836
+ if (degree === 0) {
1837
+ if (flip.toLowerCase() === 'horizontal') {
1838
+ if ((parseFloat(parent.textArea.style.left) - parent.img.destLeft) - textAreaWidth - letterWidth > 0) {
1839
+ parent.textArea.style.width = (textAreaWidth + letterWidth) + 'px';
1840
+ }
1841
+ } else if ((parent.img.destWidth - (parseFloat(parent.textArea.style.left) -
1842
+ parent.img.destLeft)) > (textAreaWidth + letterWidth)) {
1843
+ parent.textArea.style.width = (textAreaWidth + letterWidth) + 'px';
1844
+ }
1845
+ } else if (degree === 90) {
1846
+ if (flip.toLowerCase() === 'vertical') {
1847
+ if ((parseFloat(parent.textArea.style.top) - parent.img.destTop) - textAreaWidth - letterWidth > 0) {
1848
+ parent.textArea.style.width = (textAreaWidth + letterWidth) + 'px';
1849
+ }
1850
+ }
1851
+ else if ((parent.img.destHeight - (parseFloat(parent.textArea.style.top) -
1852
+ parent.img.destTop)) > (textAreaWidth + letterWidth)) {
1853
+ parent.textArea.style.width = (textAreaWidth + letterWidth) + 'px';
1854
+ }
1855
+ } else if (degree === 180) {
1856
+ const textAreaLeft: number = parseFloat(parent.textArea.style.left);
1857
+ const destLeft: number = parent.img.destLeft;
1858
+ if (flip.toLowerCase() === 'horizontal') {
1859
+ const remainingWidth: number = parent.img.destWidth - (textAreaLeft - destLeft);
1860
+ if (remainingWidth > textAreaWidth + letterWidth) {
1861
+ parent.textArea.style.width = (textAreaWidth + letterWidth) + 'px';
1862
+ }
1863
+ } else {
1864
+ const distanceToLeft: number = textAreaLeft - destLeft;
1865
+ if (distanceToLeft - textAreaWidth - letterWidth > 0) {
1866
+ parent.textArea.style.width = (textAreaWidth + letterWidth) + 'px';
1867
+ }
1868
+ }
1869
+ } else if (degree === 270) {
1870
+ const textAreaTop: number = parseFloat(parent.textArea.style.top);
1871
+ const destTop: number = parent.img.destTop;
1872
+ if (flip.toLowerCase() === 'vertical') {
1873
+ const remainingHeight: number = parent.img.destHeight - (textAreaTop - destTop);
1874
+ if (remainingHeight > textAreaWidth + letterWidth) {
1875
+ parent.textArea.style.width = (textAreaWidth + letterWidth) + 'px';
1876
+ }
1877
+ } else {
1878
+ const distanceToTop: number = textAreaTop - destTop;
1879
+ if (distanceToTop - textAreaWidth - letterWidth > 0) {
1880
+ parent.textArea.style.width = (textAreaWidth + letterWidth) + 'px';
1881
+ }
1882
+ }
1883
+ }
1884
+ }
1885
+ }
1886
+
1887
+ private setTextBoxHeight(): void {
1888
+ const parent: ImageEditor = this.parent; let textAreaTop: number;
1889
+ const actObj: SelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
1890
+ let flip: string = ''; const degree: number = this.getRotDegOfShape(actObj);
1891
+ if (actObj.textFlip === parent.transform.currFlipState) {
1892
+ flip = '';
1893
+ } else if (actObj.textFlip === '') {
1894
+ flip = parent.transform.currFlipState;
1895
+ } else {
1896
+ flip = actObj.textFlip;
1897
+ }
1898
+ switch (degree) {
1899
+ case 0:
1900
+ if (flip.toLowerCase() === 'vertical') {
1901
+ parent.textArea.style.maxHeight = (parent.img.destHeight - (parent.img.destHeight -
1902
+ parseFloat(parent.textArea.style.top))) + 'px';
1903
+ } else {
1904
+ textAreaTop = parseFloat(parent.textArea.style.top) - parent.img.destTop;
1905
+ parent.textArea.style.maxHeight = (parent.img.destHeight - textAreaTop) + 'px';
1906
+ }
1907
+ break;
1908
+ case 90:
1909
+ if (flip.toLowerCase() === 'horizontal') {
1910
+ parent.textArea.style.maxHeight = (parent.img.destWidth - (parseFloat(parent.textArea.style.left) -
1911
+ parent.img.destLeft)) + 'px';
1912
+ } else {
1913
+ parent.textArea.style.maxHeight = (parseFloat(parent.textArea.style.left) - parent.img.destLeft) + 'px';
1914
+ }
1915
+ break;
1916
+ case 180:
1917
+ if (flip.toLowerCase() === 'vertical') {
1918
+ textAreaTop = parseFloat(parent.textArea.style.top) - parent.img.destTop;
1919
+ parent.textArea.style.maxHeight = (parent.img.destHeight - textAreaTop) + 'px';
1920
+ } else {
1921
+ parent.textArea.style.maxHeight = (parseFloat(parent.textArea.style.top) - parent.img.destTop) + 'px';
1922
+ }
1923
+ break;
1924
+ case 270:
1925
+ if (flip.toLowerCase() === 'horizontal') {
1926
+ parent.textArea.style.maxHeight = (parseFloat(parent.textArea.style.left) - parent.img.destLeft) + 'px';
1927
+ } else {
1928
+ parent.textArea.style.maxHeight = parent.img.destWidth - (parseFloat(parent.textArea.style.left)
1929
+ - parent.img.destLeft) + 'px';
1930
+ }
1931
+ break;
1932
+ }
1933
+ }
1934
+
1935
+ private updatePathRatio(obj: SelectionPoint): void {
1936
+ const parent: ImageEditor = this.parent;
1937
+ for (let i: number = 0, len: number = obj.pointColl.length; i < len; i++) {
1938
+ const currPoint: Point = obj.pointColl[i as number];
1939
+ currPoint.ratioX = (currPoint.x - parent.img.destLeft) / parent.img.destWidth;
1940
+ currPoint.ratioY = (currPoint.y - parent.img.destTop) / parent.img.destHeight;
1941
+ }
1942
+ }
1943
+
1944
+ private stopPathDrawing(e: MouseEvent & TouchEvent, isApply: boolean): void {
1945
+ const parent: ImageEditor = this.parent;
1946
+ if (parent.activeObj.shape === 'path') {
1947
+ const obj: Object = {shape: null };
1948
+ parent.notify('selection', { prop: 'getCurrentDrawingShape', value: {obj: obj }});
1949
+ if (obj['shape'] === 'path') {
1950
+ const prevCropObj: CurrentObject = extend({}, parent.cropObj, {}, true) as CurrentObject;
1951
+ const object: Object = {currObj: {} as CurrentObject };
1952
+ parent.notify('filter', { prop: 'getCurrentObj', onPropertyChange: false, value: {object: object }});
1953
+ const prevObj: CurrentObject = object['currObj'];
1954
+ prevObj.objColl = extend([], parent.objColl, [], true) as SelectionPoint[];
1955
+ prevObj.pointColl = extend([], parent.pointColl, [], true) as Point[];
1956
+ prevObj.afterCropActions = extend([], parent.afterCropActions, [], true) as string[];
1957
+ const selPointCollObj: Object = {selPointColl: null };
1958
+ parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false,
1959
+ value: {obj: selPointCollObj }});
1960
+ prevObj.selPointColl = extend([], selPointCollObj['selPointColl'], [], true) as Point[];
1961
+ parent.notify('selection', { prop: 'setCurrentDrawingShape', value: {value: '' }});
1962
+ parent.currObjType.isDragging = false;
1963
+ if (e && e.type !== 'touchstart' && isNullOrUndefined(isApply)) {parent.activeObj.pointColl.pop(); }
1964
+ this.updatePathRatio(parent.activeObj);
1965
+ if (isNullOrUndefined(parent.activeObj.imageRatio)) {
1966
+ parent.notify('shape', { prop: 'updImgRatioForActObj', onPropertyChange: false});
1967
+ }
1968
+ parent.objColl.push(parent.activeObj);
1969
+ parent.notify('undo-redo', { prop: 'updateUndoRedoColl', onPropertyChange: false,
1970
+ value: {operation: 'shapeTransform', previousObj: prevObj, previousObjColl: prevObj.objColl,
1971
+ previousPointColl: prevObj.pointColl, previousSelPointColl: prevObj.selPointColl,
1972
+ previousCropObj: prevCropObj, previousText: null,
1973
+ currentText: null, previousFilter: null, isCircleCrop: null}});
1974
+ parent.objColl.pop();
1975
+ if (e) {
1976
+ parent.notify('selection', { prop: 'mouseUpEventHandler', value: {e: e }});
1977
+ this.lowerContext.clearRect(0, 0, parent.lowerCanvas.width, parent.lowerCanvas.height);
1978
+ parent.notify('draw', { prop: 'redrawImgWithObj', onPropertyChange: false});
1979
+ if (parent.objColl.length > 0) {
1980
+ const obj1: ActivePoint = parent.activeObj.activePoint;
1981
+ const obj2: ActivePoint = parent.objColl[parent.objColl.length - 1].activePoint;
1982
+ if (Math.floor(obj1.startX) === Math.floor(obj2.startX) &&
1983
+ Math.floor(obj1.startY) === Math.floor(obj2.startY) &&
1984
+ Math.floor(obj1.endX) === Math.floor(obj2.endX) &&
1985
+ Math.floor(obj1.endY) === Math.floor(obj2.endY)) {
1986
+ this.refreshActiveObj();
1987
+ }
1988
+ }
1989
+ }
1990
+ parent.notify('draw', { prop: 'setNewPath', value: {bool: true }});
1991
+ if (parent.objColl[parent.objColl.length - 1]) {
1992
+ const shape: string = parent.drawingShape;
1993
+ parent.notify('selection', { prop: 'setCurrentDrawingShape', value: {value: '' }});
1994
+ parent.noRedact = true;
1995
+ parent.selectShape(parent.objColl[parent.objColl.length - 1].currIndex);
1996
+ parent.notify('selection', { prop: 'setCurrentDrawingShape', value: {value: 'path' }});
1997
+ parent.drawingShape = shape;
1998
+ }
1999
+ parent.notify('toolbar', { prop: 'renderQAT', onPropertyChange: false, value: {isPenEdit: null} });
2000
+ const obj: Object = {shapeSettingsObj: {} as ShapeSettings };
2001
+ parent.notify('selection', { prop: 'updatePrevShapeSettings', onPropertyChange: false, value: {obj: obj}});
2002
+ const shapeSettings: ShapeSettings = obj['shapeSettingsObj'];
2003
+ const shapeResizingArgs: ShapeChangeEventArgs = {cancel: false, action: 'draw-end', previousShapeSettings: shapeSettings};
2004
+ const shapeMovingArgs: ShapeChangeEventArgs = {cancel: false, action: 'move', previousShapeSettings: shapeSettings};
2005
+ parent.notify('selection', { prop: 'triggerShapeChange', onPropertyChange: false,
2006
+ value: {shapeResizingArgs: shapeResizingArgs, shapeMovingArgs: shapeMovingArgs, type: 'mouse-up'}});
2007
+ parent.notify('undo-redo', { prop: 'updateUndoRedoStack', onPropertyChange: false });
2008
+ }
2009
+ }
2010
+ }
2011
+
2012
+ private findTextTarget(e: MouseEvent & TouchEvent): void {
2013
+ const parent: ImageEditor = this.parent;
2014
+ if (!e) {return; }
2015
+ if (parent.activeObj.shape !== 'text') {
2016
+ if (parent.activeObj.shape === 'path') {
2017
+ this.stopPathDrawing(e, null);
2018
+ return;
2019
+ } else if (e.type === 'dblclick') {
2020
+ parent.notify('selection', { prop: 'setPanDown', onPropertyChange: false, value: {panDown: null }});
2021
+ const activeObj: SelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
2022
+ const objColl: SelectionPoint[] = extend([], parent.objColl, [], true) as SelectionPoint[];
2023
+ const obj: Object = {bool: null };
2024
+ parent.notify('selection', { prop: 'findTargetObj', onPropertyChange: false,
2025
+ value: {x: e.clientX, y: e.clientY, isCrop: false, obj: obj }});
2026
+ parent.objColl = objColl;
2027
+ if (!obj['bool'] || parent.activeObj.shape !== 'text') {
2028
+ parent.activeObj = extend({}, activeObj, {}, true) as SelectionPoint;
2029
+ return;
2030
+ }
2031
+ } else {
2032
+ return;
2033
+ }
2034
+ }
2035
+ let x: number; let y: number;
2036
+ if (e.type === 'dblclick') {x = e.clientX; y = e.clientY; }
2037
+ else if (e.type === 'touchstart') {
2038
+ x = e.touches[0].clientX; y = e.touches[0].clientY;
2039
+ parent.notify('selection', { prop: 'setTouchEndPoint', onPropertyChange: false,
2040
+ value: {x: e.touches[0].clientX, y: e.touches[0].clientY}});
2041
+ }
2042
+ parent.notify('toolbar', { prop: 'setPreventZoomBtn', onPropertyChange: false, value: {isPrevent: true }});
2043
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'text',
2044
+ isApplyBtn: null, isCropping: null, isZooming: null, cType: null}});
2045
+ parent.notify('toolbar', { prop: 'setPreventZoomBtn', onPropertyChange: false, value: {isPrevent: false }});
2046
+ parent.notify('toolbar', { prop: 'update-toolbar-items', onPropertyChange: false});
2047
+ if (!isNullOrUndefined(x) && !isNullOrUndefined(y)) {
2048
+ const bbox: DOMRect = parent.lowerCanvas.getBoundingClientRect() as DOMRect;
2049
+ x -= bbox.left; y -= bbox.top; let flip: string = '';
2050
+ const degree: number = this.getRotDegOfShape(parent.activeObj);
2051
+ if (parent.activeObj.textFlip === '') {
2052
+ if (parent.activeObj.textFlip === parent.transform.currFlipState) {flip = ''; }
2053
+ else {flip = parent.transform.currFlipState; }
2054
+ } else {
2055
+ if (parent.activeObj.textFlip === parent.transform.currFlipState) {flip = ''; }
2056
+ else if (parent.transform.currFlipState === '') {flip = parent.activeObj.textFlip; }
2057
+ else {flip = parent.transform.currFlipState; }
2058
+ }
2059
+ let temp: SelectionPoint;
2060
+ if (parent.textArea.style.display === 'none') {
2061
+ temp = extend({}, parent.activeObj, {}, true) as SelectionPoint;
2062
+ for (let i: number = 0; i < parent.objColl.length; i++) {
2063
+ if (JSON.stringify(parent.activeObj) === JSON.stringify(parent.objColl[i as number])) {
2064
+ parent.objColl.splice(i, 1);
2065
+ }
2066
+ }
2067
+ this.refreshActiveObj();
2068
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
2069
+ this.lowerContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
2070
+ parent.notify('draw', { prop: 'redrawImgWithObj', onPropertyChange: false});
2071
+ parent.notify('draw', { prop: 'redrawDownScale' });
2072
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.lowerContext}});
2073
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.upperContext}});
2074
+ if ((parent.currSelectionPoint && parent.currSelectionPoint.shape === 'crop-circle') || parent.isCircleCrop) {
2075
+ parent.notify('crop', { prop: 'cropCircle', onPropertyChange: false,
2076
+ value: {context: this.lowerContext, isSave: null, isFlip: null}});
2077
+ }
2078
+ parent.activeObj = temp; this.updateFontStyles();
2079
+ const actObj: SelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
2080
+ const radius: number = actObj.topLeftCircle.radius;
2081
+ const { startX, startY, endX, endY, width, height } = actObj.activePoint;
2082
+ const center: Point = {x: startX + (width / 2), y: startY +
2083
+ (height / 2)};
2084
+ const cosAngle: number = Math.cos(actObj.rotatedAngle);
2085
+ const sinAngle: number = Math.sin(actObj.rotatedAngle);
2086
+ const p1: Point = { x: cosAngle * (startX - center.x) - sinAngle * (startY - center.y) + center.x,
2087
+ y: sinAngle * (startX - center.x) + cosAngle * (startY - center.y) + center.y };
2088
+ const p2: Point = { x: cosAngle * (endX - center.x) - sinAngle * (startY - center.y) + center.x,
2089
+ y: sinAngle * (endX - center.x) + cosAngle * (startY - center.y) + center.y };
2090
+ const p3: Point = { x: cosAngle * (startX - center.x) - sinAngle * (endY - center.y) + center.x,
2091
+ y: sinAngle * (startX - center.x) + cosAngle * (endY - center.y) + center.y };
2092
+ const p4: Point = { x: cosAngle * (endX - center.x) - sinAngle * (endY - center.y) + center.x,
2093
+ y: sinAngle * (endX - center.x) + cosAngle * (endY - center.y) + center.y };
2094
+ const obj: Object = {position: null, x: x, y: y, x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y,
2095
+ x3: p3.x, y3: p3.y, x4: p4.x, y4: p4.y };
2096
+ parent.notify('draw', { prop: 'checkPointPosition', onPropertyChange: false, value: {obj: obj }});
2097
+ if ((actObj.rotatedAngle !== 0 && (obj['position'] === 'inside' || obj['position'] === 'on')) ||
2098
+ (actObj.rotatedAngle === 0 && x >= (actObj.activePoint.startX - (radius * 2)) &&
2099
+ x <= (actObj.activePoint.endX + (radius * 2)) &&
2100
+ y >= (actObj.activePoint.startY - (radius * 2)) &&
2101
+ y <= (actObj.activePoint.endY + (radius * 2)))) {
2102
+ this.upperContext.clearRect(0, 0, parent.upperCanvas.width, parent.upperCanvas.height);
2103
+ if (actObj.flipObjColl.length === 4) {
2104
+ actObj.flipObjColl = []; flip = ''; actObj.shapeFlip = '';
2105
+ }
2106
+ if (flip === '' && actObj.flipObjColl.length > 1) {
2107
+ flip = actObj.flipObjColl[actObj.flipObjColl.length - 1];
2108
+ }
2109
+ if (actObj.flipObjColl.length <= 1) {
2110
+ const points: Point = this.setTextBoxPos(actObj, degree, flip, x, y);
2111
+ x = points.x; y = points.y;
2112
+ } else {
2113
+ const points: Point = this.setTextBoxPoints(actObj, degree, flip, x, y);
2114
+ x = points.x; y = points.y;
2115
+ }
2116
+ if (parent.activeObj.rotatedAngle !== 0) {
2117
+ let point: Point = this.getTextBoxPosition(parent.activeObj);
2118
+ x = point.x; y = point.y;
2119
+ point = this.setFlipState(x, y, parent.activeObj);
2120
+ x = point.x; y = point.y;
2121
+ }
2122
+ this.renderTextArea(x, y, actObj);
2123
+
2124
+ } else {this.applyActObj(); }
2125
+ }
2126
+ } else if ((parent.textArea.style.display === 'block' || parent.textArea.style.display === 'inline-block')
2127
+ && this.selectedText() !== '' && e.type === 'mousedown') {
2128
+ const temp: string = parent.textArea.value; parent.textArea.value += 'a'; parent.textArea.value = temp;
2129
+ } else if (parent.textArea.style.display === 'none') {
2130
+ parent.textArea.style.display = 'block';
2131
+ }
2132
+ }
2133
+
2134
+ private getTextBoxPosition(obj: SelectionPoint, object?: Object): Point {
2135
+ let point: Point = {x: 0, y: 0 };
2136
+ const { startX, startY, endX, endY, width, height } = obj.activePoint;
2137
+ const center: Point = {x: startX + (width / 2), y: startY + (height / 2)};
2138
+ const cosAngle: number = Math.cos(obj.rotatedAngle);
2139
+ const sinAngle: number = Math.sin(obj.rotatedAngle);
2140
+ const p1: Point = { x: cosAngle * (startX - center.x) - sinAngle * (startY - center.y) + center.x,
2141
+ y: sinAngle * (startX - center.x) + cosAngle * (startY - center.y) + center.y };
2142
+ const p2: Point = { x: cosAngle * (endX - center.x) - sinAngle * (startY - center.y) + center.x,
2143
+ y: sinAngle * (endX - center.x) + cosAngle * (startY - center.y) + center.y };
2144
+ const p3: Point = { x: cosAngle * (startX - center.x) - sinAngle * (endY - center.y) + center.x,
2145
+ y: sinAngle * (startX - center.x) + cosAngle * (endY - center.y) + center.y };
2146
+ const p4: Point = { x: cosAngle * (endX - center.x) - sinAngle * (endY - center.y) + center.x,
2147
+ y: sinAngle * (endX - center.x) + cosAngle * (endY - center.y) + center.y };
2148
+ const degree: number = this.getRotDegOfShape(obj);
2149
+ if (degree === 0 || degree === 360) {point = {x: p1.x, y: p1.y}; }
2150
+ else if (degree === 90 || degree === -270) {point = {x: p2.x, y: p2.y}; }
2151
+ else if (degree === 180 || degree === -180) {point = {x: p4.x, y: p4.y}; }
2152
+ else if (degree === 270 || degree === -90) {point = {x: p3.x, y: p3.y}; }
2153
+ if (object) {object['x'] = point.x; object['y'] = point.y; }
2154
+ return point;
2155
+ }
2156
+
2157
+ private setFlipState(x: number, y: number, obj: SelectionPoint, object?: Object): Point {
2158
+ const parent: ImageEditor = this.parent; const panObj: Object = {panRegion: '' };
2159
+ const { clientWidth, clientHeight } = parent.lowerCanvas;
2160
+ let center: Point = {x: 0, y: 0};
2161
+ parent.notify('crop', { prop: 'getCurrFlipState', onPropertyChange: false,
2162
+ value: {panObj: panObj }});
2163
+ if (panObj['panRegion'] !== '') {
2164
+ if (panObj['panRegion'] === 'horizontal') {
2165
+ center.x = clientWidth - (clientWidth / 2);
2166
+ x = (center.x - x) + center.x;
2167
+ } else if (panObj['panRegion'] === 'vertical') {
2168
+ center.y = clientHeight - (clientHeight / 2);
2169
+ y = (center.y - y) + center.y;
2170
+ } else {
2171
+ center = {x: clientWidth - (clientWidth / 2), y: clientHeight - (clientHeight / 2)};
2172
+ x = (center.x - x) + center.x;
2173
+ y = (center.y - y) + center.y;
2174
+ }
2175
+ }
2176
+ if (object) {object['x'] = x; object['y'] = y; }
2177
+ return {x: x, y: y};
2178
+ }
2179
+
2180
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2181
+ private fileChanged(e: any): void {
2182
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
2183
+ const filesData: FileList = (e.target as any).files[0];
2184
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
2185
+ const fileData: any = filesData;
2186
+ const fileExtension: string = fileData.name && fileData.name.split('.').pop().toLowerCase();
2187
+ if (fileExtension && ['jpg', 'jpeg', 'png', 'svg', 'webp', 'bmp'].indexOf(fileExtension) === -1) {
2188
+ this.refreshActiveObj();
2189
+ return;
2190
+ }
2191
+ // eslint-disable-next-line @typescript-eslint/tslint/config, @typescript-eslint/no-explicit-any
2192
+ const URL = window.URL; const url = URL.createObjectURL((e.target as any).files[0]);
2193
+ this.onLoadImgShape(null, null, null, null, url.toString(), true);
2194
+ (document.getElementById(this.parent.element.id + '_fileUpload') as HTMLInputElement).value = '';
2195
+ }
2196
+
2197
+ private onLoadImgShape(x: number, y: number, width: number, height: number, url: string | ImageData,
2198
+ isSelect?: boolean, degree?: number, isAspectRatio?: boolean, opacity?: number, isSelected?: boolean): void {
2199
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
2200
+ const proxy: Shape = this; const parent: ImageEditor = this.parent;
2201
+ if (typeof(url) === 'string') {this.shapeImg.src = url; }
2202
+ else {
2203
+ parent.inMemoryCanvas.width = (url as ImageData).width;
2204
+ parent.inMemoryCanvas.height = (url as ImageData).height;
2205
+ parent.inMemoryCanvas.getContext('2d').putImageData((url as ImageData), 0, 0);
2206
+ this.shapeImg.src = parent.inMemoryCanvas.toDataURL();
2207
+ }
2208
+ this.prevObjColl();
2209
+ parent.activeObj.shape = 'image';
2210
+ this.initShapeProps();
2211
+ this.shapeImg.onload = () => {
2212
+ proxy.upperContext.drawImage(proxy.shapeImg, 0, 0, proxy.shapeImg.width, proxy.shapeImg.height);
2213
+ proxy.updateImgCanvas(isSelect, x, y, width, height, degree, isAspectRatio, opacity, isSelected);
2214
+ };
2215
+ }
2216
+
2217
+ private updateImgCanvas(isSelect: boolean, x: number, y: number, width: number, height: number, degree: number,
2218
+ isAspectRatio: boolean, opacity: number, isSelected?: boolean): void {
2219
+ const parent: ImageEditor = this.parent;
2220
+ parent.activeObj.imageElement = this.shapeImg;
2221
+ parent.activeObj.imageCanvas = parent.createElement('canvas');
2222
+ let dimObj: Object = {width: 0, height: 0 };
2223
+ parent.notify('transform', { prop: 'calcMaxDimension', onPropertyChange: false,
2224
+ value: {width: this.shapeImg.width, height: this.shapeImg.height, obj: dimObj, isImgShape: null }});
2225
+ if (width && height) {
2226
+ if (isAspectRatio) {
2227
+ const obj: Object = {ratio: null };
2228
+ parent.notify('selection', { prop: 'findImageRatio', onPropertyChange: false,
2229
+ value: {width: this.shapeImg.width, height: this.shapeImg.height, obj: obj }});
2230
+ dimObj = this.resizeImage(width, obj['ratio']);
2231
+ } else {
2232
+ dimObj = {width: width, height: height };
2233
+ }
2234
+ }
2235
+ this.updateObj(dimObj, x, y);
2236
+ parent.notify('draw', { prop: 'downScaleImgCanvas', onPropertyChange: false,
2237
+ value: {ctx: parent.activeObj.imageCanvas.getContext('2d'), isImgAnnotation: true, isHFlip: null, isVFlip: null }});
2238
+ parent.notify('transform', { prop: 'calcMaxDimension', onPropertyChange: false,
2239
+ value: {width: this.shapeImg.width, height: this.shapeImg.height, obj: dimObj, isImgShape: true }});
2240
+ if (width && height) {
2241
+ if (isAspectRatio) {
2242
+ const obj: Object = {ratio: null };
2243
+ parent.notify('selection', { prop: 'findImageRatio', onPropertyChange: false,
2244
+ value: {width: this.shapeImg.width, height: this.shapeImg.height, obj: obj }});
2245
+ dimObj = this.resizeImage(width, obj['ratio']);
2246
+ } else {
2247
+ dimObj = {width: width, height: height };
2248
+ }
2249
+ }
2250
+ if (opacity !== null && opacity !== undefined) {parent.activeObj.opacity = opacity; }
2251
+ this.updateObj(dimObj, x, y);
2252
+ parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: 'duplicate' }});
2253
+ this.shapeImg = null;
2254
+ if (degree) {
2255
+ parent.activeObj.rotatedAngle = degree * (Math.PI / 180);
2256
+ parent.notify('selection', {prop: 'updPtCollForShpRot', onPropertyChange: false, value: {obj: parent.activeObj }});
2257
+ }
2258
+ const obj: Object = {shapeSettingsObj: {} as ShapeSettings };
2259
+ parent.notify('selection', { prop: 'updatePrevShapeSettings', onPropertyChange: false, value: {obj: obj}});
2260
+ const shapeSettings: ShapeSettings = obj['shapeSettingsObj'];
2261
+ const shapeChangingArgs: ShapeChangeEventArgs = {cancel: false, action: 'insert', previousShapeSettings: shapeSettings,
2262
+ currentShapeSettings: shapeSettings};
2263
+ parent.trigger('shapeChanging', shapeChangingArgs);
2264
+ parent.editCompleteArgs = shapeChangingArgs;
2265
+ isSelect = isSelect ? isSelect : isSelected;
2266
+ this.drawShapeImageEvent(shapeChangingArgs, isSelect);
2267
+ if (parent.isPublicMethod && !isSelected) {
2268
+ parent.notify('undo-redo', {prop: 'updateUndoRedo', onPropertyChange: false});
2269
+ } else if (!parent.isPublicMethod) {
2270
+ parent.notify('undo-redo', { prop: 'updateUndoRedoStack', onPropertyChange: false});
2271
+ }
2272
+ parent.isPublicMethod = false;
2273
+ }
2274
+
2275
+ private updateObj(dimObj: Object, x: number, y: number): void {
2276
+ const parent: ImageEditor = this.parent;
2277
+ parent.activeObj.activePoint.width = dimObj['width'];
2278
+ parent.activeObj.activePoint.height = dimObj['height'];
2279
+ parent.activeObj.activePoint.startX = x ? x : (parent.lowerCanvas.width / 2) - (dimObj['width'] / 2);
2280
+ parent.activeObj.activePoint.startY = y ? y : (parent.lowerCanvas.height / 2) - (dimObj['height'] / 2);
2281
+ parent.activeObj.activePoint.endX = parent.activeObj.activePoint.startX + dimObj['width'];
2282
+ parent.activeObj.activePoint.endY = parent.activeObj.activePoint.startY + dimObj['height'];
2283
+ }
2284
+
2285
+ private resizeImage(newWidth: number, aspectRatio: string): Object {
2286
+ const aspectRatioArray: string[] = aspectRatio.split(':');
2287
+ const aspectRatioWidth: number = parseInt(aspectRatioArray[0], 10);
2288
+ const aspectRatioHeight: number = parseInt(aspectRatioArray[1], 10);
2289
+ const newHeight: number = Math.round((newWidth * aspectRatioHeight) / aspectRatioWidth);
2290
+ return { width: newWidth, height: newHeight };
2291
+ }
2292
+
2293
+ private setTextBoxPos(actObj: SelectionPoint, degree: number, flip: string, x: number, y: number): Point {
2294
+ const point: Point = {x: x, y: y};
2295
+ const { startX, startY, endX, endY } = actObj.activePoint;
2296
+ flip = flip.toLowerCase();
2297
+ switch (degree) {
2298
+ case 0:
2299
+ if (flip === 'horizontal') {
2300
+ point.x = endX; point.y = startY;
2301
+ } else if (flip === 'vertical') {
2302
+ point.x = startX; point.y = endY;
2303
+ } else {
2304
+ point.x = startX; point.y = startY;
2305
+ }
2306
+ break;
2307
+ case 90:
2308
+ if (flip === 'horizontal') {
2309
+ point.x = startX; point.y = startY;
2310
+ } else if (flip === 'vertical') {
2311
+ point.x = endX; point.y = endY;
2312
+ } else {
2313
+ point.x = endX; point.y = startY;
2314
+ }
2315
+ break;
2316
+ case 180:
2317
+ if (flip === 'horizontal') {
2318
+ point.x = startX; point.y = endY;
2319
+ } else if (flip === 'vertical') {
2320
+ point.x = endX; point.y = startY;
2321
+ } else {
2322
+ point.x = endX; point.y = endY;
2323
+ }
2324
+ break;
2325
+ case 270:
2326
+ if (flip === 'horizontal') {
2327
+ point.x = endX; point.y = endY;
2328
+ } else if (flip === 'vertical') {
2329
+ point.x = startX; point.y = startY;
2330
+ } else {
2331
+ point.x = startX; point.y = endY;
2332
+ }
2333
+ break;
2334
+ }
2335
+ return point;
2336
+ }
2337
+
2338
+ private setTextBoxPoints(actObj: SelectionPoint, degree: number, flip: string, x: number, y: number): Point {
2339
+ const point: Point = {x: x, y: y};
2340
+ const { startX, startY, endX, endY } = actObj.activePoint;
2341
+ flip = flip.toLowerCase();
2342
+ switch (degree) {
2343
+ case 0:
2344
+ if (actObj.flipObjColl[0] && actObj.flipObjColl[0].toLowerCase() === 'horizontal') {
2345
+ if (flip === 'horizontal') {
2346
+ point.x = startX; point.y = startY;
2347
+ } else if (flip === 'vertical') {
2348
+ point.x = endX; point.y = endY;
2349
+ }
2350
+ } else {
2351
+ if (flip === 'horizontal') {
2352
+ point.x = endX; point.y = endY;
2353
+ } else if (flip === 'vertical') {
2354
+ point.x = endX; point.y = startY;
2355
+ }
2356
+ }
2357
+ break;
2358
+ case 90:
2359
+ if (actObj.flipObjColl[0] && actObj.flipObjColl[0].toLowerCase() === 'horizontal') {
2360
+ if (flip === 'horizontal') {
2361
+ point.x = endX; point.y = endY;
2362
+ } else if (flip === 'vertical') {
2363
+ point.x = startX; point.y = endY;
2364
+ }
2365
+ } else {
2366
+ if (flip === 'horizontal') {
2367
+ point.x = startX; point.y = endY;
2368
+ } else if (flip === 'vertical') {
2369
+ point.x = startX; point.y = startY;
2370
+ }
2371
+ }
2372
+ break;
2373
+ case 180:
2374
+ if (actObj.flipObjColl[0] && actObj.flipObjColl[0].toLowerCase() === 'horizontal') {
2375
+ if (flip === 'horizontal') {
2376
+ point.x = startX; point.y = startY;
2377
+ } else if (flip === 'vertical') {
2378
+ point.x = startX; point.y = startY;
2379
+ }
2380
+ } else {
2381
+ if (flip === 'horizontal') {
2382
+ point.x = startX; point.y = startY;
2383
+ } else if (flip === 'vertical') {
2384
+ point.x = startX; point.y = endY;
2385
+ }
2386
+ }
2387
+ break;
2388
+ case 270:
2389
+ if (actObj.flipObjColl[0] && actObj.flipObjColl[0].toLowerCase() === 'horizontal') {
2390
+ if (flip === 'horizontal') {
2391
+ point.x = startX; point.y = startY;
2392
+ } else if (flip === 'vertical') {
2393
+ point.x = endX; point.y = startY;
2394
+ }
2395
+ } else {
2396
+ if (flip === 'horizontal') {
2397
+ point.x = endX; point.y = startY;
2398
+ } else if (flip === 'vertical') {
2399
+ point.x = endX; point.y = endY;
2400
+ }
2401
+ }
2402
+ break;
2403
+ }
2404
+ return point;
2405
+ }
2406
+
2407
+ private selectedText(): string {
2408
+ const parent: ImageEditor = this.parent;
2409
+ const start: number = parent.textArea.selectionStart;
2410
+ const finish: number = parent.textArea.selectionEnd;
2411
+ return parent.textArea.value.substring(start, finish);
2412
+ }
2413
+
2414
+ private panObjColl(xDiff: number, yDiff: number, panRegion: string): void {
2415
+ const parent: ImageEditor = this.parent;
2416
+ if (parent.objColl.length > 0) {
2417
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
2418
+ let currObj: SelectionPoint = parent.objColl[i as number];
2419
+ if (panRegion === '') {
2420
+ currObj.activePoint.startX += xDiff;
2421
+ currObj.activePoint.endX += xDiff;
2422
+ if (currObj.rotationCirclePointColl) {
2423
+ currObj.rotationCirclePointColl.x += xDiff;
2424
+ }
2425
+ if (currObj.shape === 'path') {
2426
+ for (let l: number = 0, len: number = currObj.pointColl.length; l < len; l++) {
2427
+ currObj.pointColl[l as number].x += xDiff;
2428
+ }
2429
+ }
2430
+ currObj.activePoint.startY += yDiff;
2431
+ currObj.activePoint.endY += yDiff;
2432
+ if (currObj.rotationCirclePointColl) {
2433
+ currObj.rotationCirclePointColl.y += yDiff;
2434
+ }
2435
+ if (currObj.shape === 'path') {
2436
+ for (let l: number = 0; l < currObj.pointColl.length; l++) {
2437
+ currObj.pointColl[l as number].y += yDiff;
2438
+ }
2439
+ }
2440
+ }
2441
+ currObj = this.updateWidthHeight(currObj);
2442
+ parent.notify('draw', { prop: 'updateActiveObject', onPropertyChange: false, value:
2443
+ {actPoint: currObj.activePoint,
2444
+ obj: currObj}});
2445
+ if (currObj.shape === 'line' || currObj.shape === 'arrow') {
2446
+ currObj.pointColl = this.getLinePoints(currObj.activePoint.startX, currObj.activePoint.startY, currObj.activePoint.endX,
2447
+ currObj.activePoint.endY);
2448
+ for (let j: number = 0, len: number = currObj.pointColl.length; j < len; j++) {
2449
+ currObj.pointColl[j as number].ratioX =
2450
+ (currObj.pointColl[j as number].x - parent.img.destLeft) / parent.img.destWidth;
2451
+ currObj.pointColl[j as number].ratioY =
2452
+ (currObj.pointColl[j as number].y - parent.img.destTop) / parent.img.destHeight;
2453
+ }
2454
+ }
2455
+ this.refreshActiveObj();
2456
+ }
2457
+ const temp: string = this.lowerContext.filter; this.lowerContext.filter = 'none';
2458
+ this.iterateObjColl();
2459
+ this.lowerContext.filter = temp; this.refreshActiveObj();
2460
+ parent.notify('draw', {prop: 'applyFrame', value: {ctx: this.lowerContext, frame: parent.frameObj.type, preventImg: true}});
2461
+ }
2462
+ }
2463
+
2464
+ private updateFontStyles(isTextBox?: boolean): void {
2465
+ const parent: ImageEditor = this.parent;
2466
+ this.upperContext.strokeStyle = parent.activeObj.strokeSettings.strokeColor;
2467
+ this.upperContext.fillStyle = parent.activeObj.strokeSettings.strokeColor;
2468
+ let textStyle: string = '';
2469
+ if (parent.activeObj.textSettings.bold) {textStyle = 'bold '; }
2470
+ if (parent.activeObj.textSettings.italic) {textStyle = 'italic '; }
2471
+ if (parent.activeObj.textSettings.bold && parent.activeObj.textSettings.italic) {textStyle = 'italic bold '; }
2472
+ const fontSize: number = isTextBox ? parseFloat(parent.textArea.style.fontSize) : parent.activeObj.textSettings.fontSize;
2473
+ const fontFamily: string = (parent.textArea.style.display === 'block' || parent.textArea.style.display === 'inline-block') ?
2474
+ parent.textArea.style.fontFamily : parent.activeObj.textSettings.fontFamily;
2475
+ this.upperContext.font = textStyle + fontSize + 'px' + ' ' + fontFamily;
2476
+ }
2477
+
2478
+ private applyFontStyle(item: string): void {
2479
+ const parent: ImageEditor = this.parent;
2480
+ const obj: Object = {shapeSettingsObj: {} as ShapeSettings };
2481
+ parent.notify('selection', { prop: 'updatePrevShapeSettings', onPropertyChange: false, value: {obj: obj}});
2482
+ const shapeSettings: ShapeSettings = obj['shapeSettingsObj'];
2483
+ let isObjPushed: boolean = false;
2484
+ const collLength: number = parent.objColl.length;
2485
+ this.pushActItemIntoObj();
2486
+ if (collLength !== parent.objColl.length) {isObjPushed = true; }
2487
+ const objColl: SelectionPoint[] = extend([], parent.objColl, [], true) as SelectionPoint[];
2488
+ if (isObjPushed) {
2489
+ parent.objColl.pop();
2490
+ }
2491
+ if (parent.textArea.style.display === 'none') { this.updateFontRatio(parent.activeObj); }
2492
+ else { this.updateFontRatio(parent.activeObj, true); }
2493
+ switch (item) {
2494
+ case 'default':
2495
+ this.updateFontStyle(item, objColl, 'normal', 'normal', false, false);
2496
+ break;
2497
+ case 'bold':
2498
+ this.updateFontStyle(item, objColl, 'bold', 'normal', false, false);
2499
+ break;
2500
+ case 'italic':
2501
+ this.updateFontStyle(item, objColl, 'normal', 'italic', false, false);
2502
+ break;
2503
+ case 'bolditalic':
2504
+ this.updateFontStyle(item, objColl, 'bold', 'italic', false, false);
2505
+ break;
2506
+ case 'underline':
2507
+ this.updateFontStyle(item, objColl, 'normal', 'normal', true, false);
2508
+ break;
2509
+ case 'boldunderline':
2510
+ this.updateFontStyle(item, objColl, 'bold', 'normal', true, false);
2511
+ break;
2512
+ case 'italicunderline':
2513
+ this.updateFontStyle(item, objColl, 'normal', 'italic', true, false);
2514
+ break;
2515
+ case 'bolditalicunderline':
2516
+ this.updateFontStyle(item, objColl, 'bold', 'italic', true, false);
2517
+ break;
2518
+ case 'strikethrough':
2519
+ this.updateFontStyle(item, objColl, 'normal', 'normal', false, true);
2520
+ break;
2521
+ case 'boldstrikethrough':
2522
+ this.updateFontStyle(item, objColl, 'bold', 'normal', false, true);
2523
+ break;
2524
+ case 'italicstrikethrough':
2525
+ this.updateFontStyle(item, objColl, 'normal', 'italic', false, true);
2526
+ break;
2527
+ case 'underlinestrikethrough':
2528
+ this.updateFontStyle(item, objColl, 'normal', 'normal', true, true);
2529
+ break;
2530
+ case 'bolditalicstrikethrough':
2531
+ this.updateFontStyle(item, objColl, 'bold', 'italic', false, true);
2532
+ break;
2533
+ case 'boldunderlinestrikethrough':
2534
+ this.updateFontStyle(item, objColl, 'bold', 'normal', true, true);
2535
+ break;
2536
+ case 'italicunderlinestrikethrough':
2537
+ this.updateFontStyle(item, objColl, 'normal', 'italic', true, true);
2538
+ break;
2539
+ case 'bolditalicunderlinestrikethrough':
2540
+ this.updateFontStyle(item, objColl, 'bold', 'italic', true, true);
2541
+ break;
2542
+ }
2543
+ const shapeChangedArgs: ShapeChangeEventArgs = {action: 'font-style', currentShapeSettings: extend({}, shapeSettings, {}, true) as ShapeSettings};
2544
+ shapeChangedArgs.currentShapeSettings.fontStyle = this.getFontStyleArray(item);
2545
+ parent.trigger('shapeChange', shapeChangedArgs);
2546
+ parent.editCompleteArgs = shapeChangedArgs;
2547
+ }
2548
+
2549
+ private getFontStyleArray(item: string): string[] {
2550
+ const styleArray: string[] = [];
2551
+ const lowerItem: string = item.toLowerCase();
2552
+ if (lowerItem.indexOf('bold') > -1) {
2553
+ styleArray.push('bold');
2554
+ }
2555
+ if (lowerItem.indexOf('italic') > -1) {
2556
+ styleArray.push('italic');
2557
+ }
2558
+ if (lowerItem.indexOf('underline') > -1) {
2559
+ styleArray.push('underline');
2560
+ }
2561
+ if (lowerItem.indexOf('strikethrough') > -1) {
2562
+ styleArray.push('strikethrough');
2563
+ }
2564
+ return styleArray;
2565
+ }
2566
+
2567
+ private updateFontStyle(item: string, objColl: SelectionPoint[], fontWeight: string, fontStyle: string, underline: boolean,
2568
+ strikethrough: boolean): void {
2569
+ const parent: ImageEditor = this.parent;
2570
+ const style: CSSStyleDeclaration = parent.textArea.style;
2571
+ if (style.display === 'block' || style.display === 'inline-block') {
2572
+ if (fontWeight === 'bold') {style.fontWeight = 'bold'; }
2573
+ else {style.fontWeight = 'normal'; }
2574
+ if (fontStyle === 'italic') {style.fontStyle = 'italic'; }
2575
+ else {style.fontStyle = 'normal'; }
2576
+ if (underline && strikethrough) {
2577
+ style.textDecoration = 'underline line-through';
2578
+ }
2579
+ else if (strikethrough)
2580
+ {
2581
+ style.textDecoration = 'line-through';
2582
+ }
2583
+ else if (underline) {
2584
+ style.textDecoration = 'underline';
2585
+ }
2586
+ else {
2587
+ style.textDecoration = 'none';
2588
+ }
2589
+ const key: string = [
2590
+ style.fontWeight === 'bold' ? 'bold' : '',
2591
+ style.fontStyle === 'italic' ? 'italic' : '',
2592
+ typeof style.textDecoration === 'string' && style.textDecoration.indexOf('underline') > -1 ? 'underline' : '',
2593
+ typeof style.textDecoration === 'string' && style.textDecoration.indexOf('line-through') > -1 ? 'strikethrough' : ''
2594
+ ].filter(Boolean).join('');
2595
+ const valueMap: Record<string, string> = {
2596
+ '': 'default',
2597
+ bold: 'bold',
2598
+ italic: 'italic',
2599
+ underline: 'underline',
2600
+ strikethrough: 'strikethrough',
2601
+ bolditalic: 'bolditalic',
2602
+ boldunderline: 'boldunderline',
2603
+ boldstrikethrough: 'boldstrikethrough',
2604
+ italicunderline: 'italicunderline',
2605
+ italicstrikethrough: 'italicstrikethrough',
2606
+ underlinestrikethrough: 'underlinestrikethrough',
2607
+ bolditalicunderline: 'bolditalicunderline',
2608
+ bolditalicstrikethrough: 'bolditalicstrikethrough',
2609
+ boldunderlinestrikethrough: 'boldunderlinestrikethrough',
2610
+ italicunderlinestrikethrough: 'italicunderlinestrikethrough',
2611
+ bolditalicunderlinestrikethrough: 'bolditalicunderlinestrikethrough'
2612
+ };
2613
+ const value: string = key in valueMap ? valueMap[key as string] : 'default';
2614
+ const width: number = this.getTextAreaWidth(value); style.width = width + 'px';
2615
+ this.updateObjColl(item, objColl);
2616
+ } else {
2617
+ this.textSettings.bold = parent.activeObj.textSettings.bold = fontWeight === 'normal' ? false : true;
2618
+ this.textSettings.italic = parent.activeObj.textSettings.italic = fontStyle === 'normal' ? false : true;
2619
+ this.textSettings.underline = parent.activeObj.textSettings.underline = underline ? true : false;
2620
+ this.textSettings.strikethrough = parent.activeObj.textSettings.strikethrough = strikethrough ? true : false;
2621
+ if (parent.activeObj.activePoint.width !== 0 || parent.activeObj.activePoint.height !== 0) {
2622
+ this.redrawText();
2623
+ }
2624
+ parent.notify('undo-redo', { prop: 'updateUrObj', onPropertyChange: false, value: {objColl: objColl}});
2625
+ }
2626
+ }
2627
+
2628
+ private updateArrowRatio(obj: SelectionPoint): void {
2629
+ const parent: ImageEditor = this.parent;
2630
+ const object: Object = {arrowDimension: null };
2631
+ parent.notify('draw', { prop: 'getArrowDimension', onPropertyChange: false, value: {obj: object }});
2632
+ let length: number;
2633
+ if (Math.abs(obj.activePoint.width) > Math.abs(obj.activePoint.height)) {length = Math.abs(obj.activePoint.width); }
2634
+ else {length = Math.abs(obj.activePoint.height); }
2635
+ let dimension: string; const dimensions: string[] = ['bar', 'arrow', 'arrowSolid', 'circle', 'square'];
2636
+ for (dimension of dimensions) {
2637
+ const ratioX: number = length / object['arrowDimension'][dimension as string]['width'];
2638
+ const ratioY: number = length / object['arrowDimension'][dimension as string]['height'];
2639
+ object['arrowDimension'][dimension as string]['ratioX'] = ratioX;
2640
+ object['arrowDimension'][dimension as string]['ratioY'] = ratioY;
2641
+ }
2642
+ }
2643
+
2644
+ private updateArrowSize(obj: SelectionPoint): void {
2645
+ const object: Object = {arrowDimension: null };
2646
+ this.parent.notify('draw', { prop: 'getArrowDimension', onPropertyChange: false, value: {obj: object }});
2647
+ let length: number;
2648
+ if (Math.abs(obj.activePoint.width) > Math.abs(obj.activePoint.height)) {length = Math.abs(obj.activePoint.width); }
2649
+ else {length = Math.abs(obj.activePoint.height); }
2650
+ let dimension: string; const dimensions: string[] = ['bar', 'arrow', 'arrowSolid', 'circle', 'square'];
2651
+ for (dimension of dimensions) {
2652
+ const ratioX: number = object['arrowDimension'][dimension as string]['ratioX'];
2653
+ const ratioY: number = object['arrowDimension'][dimension as string]['ratioY'];
2654
+ object['arrowDimension'][dimension as string]['width'] = length / ratioX;
2655
+ object['arrowDimension'][dimension as string]['height'] = length / ratioY;
2656
+ }
2657
+ }
2658
+
2659
+ private updateFontRatio(obj: SelectionPoint, isTextArea?: boolean): void {
2660
+ const parent: ImageEditor = this.parent;
2661
+ const text: string = this.getMaxText(isTextArea);
2662
+ const width: number = this.upperContext.measureText(text).width +
2663
+ parent.activeObj.textSettings.fontSize * 0.5;
2664
+ const height: number = parent.activeObj.textSettings.fontSize;
2665
+ const degree: number = this.getRotDegOfShape(obj);
2666
+ if (isNullOrUndefined(isTextArea)) {
2667
+ if (degree === 0 || Math.abs(degree) === 180) {
2668
+ obj.textSettings.fontRatio = width / obj.textSettings.fontSize;
2669
+ } else {
2670
+ obj.textSettings.fontRatio = height / obj.textSettings.fontSize;
2671
+ }
2672
+ } else if (isTextArea) {
2673
+ const transformObj: Object = {bool: false };
2674
+ parent.notify('selection', { prop: 'getTransformedShape', onPropertyChange: false, value: {obj: transformObj}});
2675
+ if (!transformObj['bool'] || degree === 0 || Math.abs(degree) === 180) {
2676
+ obj.textSettings.fontRatio = width / parseFloat(parent.textArea.style.fontSize);
2677
+ } else {
2678
+ obj.textSettings.fontRatio = height / parseFloat(parent.textArea.style.fontSize);
2679
+ }
2680
+ }
2681
+ }
2682
+
2683
+ private updateFontSize(obj: SelectionPoint): void {
2684
+ const degree: number = this.getRotDegOfShape(obj, true);
2685
+ if (degree === 0 || Math.abs(degree) === 180) {
2686
+ obj.textSettings.fontSize = (obj.activePoint.width / obj.textSettings.fontRatio);
2687
+ } else {
2688
+ obj.textSettings.fontSize = (obj.activePoint.height / obj.textSettings.fontRatio);
2689
+ }
2690
+ }
2691
+
2692
+ private updateObjColl(item: string, objColl: SelectionPoint[]): void {
2693
+ const parent: ImageEditor = this.parent;
2694
+ const prevCropObj: CurrentObject = extend({}, parent.cropObj, {}, true) as CurrentObject;
2695
+ const object: Object = {currObj: {} as CurrentObject };
2696
+ parent.notify('filter', { prop: 'getCurrentObj', onPropertyChange: false, value: {object: object }});
2697
+ const prevObj: CurrentObject = object['currObj'];
2698
+ prevObj.objColl = objColl;
2699
+ prevObj.pointColl = extend([], parent.pointColl, [], true) as Point[];
2700
+ prevObj.afterCropActions = extend([], parent.afterCropActions, [], true) as string[];
2701
+ const selPointCollObj: Object = {selPointColl: null };
2702
+ parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false,
2703
+ value: {obj: selPointCollObj }});
2704
+ prevObj.selPointColl = extend([], selPointCollObj['selPointColl'], [], true) as Point[];
2705
+ const textSettings: TextSettings = parent.activeObj.textSettings;
2706
+ const tempBold: boolean = textSettings.bold;
2707
+ const tempItalic: boolean = textSettings.italic;
2708
+ const tempUnderline: boolean = textSettings.underline;
2709
+ const tempStrikethrough: boolean = textSettings.strikethrough;
2710
+ switch (item) {
2711
+ case 'default':
2712
+ textSettings.bold = false;
2713
+ textSettings.italic = false;
2714
+ textSettings.underline = false;
2715
+ textSettings.strikethrough = false;
2716
+ break;
2717
+ case 'bold':
2718
+ textSettings.bold = true;
2719
+ textSettings.italic = false;
2720
+ textSettings.underline = false;
2721
+ textSettings.strikethrough = false;
2722
+ break;
2723
+ case 'italic':
2724
+ textSettings.bold = false;
2725
+ textSettings.italic = true;
2726
+ textSettings.underline = false;
2727
+ textSettings.strikethrough = false;
2728
+ break;
2729
+ case 'bolditalic':
2730
+ textSettings.bold = true;
2731
+ textSettings.italic = true;
2732
+ textSettings.underline = false;
2733
+ textSettings.strikethrough = false;
2734
+ break;
2735
+ case 'underline':
2736
+ textSettings.bold = false;
2737
+ textSettings.italic = false;
2738
+ textSettings.underline = true;
2739
+ textSettings.strikethrough = false;
2740
+ break;
2741
+ case 'boldunderline':
2742
+ textSettings.bold = true;
2743
+ textSettings.italic = false;
2744
+ textSettings.underline = true;
2745
+ textSettings.strikethrough = false;
2746
+ break;
2747
+ case 'italicunderline':
2748
+ textSettings.bold = false;
2749
+ textSettings.italic = true;
2750
+ textSettings.underline = true;
2751
+ textSettings.strikethrough = false;
2752
+ break;
2753
+ case 'bolditalicunderline':
2754
+ textSettings.bold = true;
2755
+ textSettings.italic = true;
2756
+ textSettings.underline = true;
2757
+ textSettings.strikethrough = false;
2758
+ break;
2759
+ case 'strikethrough':
2760
+ textSettings.bold = false;
2761
+ textSettings.italic = false;
2762
+ textSettings.underline = false;
2763
+ textSettings.strikethrough = true;
2764
+ break;
2765
+ case 'boldstrikethrough':
2766
+ textSettings.bold = true;
2767
+ textSettings.italic = false;
2768
+ textSettings.underline = false;
2769
+ textSettings.strikethrough = true;
2770
+ break;
2771
+ case 'italicstrikethrough':
2772
+ textSettings.bold = false;
2773
+ textSettings.italic = true;
2774
+ textSettings.underline = false;
2775
+ textSettings.strikethrough = true;
2776
+ break;
2777
+ case 'underlinestrikethrough':
2778
+ textSettings.bold = false;
2779
+ textSettings.italic = false;
2780
+ textSettings.underline = true;
2781
+ textSettings.strikethrough = true;
2782
+ break;
2783
+ case 'bolditalicstrikethrough':
2784
+ textSettings.bold = true;
2785
+ textSettings.italic = true;
2786
+ textSettings.underline = false;
2787
+ textSettings.strikethrough = true;
2788
+ break;
2789
+ case 'boldunderlinestrikethrough':
2790
+ textSettings.bold = true;
2791
+ textSettings.italic = false;
2792
+ textSettings.underline = true;
2793
+ textSettings.strikethrough = true;
2794
+ break;
2795
+ case 'italicunderlinestrikethrough':
2796
+ textSettings.bold = false;
2797
+ textSettings.italic = true;
2798
+ textSettings.underline = true;
2799
+ textSettings.strikethrough = true;
2800
+ break;
2801
+ case 'bolditalicunderlinestrikethrough':
2802
+ textSettings.bold = true;
2803
+ textSettings.italic = true;
2804
+ textSettings.underline = true;
2805
+ textSettings.strikethrough = true;
2806
+ break;
2807
+ }
2808
+ parent.objColl.push(parent.activeObj);
2809
+ parent.notify('undo-redo', { prop: 'updateUndoRedoColl', onPropertyChange: false,
2810
+ value: {operation: 'textAreaCustomization', previousObj: prevObj, previousObjColl: prevObj.objColl,
2811
+ previousPointColl: prevObj.pointColl, previousSelPointColl: prevObj.selPointColl,
2812
+ previousCropObj: prevCropObj, previousText: null,
2813
+ currentText: null, previousFilter: null, isCircleCrop: null}});
2814
+ parent.objColl.pop();
2815
+ textSettings.bold = tempBold; textSettings.italic = tempItalic;
2816
+ textSettings.underline = tempUnderline; textSettings.strikethrough = tempStrikethrough;
2817
+ }
2818
+
2819
+ private pushActItemIntoObj(): void {
2820
+ const parent: ImageEditor = this.parent;
2821
+ if (parent.textArea.style.display === 'none') {
2822
+ if (parent.activeObj.activePoint.width !== 0 || parent.activeObj.activePoint.height !== 0) {
2823
+ parent.objColl.push(parent.activeObj);
2824
+ }
2825
+ } else {
2826
+ const temp: SelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
2827
+ parent.notify('selection', { prop: 'setTextBoxStylesToActObj', onPropertyChange: false });
2828
+ parent.objColl.push(parent.activeObj); parent.activeObj = temp;
2829
+ }
2830
+ }
2831
+
2832
+ private clearActObj(): void {
2833
+ const parent: ImageEditor = this.parent;
2834
+ if (parent.textArea.style.display === 'none') {
2835
+ this.refreshActiveObj(); this.applyActObj();
2836
+ this.refreshActiveObj(); parent.currObjType.isCustomCrop = false;
2837
+ }
2838
+ }
2839
+
2840
+ private refreshActiveObj(): void {
2841
+ const parent: ImageEditor = this.parent;
2842
+ parent.activeObj = {} as SelectionPoint;
2843
+ parent.activeObj.activePoint = {startX: 0, startY: 0, endX: 0, endY: 0, width: 0, height: 0};
2844
+ parent.activeObj.triangle = []; parent.activeObj.triangleRatio = []; parent.activeObj.order = null;
2845
+ parent.activeObj.flipObjColl = []; parent.activeObj.strokeSettings = this.strokeSettings;
2846
+ parent.activeObj.textSettings = this.textSettings; parent.activeObj.rotatedAngle = 0;
2847
+ parent.activeObj.opacity = 1;
2848
+ parent.activeObj.redactType = this.redactType;
2849
+ parent.activeObj.redactBlur = parent.tempRedactBlur;
2850
+ parent.activeObj.redactPixelate = parent.tempRedactPixel;
2851
+ }
2852
+
2853
+ private applyActObj(isMouseDown?: boolean): void {
2854
+ const parent: ImageEditor = this.parent;
2855
+ let isActObj: boolean = false;
2856
+ if (parent.activeObj.shape !== undefined && parent.activeObj.shape === 'text' && parent.activeObj.keyHistory === '') {
2857
+ this.refreshActiveObj();
2858
+ this.upperContext.clearRect(0, 0 , parent.upperCanvas.width, parent.upperCanvas.height);
2859
+ } else {
2860
+ let splitWords: string[]; let isCropSelection: boolean = false;
2861
+ if (parent.activeObj.shape !== undefined) {splitWords = parent.activeObj.shape.split('-'); }
2862
+ if (splitWords === undefined && parent.currObjType.isCustomCrop) {isCropSelection = true; }
2863
+ else if (splitWords !== undefined && splitWords[0] === 'crop') {isCropSelection = true; }
2864
+ if (parent.activeObj.shape && !isCropSelection && parent.activeObj.shape !== 'shape') {
2865
+ for (let i: number = 0; i < parent.objColl.length; i++) {
2866
+ if (JSON.stringify(parent.activeObj) === JSON.stringify(parent.objColl[i as number])) {
2867
+ isActObj = true;
2868
+ break;
2869
+ }
2870
+ }
2871
+ if (!isActObj) {
2872
+ if (isNullOrUndefined(parent.activeObj.currIndex)) {
2873
+ parent.activeObj.currIndex = this.getNewShapeId();
2874
+ }
2875
+ if (isNullOrUndefined(parent.activeObj.order)) {
2876
+ parent.activeObj.order = this.getNewOrder();
2877
+ }
2878
+ this.updImgRatioForActObj();
2879
+ const splitWords: string[] = parent.activeObj.currIndex.split('_');
2880
+ let tempObjColl: SelectionPoint[] = parent.objColl.splice(0, parseInt(splitWords[1], 10) - 1);
2881
+ tempObjColl.push(extend({}, parent.activeObj, {}, true) as SelectionPoint);
2882
+ for (let i: number = 0; i < parent.objColl.length; i++) {
2883
+ tempObjColl.push(parent.objColl[i as number]);
2884
+ }
2885
+ parent.objColl = tempObjColl;
2886
+ tempObjColl = []; this.refreshActiveObj();
2887
+ this.lowerContext.clearRect(0, 0, parent.lowerCanvas.width, parent.lowerCanvas.height);
2888
+ parent.notify('draw', { prop: 'redrawImgWithObj', onPropertyChange: false});
2889
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.lowerContext}});
2890
+ parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.upperContext}});
2891
+ parent.currObjType.shape = ''; this.refreshActiveObj();
2892
+ if (parent.isCircleCrop) {
2893
+ parent.notify('crop', { prop: 'cropCircle', onPropertyChange: false,
2894
+ value: {context: this.lowerContext, isSave: null, isFlip: null}});
2895
+ }
2896
+ parent.notify('toolbar', { prop: 'destroy-qa-toolbar', onPropertyChange: false});
2897
+ if (isNullOrUndefined(isMouseDown)) {
2898
+ parent.notify('undo-redo', {prop: 'updateCurrUrc', value: {type: 'ok' }});
2899
+ parent.notify('draw', { prop: 'setPrevActObj', onPropertyChange: false, value: { prevActObj: null }});
2900
+ }
2901
+ }
2902
+ }
2903
+ }
2904
+ }
2905
+
2906
+ private getNewShapeId(): string {
2907
+ const parent: ImageEditor = this.parent;
2908
+ let value: number = parent.objColl.length + 1;
2909
+ for (let i: number = 0; i < parent.objColl.length; i++) {
2910
+ if (parent.objColl[i as number].currIndex === 'shape_' + value) {
2911
+ value++; i = -1;
2912
+ }
2913
+ }
2914
+ return 'shape_' + value;
2915
+ }
2916
+
2917
+ private getNewOrder(): number {
2918
+ const parent: ImageEditor = this.parent;
2919
+ this.updateShapeColl();
2920
+ let value: number = parent.shapeColl.length + 1;
2921
+ for (let i: number = 0; i < parent.shapeColl.length; i++) {
2922
+ if (parent.shapeColl[i as number].order === value) {
2923
+ value++; i = -1;
2924
+ }
2925
+ }
2926
+ return value;
2927
+ }
2928
+
2929
+ private getHighestOrder(): number {
2930
+ const parent: ImageEditor = this.parent;
2931
+ this.updateShapeColl();
2932
+ let value: number = 0;
2933
+ for (let i: number = 0; i < parent.shapeColl.length; i++) {
2934
+ if (parent.shapeColl[i as number].order > value) {
2935
+ value = parent.shapeColl[i as number].order;
2936
+ }
2937
+ }
2938
+ return value;
2939
+ }
2940
+
2941
+ private getLowestOrder(): number {
2942
+ const parent: ImageEditor = this.parent;
2943
+ this.updateShapeColl();
2944
+ let value: number = 1;
2945
+ for (let i: number = 0; i < parent.shapeColl.length; i++) {
2946
+ if (parent.shapeColl[i as number].order < value) {
2947
+ value = parent.shapeColl[i as number].order;
2948
+ }
2949
+ }
2950
+ return value;
2951
+ }
2952
+
2953
+ private alignTextAreaIntoCanvas(): void {
2954
+ const parent: ImageEditor = this.parent; const letters: string = parent.textArea.value;
2955
+ parent.textArea.value = '';
2956
+ for (let i: number = 0, len: number = letters.length; i < len; i++) {
2957
+ parent.textArea.value += letters[i as number]; parent.textArea.style.height = 'auto';
2958
+ parent.textArea.style.height = parent.textArea.scrollHeight + 'px'; this.setTextBoxWidth();
2959
+ }
2960
+ }
2961
+
2962
+ private transformTextArea(): void {
2963
+ const parent: ImageEditor = this.parent;
2964
+ if (parent.activeObj.shape === 'text') {
2965
+ parent.textArea.style.transformOrigin = '0 0';
2966
+ const rotatedDegree: number = parent.activeObj.rotatedAngle * (180 / Math.PI);
2967
+ let scale: string = ''; let degree: number = this.getRotDegOfShape(parent.activeObj);
2968
+ if (parent.activeObj.flipObjColl.length > 0) {
2969
+ for (let i: number = 0; i < parent.activeObj.flipObjColl.length; i++) {
2970
+ if (degree !== 0 && degree % 90 === 0 && degree !== 180) {
2971
+ scale += parent.activeObj.flipObjColl[i as number].toLowerCase() === 'horizontal' ? 'scale(1, -1)' :
2972
+ 'scale(-1, 1)';
2973
+ } else {
2974
+ scale += parent.activeObj.flipObjColl[i as number].toLowerCase() === 'horizontal' ? 'scale(-1, 1)' :
2975
+ 'scale(1, -1)';
2976
+ }
2977
+ degree += rotatedDegree;
2978
+ if (parent.activeObj.flipObjColl[i as number].toLowerCase() === 'horizontal') {
2979
+ parent.textArea.style.transform = 'rotate(' + degree + 'deg)' + scale;
2980
+ } else if (parent.activeObj.flipObjColl[i as number].toLowerCase() === 'vertical') {
2981
+ parent.textArea.style.transform = 'rotate(' + degree + 'deg)' + scale;
2982
+ }
2983
+ }
2984
+ } else {
2985
+ degree += rotatedDegree; parent.textArea.style.transform = 'rotate(' + degree + 'deg)';
2986
+ }
2987
+ }
2988
+ }
2989
+
2990
+ private getTextAreaWidth(item: string): number {
2991
+ const parent: ImageEditor = this.parent;
2992
+ const textSettings: TextSettings = parent.activeObj.textSettings;
2993
+ const tempBold: boolean = textSettings.bold;
2994
+ const tempItalic: boolean = textSettings.italic;
2995
+ const tempUnderline: boolean = textSettings.underline;
2996
+ const tempStrikethrough: boolean = textSettings.strikethrough;
2997
+ switch (item) {
2998
+ case 'default':
2999
+ textSettings.bold = false;
3000
+ textSettings.italic = false;
3001
+ textSettings.underline = false;
3002
+ textSettings.strikethrough = false;
3003
+ break;
3004
+ case 'bold':
3005
+ textSettings.bold = true;
3006
+ textSettings.italic = false;
3007
+ textSettings.underline = false;
3008
+ textSettings.strikethrough = false;
3009
+ break;
3010
+ case 'italic':
3011
+ textSettings.bold = false;
3012
+ textSettings.italic = true;
3013
+ textSettings.underline = false;
3014
+ textSettings.strikethrough = false;
3015
+ break;
3016
+ case 'bolditalic':
3017
+ textSettings.bold = true;
3018
+ textSettings.italic = true;
3019
+ textSettings.underline = false;
3020
+ textSettings.strikethrough = false;
3021
+ break;
3022
+ case 'underline':
3023
+ textSettings.bold = false;
3024
+ textSettings.italic = false;
3025
+ textSettings.underline = true;
3026
+ textSettings.strikethrough = false;
3027
+ break;
3028
+ case 'boldunderline':
3029
+ textSettings.bold = true;
3030
+ textSettings.italic = false;
3031
+ textSettings.underline = true;
3032
+ textSettings.strikethrough = false;
3033
+ break;
3034
+ case 'italicunderline':
3035
+ textSettings.bold = false;
3036
+ textSettings.italic = true;
3037
+ textSettings.underline = true;
3038
+ textSettings.strikethrough = false;
3039
+ break;
3040
+ case 'bolditalicunderline':
3041
+ textSettings.bold = true;
3042
+ textSettings.italic = true;
3043
+ textSettings.underline = true;
3044
+ textSettings.strikethrough = false;
3045
+ break;
3046
+ case 'strikethrough':
3047
+ textSettings.bold = false;
3048
+ textSettings.italic = false;
3049
+ textSettings.underline = false;
3050
+ textSettings.strikethrough = true;
3051
+ break;
3052
+ case 'boldstrikethrough':
3053
+ textSettings.bold = true;
3054
+ textSettings.italic = false;
3055
+ textSettings.underline = false;
3056
+ textSettings.strikethrough = true;
3057
+ break;
3058
+ case 'italicstrikethrough':
3059
+ textSettings.bold = false;
3060
+ textSettings.italic = true;
3061
+ textSettings.underline = false;
3062
+ textSettings.strikethrough = true;
3063
+ break;
3064
+ case 'underlinestrikethrough':
3065
+ textSettings.bold = false;
3066
+ textSettings.italic = false;
3067
+ textSettings.underline = true;
3068
+ textSettings.strikethrough = true;
3069
+ break;
3070
+ case 'bolditalicstrikethrough':
3071
+ textSettings.bold = true;
3072
+ textSettings.italic = true;
3073
+ textSettings.underline = false;
3074
+ textSettings.strikethrough = true;
3075
+ break;
3076
+ case 'boldunderlinestrikethrough':
3077
+ textSettings.bold = true;
3078
+ textSettings.italic = false;
3079
+ textSettings.underline = true;
3080
+ textSettings.strikethrough = true;
3081
+ break;
3082
+ case 'italicunderlinestrikethrough':
3083
+ textSettings.bold = false;
3084
+ textSettings.italic = true;
3085
+ textSettings.underline = true;
3086
+ textSettings.strikethrough = true;
3087
+ break;
3088
+ case 'bolditalicunderlinestrikethrough':
3089
+ textSettings.bold = true;
3090
+ textSettings.italic = true;
3091
+ textSettings.underline = true;
3092
+ textSettings.strikethrough = true;
3093
+ break;
3094
+ }
3095
+ const isTextArea: boolean = parent.textArea.style.display === 'none' ? false : true;
3096
+ this.updateFontStyles(isTextArea); let width: number;
3097
+ if (!isTextArea) {
3098
+ width = this.upperContext.measureText(parent.activeObj.keyHistory).width +
3099
+ textSettings.fontSize * 0.5;
3100
+ } else {
3101
+ width = this.upperContext.measureText(parent.textArea.value).width +
3102
+ textSettings.fontSize * 0.5;
3103
+ }
3104
+ textSettings.bold = tempBold; textSettings.italic = tempItalic;
3105
+ textSettings.underline = tempUnderline; textSettings.strikethrough = tempStrikethrough;
3106
+ return width;
3107
+ }
3108
+
3109
+ private getRedactObjDetails(obj: SelectionPoint): RedactSettings {
3110
+ const parent: ImageEditor = this.parent;
3111
+ const redactDetails: RedactSettings = {} as RedactSettings; redactDetails.id = obj.currIndex;
3112
+ redactDetails.type = parent.toPascalCase(obj.redactType) as RedactType;
3113
+ redactDetails.startX = obj.activePoint.startX; redactDetails.startY = obj.activePoint.startY;
3114
+ redactDetails.width = obj.activePoint.width; redactDetails.height = obj.activePoint.height;
3115
+ switch (obj.redactType) {
3116
+ case 'blur':
3117
+ redactDetails.blurIntensity = obj.redactBlur;
3118
+ break;
3119
+ case 'pixelate':
3120
+ redactDetails.pixelSize = obj.redactPixelate;
3121
+ break;
3122
+ }
3123
+ return redactDetails;
3124
+ }
3125
+
3126
+ private getObjDetails(obj: SelectionPoint): ShapeSettings {
3127
+ const parent: ImageEditor = this.parent;
3128
+ const shapeDetails: ShapeSettings = {} as ShapeSettings; shapeDetails.id = obj.currIndex;
3129
+ shapeDetails.type = parent.toPascalCase(obj.shape) as ShapeType;
3130
+ shapeDetails.startX = obj.activePoint.startX; shapeDetails.startY = obj.activePoint.startY;
3131
+ shapeDetails.index = obj.order;
3132
+ const transformObj: Object = {coll: null };
3133
+ switch (obj.shape) {
3134
+ case 'rectangle':
3135
+ shapeDetails.width = obj.activePoint.width;
3136
+ shapeDetails.height = obj.activePoint.height;
3137
+ shapeDetails.strokeColor = obj.strokeSettings.strokeColor;
3138
+ shapeDetails.fillColor = obj.strokeSettings.fillColor;
3139
+ shapeDetails.strokeWidth = obj.strokeSettings.strokeWidth;
3140
+ shapeDetails.degree = obj.rotatedAngle * (180 / Math.PI);
3141
+ break;
3142
+ case 'ellipse':
3143
+ shapeDetails.radius = obj.activePoint.width / 2;
3144
+ shapeDetails.strokeColor = obj.strokeSettings.strokeColor;
3145
+ shapeDetails.fillColor = obj.strokeSettings.fillColor;
3146
+ shapeDetails.strokeWidth = obj.strokeSettings.strokeWidth;
3147
+ shapeDetails.radiusX = obj.activePoint.width / 2;
3148
+ shapeDetails.radiusY = obj.activePoint.height / 2;
3149
+ shapeDetails.degree = obj.rotatedAngle * (180 / Math.PI);
3150
+ break;
3151
+ case 'line':
3152
+ case 'arrow':
3153
+ shapeDetails.length = obj.activePoint.width;
3154
+ shapeDetails.strokeColor = obj.strokeSettings.strokeColor;
3155
+ shapeDetails.strokeWidth = obj.strokeSettings.strokeWidth;
3156
+ shapeDetails.endX = obj.activePoint.endX;
3157
+ shapeDetails.endY = obj.activePoint.endY;
3158
+ if (obj.shape === 'arrow') {
3159
+ const arrowObj: Object = {type: null };
3160
+ parent.notify('selection', {prop: 'getArrowType', onPropertyChange: false, value: {type: obj.start, obj: arrowObj}});
3161
+ shapeDetails.arrowHead = arrowObj['type'];
3162
+ parent.notify('selection', {prop: 'getArrowType', onPropertyChange: false, value: {type: obj.end, obj: arrowObj}});
3163
+ shapeDetails.arrowTail = arrowObj['type'];
3164
+ }
3165
+ break;
3166
+ case 'text':
3167
+ shapeDetails.text = obj.keyHistory;
3168
+ shapeDetails.fontSize = obj.textSettings.fontSize;
3169
+ shapeDetails.fontFamily = obj.textSettings.fontFamily;
3170
+ shapeDetails.color = obj.strokeSettings.strokeColor;
3171
+ shapeDetails.strokeColor = obj.strokeSettings.outlineColor;
3172
+ shapeDetails.fillColor = obj.strokeSettings.fillColor;
3173
+ shapeDetails.strokeWidth = obj.strokeSettings.outlineWidth;
3174
+ shapeDetails.fontStyle = [];
3175
+ if (obj.textSettings.bold) {shapeDetails.fontStyle.push('bold'); }
3176
+ if (obj.textSettings.italic) {shapeDetails.fontStyle.push('italic'); }
3177
+ if (obj.textSettings.underline) {shapeDetails.fontStyle.push('underline'); }
3178
+ if (obj.textSettings.strikethrough) {shapeDetails.fontStyle.push('strikethrough'); }
3179
+ shapeDetails.degree = obj.rotatedAngle * (180 / Math.PI);
3180
+ parent.notify('selection', {prop: 'updateTransColl', onPropertyChange: false, value: {obj: transformObj, object: obj}});
3181
+ shapeDetails.transformCollection = transformObj['coll'];
3182
+ break;
3183
+ case 'path':
3184
+ shapeDetails.strokeColor = obj.strokeSettings.strokeColor;
3185
+ shapeDetails.strokeWidth = obj.strokeSettings.strokeWidth;
3186
+ shapeDetails.points = obj.pointColl;
3187
+ break;
3188
+ case 'image':
3189
+ shapeDetails.imageData = obj.imageCanvas.toDataURL();
3190
+ shapeDetails.degree = obj.rotatedAngle * (180 / Math.PI);
3191
+ shapeDetails.width = obj.activePoint.width;
3192
+ shapeDetails.height = obj.activePoint.height;
3193
+ shapeDetails.opacity = obj.opacity;
3194
+ break;
3195
+ }
3196
+ return shapeDetails;
3197
+ }
3198
+
3199
+ private getFreehandDrawDetails(index: number): ShapeSettings {
3200
+ const parent: ImageEditor = this.parent;
3201
+ const shapeDetails: ShapeSettings = {} as ShapeSettings;
3202
+ shapeDetails.id = parent.pointColl[index as number].id;
3203
+ shapeDetails.type = ShapeType.FreehandDraw;
3204
+ shapeDetails.points = extend([], parent.pointColl[index as number].points) as Point[];
3205
+ shapeDetails.strokeColor = parent.pointColl[index as number].strokeColor;
3206
+ shapeDetails.strokeWidth = parent.pointColl[index as number].strokeWidth;
3207
+ shapeDetails.index = parent.pointColl[index as number].order;
3208
+ return shapeDetails;
3209
+ }
3210
+
3211
+ private getShapeSetting(id: string, obj: Object): void {
3212
+ const parent: ImageEditor = this.parent; let shapeDetails: ShapeSettings;
3213
+ if (!parent.disabled && parent.isImageLoaded) {
3214
+ if (parent.textArea.style.display !== 'none') {
3215
+ parent.okBtn(null, true);
3216
+ } else {
3217
+ this.applyActObj(true);
3218
+ }
3219
+ if (id.split('_')[0] === 'shape') {
3220
+ let obj: SelectionPoint;
3221
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
3222
+ if (parent.objColl[i as number].currIndex === id) {
3223
+ obj = extend({}, parent.objColl[i as number], {}, true) as SelectionPoint;
3224
+ break;
3225
+ }
3226
+ }
3227
+ shapeDetails = this.getObjDetails(obj);
3228
+ } else if (id.split('_')[0] === 'pen') {
3229
+ shapeDetails = this.getFreehandDrawDetails(parseInt(id.split('_')[1], 10) - 1);
3230
+ }
3231
+ }
3232
+ obj['shapeDetails'] = shapeDetails;
3233
+ }
3234
+
3235
+ private getShapeSettings(obj: Object): void {
3236
+ const parent: ImageEditor = this.parent; const shapeDetailsColl: ShapeSettings[] = [];
3237
+ if (!parent.disabled && parent.isImageLoaded) {
3238
+ if (parent.textArea.style.display !== 'none') {
3239
+ parent.okBtn(null, true);
3240
+ } else {
3241
+ this.applyActObj(true);
3242
+ }
3243
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
3244
+ const shapeDetails: ShapeSettings = this.getObjDetails(parent.objColl[i as number]);
3245
+ shapeDetailsColl.push(shapeDetails);
3246
+ }
3247
+ for (let i: number = 0; i < parent.freehandCounter; i++) {
3248
+ const shapeDetails: ShapeSettings = this.getFreehandDrawDetails(i as number);
3249
+ shapeDetailsColl.push(shapeDetails);
3250
+ }
3251
+ }
3252
+ obj['shapeDetailsColl'] = shapeDetailsColl;
3253
+ }
3254
+
3255
+ private getRedactSettings(obj: Object): void {
3256
+ const parent: ImageEditor = this.parent; const RedactDetailsColl: RedactSettings[] = [];
3257
+ if (!parent.disabled && parent.isImageLoaded) {
3258
+ if (parent.textArea.style.display !== 'none') {
3259
+ parent.okBtn(null, true);
3260
+ } else {
3261
+ this.applyActObj(true);
3262
+ }
3263
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
3264
+ const redactDetails: RedactSettings = this.getRedactObjDetails(parent.objColl[i as number]);
3265
+ RedactDetailsColl.push(redactDetails);
3266
+ }
3267
+ }
3268
+ obj['shapeDetailsColl'] = RedactDetailsColl;
3269
+ }
3270
+
3271
+ private isPointsInRange(x: number, y: number, obj: Object): void {
3272
+ let inRange: boolean = false; const parent: ImageEditor = this.parent;
3273
+ if (!isNullOrUndefined(x) && !isNullOrUndefined(y) && x >= parent.img.destLeft && y >= parent.img.destTop &&
3274
+ x <= parent.img.destLeft + parent.img.destWidth && y <= parent.img.destTop + parent.img.destHeight) {
3275
+ inRange = true;
3276
+ }
3277
+ obj['inRange'] = inRange;
3278
+ }
3279
+
3280
+ private alignRotateFlipColl(collection: number[] | string[], isRotateFlipCollection?: boolean,
3281
+ obj?: Object): number[] | string[] {
3282
+ collection = this.popForDefaultTransformedState(collection);
3283
+ collection = this.popForDefaultFlipState(collection);
3284
+ collection = this.popForDefaultRotateState(collection);
3285
+ if (collection.length === 0 && isRotateFlipCollection) {
3286
+ this.parent.transform.degree = 0; this.parent.transform.currFlipState = '';
3287
+ }
3288
+ obj['collection'] = collection;
3289
+ return collection;
3290
+ }
3291
+
3292
+ private popForDefaultTransformedState(collection: number[] | string[]): number[] | string[] {
3293
+ let rotateRight: number = 0; let rotateleft: number = 0; let horizontal: number = 0; let vertical: number = 0;
3294
+ for (let i: number = 0; i < collection.length; i++) {
3295
+ if (collection[i as number] === 90 || collection[i as number] === 'rotateRight') {
3296
+ rotateRight++; rotateleft = 0; horizontal = 0; vertical = 0;
3297
+ if (rotateRight === 4) {
3298
+ collection.pop(); collection.pop(); collection.pop(); collection.pop();
3299
+ }
3300
+ } else if (collection[i as number] === -90 || collection[i as number] === 'rotateLeft') {
3301
+ rotateleft++; rotateRight = 0; horizontal = 0; vertical = 0;
3302
+ if (rotateleft === 4) {
3303
+ collection.pop(); collection.pop(); collection.pop(); collection.pop();
3304
+ }
3305
+ } else if (collection[i as number] === 'horizontal' || collection[i as number] === 'Horizontal'
3306
+ || collection[i as number] === 'horizontalflip') {
3307
+ horizontal++; rotateleft = 0; rotateRight = 0; vertical = 0;
3308
+ if (horizontal === 2) {
3309
+ collection.pop(); collection.pop();
3310
+ }
3311
+ } else if (collection[i as number] === 'vertical' || collection[i as number] === 'Vertical'
3312
+ || collection[i as number] === 'verticalflip') {
3313
+ vertical++; horizontal = 0; rotateleft = 0; rotateRight = 0;
3314
+ if (vertical === 2) {
3315
+ collection.pop(); collection.pop();
3316
+ }
3317
+ }
3318
+ }
3319
+ return collection;
3320
+ }
3321
+
3322
+ private popForDefaultFlipState(collection: number[] | string[]): number[] | string[] {
3323
+ for (let i: number = 0, iLen: number = collection.length - 3; i < iLen; i++) {
3324
+ const isHorizontal: boolean = collection[i as number] === 'horizontal' || collection[i as number] === 'Horizontal'
3325
+ || collection[i as number] === 'horizontalFlip';
3326
+ const isVertical: boolean = collection[i as number] === 'vertical' || collection[i as number] === 'Vertical' ||
3327
+ collection[i as number] === 'verticalFlip';
3328
+ const isNextHorizontal: boolean = collection[i + 1] === 'horizontal' || collection[i + 1] === 'Horizontal' ||
3329
+ collection[i + 1] === 'horizontalFlip';
3330
+ const isNextVertical: boolean = collection[i + 1] === 'vertical' || collection[i + 1] === 'Vertical' ||
3331
+ collection[i + 1] === 'verticalFlip';
3332
+ const isNextToNextHorizontal: boolean = collection[i + 2] === 'horizontal' || collection[i + 2] === 'Horizontal' ||
3333
+ collection[i + 2] === 'horizontalFlip';
3334
+ const isNextToNextVertical: boolean = collection[i + 2] === 'vertical' || collection[i + 2] === 'Vertical' ||
3335
+ collection[i + 2] === 'verticalFlip';
3336
+ const isNextToNextToNextHorizontal: boolean = collection[i + 3] === 'horizontal' || collection[i + 3] === 'Horizontal' ||
3337
+ collection[i + 3] === 'horizontalFlip';
3338
+ if ((isHorizontal && isNextVertical && isNextToNextHorizontal && isNextToNextVertical) ||
3339
+ (isVertical && isNextHorizontal && isNextToNextVertical && isNextToNextToNextHorizontal)) {
3340
+ collection.splice(i, 4);
3341
+ i -= 4;
3342
+ }
3343
+ }
3344
+ return collection;
3345
+ }
3346
+
3347
+ private popForDefaultRotateState(collection: number[] | string[]): number[] | string[] {
3348
+ for (let i: number = 0; i < collection.length - 1; i++) {
3349
+ const curr: number | string = collection[i as number];
3350
+ const next: number | string = collection[i + 1];
3351
+ if ((curr === 90 || curr === 'rotateRight') && (next === -90 || next === 'rotateLeft')) {
3352
+ collection.splice(i, 2);
3353
+ i -= 2;
3354
+ } else if ((curr === -90 || curr === 'rotateLeft') && (next === 90 || next === 'rotateRight')) {
3355
+ collection.splice(i, 2);
3356
+ i -= 2;
3357
+ }
3358
+ }
3359
+ return collection;
3360
+ }
3361
+
3362
+ private selectShape(id: string, obj: Object): void {
3363
+ const parent: ImageEditor = this.parent; let isSelected: boolean = false;
3364
+ if (!parent.disabled && parent.isImageLoaded) {
3365
+ this.applyActObj();
3366
+ if (id.split('_')[0] === 'shape') {
3367
+ let obj: SelectionPoint;
3368
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
3369
+ if (parent.objColl[i as number].currIndex === id) {
3370
+ obj = extend({}, parent.objColl[i as number], {}, true) as SelectionPoint;
3371
+ break;
3372
+ }
3373
+ }
3374
+ if (isNullOrUndefined(obj)) {isSelected = false; }
3375
+ else {
3376
+ isSelected = true; parent.activeObj = obj;
3377
+ const object: Object = {canvasFilter: null };
3378
+ parent.notify('toolbar', { prop: 'getCanvasFilter', onPropertyChange: false, value: {obj: object }});
3379
+ this.lowerContext.filter = object['canvasFilter'];
3380
+ parent.notify('selection', { prop: 'redrawShape', onPropertyChange: false,
3381
+ value: {obj: parent.activeObj}});
3382
+ if (parent.activeObj.shape === 'text') {
3383
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'text',
3384
+ isApplyBtn: null, isCropping: null, isZooming: null, cType: null}});
3385
+ } else if (parent.activeObj.shape === 'pen') {
3386
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'pen',
3387
+ isApplyBtn: null, isCropping: null, isZooming: null, cType: null}});
3388
+ } else if (parent.activeObj.shape === 'redact') {
3389
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'redact',
3390
+ isApplyBtn: null, isCropping: null, isZooming: null, cType: null}});
3391
+ } else {
3392
+ parent.notify('toolbar', { prop: 'refresh-toolbar', onPropertyChange: false, value: {type: 'shapes',
3393
+ isApplyBtn: null, isCropping: null, isZooming: null, cType: null}});
3394
+ }
3395
+ parent.notify('toolbar', { prop: 'update-toolbar-items', onPropertyChange: false});
3396
+ parent.notify('toolbar', { prop: 'renderQAT', onPropertyChange: false, value: {isPenEdit: null} });
3397
+ }
3398
+ } else if (id.split('_')[0] === 'pen') {
3399
+ const object: Object = {bool: false };
3400
+ parent.notify('selection', { prop: 'getFreehandDrawEditing', onPropertyChange: false, value: {obj: object }});
3401
+ if (object['bool']) {parent.okBtn(null, true); }
3402
+ const obj: Object = {isIndex: false };
3403
+ parent.notify('freehand-draw', { prop: 'isFHDIdx', value: { index: parseInt(id.split('_')[1], 10) - 1, obj: obj }});
3404
+ if (obj['isIndex']) {
3405
+ isSelected = true;
3406
+ parent.notify('freehand-draw', { prop: 'selectFhd', value: { id: id} });
3407
+ parent.notify('toolbar', { prop: 'renderQAT', onPropertyChange: false, value: {isPenEdit: true} });
3408
+ parent.notify('toolbar', { prop: 'update-toolbar-items', onPropertyChange: false});
3409
+ } else {
3410
+ isSelected = false;
3411
+ }
3412
+ }
3413
+ }
3414
+ obj['isSelected'] = isSelected;
3415
+ }
3416
+
3417
+ private deleteShape(id: string): void {
3418
+ const parent: ImageEditor = this.parent;
3419
+ if (!parent.disabled && parent.isImageLoaded) {
3420
+ if (parent.activeObj.currIndex && parent.activeObj.currIndex === id) {
3421
+ parent.notify('selection', { prop: 'deleteItem', onPropertyChange: false});
3422
+ } else {
3423
+ this.applyActObj();
3424
+ if (id.split('_')[0] === 'shape') {
3425
+ for (let i: number = 0, len: number = parent.objColl.length; i < len; i++) {
3426
+ if (parent.objColl[i as number].currIndex === id) {
3427
+ parent.objColl.splice(i, 1);
3428
+ break;
3429
+ }
3430
+ }
3431
+ } else if (id.split('_')[0] === 'pen') {
3432
+ parent.notify('freehand-draw', {prop: 'handle-freehand-draw', value: {id: id}});
3433
+ }
3434
+ }
3435
+ const object: Object = {canvasFilter: null };
3436
+ parent.notify('toolbar', { prop: 'getCanvasFilter', onPropertyChange: false, value: {obj: object }});
3437
+ this.lowerContext.filter = object['canvasFilter'];
3438
+ this.lowerContext.clearRect(0, 0, parent.lowerCanvas.width, parent.lowerCanvas.height);
3439
+ parent.notify('draw', { prop: 'redrawImgWithObj', onPropertyChange: false});
3440
+ parent.notify('toolbar', { prop: 'refresh-main-toolbar', onPropertyChange: false});
3441
+ parent.notify('undo-redo', {prop: 'updateCurrUrc', value: {type: 'ok' }});
3442
+ }
3443
+ }
3444
+
3445
+ private getMaxText(isTextBox?: boolean, text?: string, obj?: Object): string {
3446
+ if (isNullOrUndefined(text)) {
3447
+ text = isTextBox ? this.parent.textArea.value : this.parent.activeObj.keyHistory;
3448
+ if (!text) {return text; }
3449
+ }
3450
+ let maxi: number; const rows: string[] = text.split('\n'); let maxStr: number = rows[0].length;
3451
+ let maxText: string = rows[0];
3452
+ for (let i: number = 1; i < rows.length; i++) {
3453
+ maxi = rows[i as number].length;
3454
+ if (maxi > maxStr) {
3455
+ maxText = rows[i as number]; maxStr = maxi;
3456
+ }
3457
+ }
3458
+ if (obj) { obj['maxText'] = maxText; }
3459
+ return maxText;
3460
+ }
3461
+ private getLinePoints(x1: number, y1: number, x2: number, y2: number): Point[] {
3462
+ let points: Point[] = []; let i: number[]; let j: number[];
3463
+ if (x1 === x2) {
3464
+ if (y1 < y2) {
3465
+ i = [x1, y1]; j = [x2, y2];
3466
+ } else {
3467
+ j = [x1, y1]; i = [x2, y2];
3468
+ }
3469
+ const m: number = this.getSlope(i, j, true); const b: number = this.getIntercept(i, m);
3470
+ for (let y: number = i[1]; y <= j[1]; y++){
3471
+ const x: number = m * y + b; points.push({x: x, y: y});
3472
+ }
3473
+ } else {
3474
+ if (x1 < x2) {
3475
+ i = [x1, y1]; j = [x2, y2];
3476
+ } else {
3477
+ j = [x1, y1]; i = [x2, y2];
3478
+ }
3479
+ const m: number = this.getSlope(i, j, false); const b: number = this.getIntercept(i, m);
3480
+ for (let x: number = i[0]; x <= j[0]; x++){
3481
+ const y: number = m * x + b; points.push({x: x, y: y});
3482
+ }
3483
+ }
3484
+ if (Math.floor(x1) === Math.floor(x2) || (points.length < 10 && (y2 - y1 > 10 || y1 - y2 > 10))) {
3485
+ points = [];
3486
+ const lesserY: number = Math.min(y1, y2);
3487
+ for (let i: number = 0; i < Math.abs(Math.floor(y2) - Math.floor(y1)); i++) {
3488
+ points.push({x: x1, y: lesserY + i});
3489
+ }
3490
+ if (points.length > 1) {
3491
+ let prev: Point;
3492
+ if (isNullOrUndefined(points[points.length - 2])) {prev = {x: 0, y: 0}; }
3493
+ else {prev = points[points.length - 2]; }
3494
+ const diffX: number = points[points.length - 1]['x'] - prev.x;
3495
+ const diffY: number = points[points.length - 1]['y'] - prev.y;
3496
+ points.push({ x: points[points.length - 1]['x'] + (diffX / 2), y: points[points.length - 1]['y'] + (diffY / 2) });
3497
+ }
3498
+ } else if (Math.floor(y1) === Math.floor(y2) || (points.length < 10 && (x2 - x1 > 10 || x1 - x2 > 10))) {
3499
+ points = [];
3500
+ const lesserX: number = Math.min(x1, x2);
3501
+ for (let i: number = 0; i < Math.abs(Math.floor(x2) - Math.floor(x1)); i++) {
3502
+ points.push({x: lesserX + i, y: y1});
3503
+ }
3504
+ if (points.length > 1) {
3505
+ let prev: Point;
3506
+ if (isNullOrUndefined(points[points.length - 2])) {prev = {x: 0, y: 0}; }
3507
+ else {prev = points[points.length - 2]; }
3508
+ const diffX: number = points[points.length - 1]['x'] - prev.x;
3509
+ const diffY: number = points[points.length - 1]['y'] - prev.y;
3510
+ points.push({ x: points[points.length - 1]['x'] + (diffX / 2), y: points[points.length - 1]['y'] + (diffY / 2) });
3511
+ }
3512
+ }
3513
+ return points;
3514
+ }
3515
+
3516
+ private getSlope(a: number[], b: number[], isSameAxis: boolean): number {
3517
+ let slope: number;
3518
+ if (isSameAxis) {
3519
+ if (a[1] === b[1]) {return null; } slope = (b[0] - a[0]) / (b[1] - a[1]);
3520
+ } else {
3521
+ if (a[0] === b[0]) {return null; } slope = (b[1] - a[1]) / (b[0] - a[0]);
3522
+ }
3523
+ return slope;
3524
+ }
3525
+
3526
+ private getIntercept(point: number[], getSlope: number): number {
3527
+ if (getSlope === null) {return point[0]; }
3528
+ return point[1] - getSlope * point[0];
3529
+ }
3530
+
3531
+ private setPointCollForShapeRotation(obj: SelectionPoint): void {
3532
+ const parent: ImageEditor = this.parent;
3533
+ const { startX, startY, endX, endY, width, height } = obj.activePoint;
3534
+ const center: Point = {x: startX + (width / 2), y: startY +
3535
+ (height / 2)};
3536
+ const cosAngle: number = Math.cos(obj.rotatedAngle);
3537
+ const sinAngle: number = Math.sin(obj.rotatedAngle);
3538
+ const p1: Point = { x: cosAngle * (startX - center.x) - sinAngle * (startY - center.y) + center.x,
3539
+ y: sinAngle * (startX - center.x) + cosAngle * (startY - center.y) + center.y };
3540
+ const p2: Point = { x: cosAngle * (endX - center.x) - sinAngle * (startY - center.y) + center.x,
3541
+ y: sinAngle * (endX - center.x) + cosAngle * (startY - center.y) + center.y };
3542
+ const p3: Point = { x: cosAngle * (startX - center.x) - sinAngle * (endY - center.y) + center.x,
3543
+ y: sinAngle * (startX - center.x) + cosAngle * (endY - center.y) + center.y };
3544
+ const p4: Point = { x: cosAngle * (endX - center.x) - sinAngle * (endY - center.y) + center.x,
3545
+ y: sinAngle * (endX - center.x) + cosAngle * (endY - center.y) + center.y };
3546
+ obj.horTopLinePointColl = this.getLinePoints(p1.x, p1.y, p2.x, p2.y);
3547
+ obj.horTopLinePointColl = this.getLinePoints(p1.x, p1.y, p2.x, p2.y);
3548
+ obj.horBottomLinePointColl = this.getLinePoints(p3.x, p3.y, p4.x, p4.y);
3549
+ obj.verLeftLinePointColl = this.getLinePoints(p1.x, p1.y, p3.x, p3.y);
3550
+ obj.verRightLinePointColl = this.getLinePoints(p2.x, p2.y, p4.x, p4.y);
3551
+ obj.verLeftLinePointColl.reverse(); obj.verRightLinePointColl.reverse();
3552
+ for (let i: number = 0; i < obj.horTopLinePointColl.length; i++) {
3553
+ obj.horTopLinePointColl[i as number].ratioX = (obj.horTopLinePointColl[i as number].x -
3554
+ this.parent.img.destLeft) / this.parent.img.destWidth;
3555
+ obj.horTopLinePointColl[i as number].ratioY = (obj.horTopLinePointColl[i as number].y -
3556
+ this.parent.img.destTop) / this.parent.img.destHeight;
3557
+ }
3558
+ for (let i: number = 0; i < obj.horBottomLinePointColl.length; i++) {
3559
+ obj.horBottomLinePointColl[i as number].ratioX = (obj.horBottomLinePointColl[i as number].x -
3560
+ this.parent.img.destLeft) / this.parent.img.destWidth;
3561
+ obj.horBottomLinePointColl[i as number].ratioY = (obj.horBottomLinePointColl[i as number].y -
3562
+ this.parent.img.destTop) / this.parent.img.destHeight;
3563
+ }
3564
+ for (let i: number = 0; i < obj.verLeftLinePointColl.length; i++) {
3565
+ obj.verLeftLinePointColl[i as number].ratioX = (obj.verLeftLinePointColl[i as number].x -
3566
+ this.parent.img.destLeft) / this.parent.img.destWidth;
3567
+ obj.verLeftLinePointColl[i as number].ratioY = (obj.verLeftLinePointColl[i as number].y -
3568
+ this.parent.img.destTop) / this.parent.img.destHeight;
3569
+ }
3570
+ for (let i: number = 0; i < obj.verRightLinePointColl.length; i++) {
3571
+ obj.verRightLinePointColl[i as number].ratioX = (obj.verRightLinePointColl[i as number].x -
3572
+ this.parent.img.destLeft) / this.parent.img.destWidth;
3573
+ obj.verRightLinePointColl[i as number].ratioY = (obj.verRightLinePointColl[i as number].y -
3574
+ this.parent.img.destTop) / this.parent.img.destHeight;
3575
+ }
3576
+ if (parent.upperCanvas.style.cursor !== 'move') {
3577
+ const object: Object = {rotationCirclePoint: null };
3578
+ parent.notify('selection', { prop: 'getTransRotationPoint', value: {obj: obj, object: object }});
3579
+ const rotationCirclePoint: Point = object['rotationCirclePoint'];
3580
+ if (rotationCirclePoint) {
3581
+ obj.rotationCirclePointColl = { x: cosAngle * (rotationCirclePoint.x - center.x) -
3582
+ sinAngle * (rotationCirclePoint.y - center.y) + center.x,
3583
+ y: sinAngle * (rotationCirclePoint.x - center.x) + cosAngle
3584
+ * (rotationCirclePoint.y - center.y) + center.y };
3585
+ obj.rotationCirclePointColl.ratioX = (obj.rotationCirclePointColl.x - parent.img.destLeft) /
3586
+ parent.img.destWidth;
3587
+ obj.rotationCirclePointColl.ratioY = (obj.rotationCirclePointColl.y - parent.img.destTop) /
3588
+ parent.img.destHeight;
3589
+ }
3590
+ }
3591
+ }
3592
+
3593
+ private getSquarePointForRotatedShape(obj: SelectionPoint, object?: Object): ActivePoint {
3594
+ const point: ActivePoint = { startX: 0, startY: 0, endX: 0, endY: 0, width: 0, height: 0 };
3595
+ const { startX, startY, endX, endY, width, height } = obj.activePoint;
3596
+ const center: Point = {x: startX + (width / 2), y: startY + (height / 2)};
3597
+ const cosAngle: number = Math.cos(obj.rotatedAngle);
3598
+ const sinAngle: number = Math.sin(obj.rotatedAngle);
3599
+ const p1: Point = { x: cosAngle * (startX - center.x) - sinAngle * (startY - center.y) + center.x,
3600
+ y: sinAngle * (startX - center.x) + cosAngle * (startY - center.y) + center.y };
3601
+ const p2: Point = { x: cosAngle * (endX - center.x) - sinAngle * (startY - center.y) + center.x,
3602
+ y: sinAngle * (endX - center.x) + cosAngle * (startY - center.y) + center.y };
3603
+ const p3: Point = { x: cosAngle * (startX - center.x) - sinAngle * (endY - center.y) + center.x,
3604
+ y: sinAngle * (startX - center.x) + cosAngle * (endY - center.y) + center.y };
3605
+ const p4: Point = { x: cosAngle * (endX - center.x) - sinAngle * (endY - center.y) + center.x,
3606
+ y: sinAngle * (endX - center.x) + cosAngle * (endY - center.y) + center.y };
3607
+ point.startX = p1.x; point.startY = p1.y; point.endX = p1.x; point.endY = p1.y;
3608
+ if (point.startX > p2.x) { point.startX = p2.x; } if (point.startX > p3.x) { point.startX = p3.x; }
3609
+ if (point.startX > p4.x) { point.startX = p4.x; } if (point.startY > p2.y) { point.startY = p2.y; }
3610
+ if (point.startY > p3.y) { point.startY = p3.y; } if (point.startY > p4.y) { point.startY = p4.y; }
3611
+ if (point.endX < p2.x) { point.endX = p2.x; } if (point.endX < p3.x) { point.endX = p3.x; }
3612
+ if (point.endX < p4.x) { point.endX = p4.x; } if (point.endY < p2.y) { point.endY = p2.y; }
3613
+ if (point.endY < p3.y) { point.endY = p3.y; } if (point.endY < p4.y) { point.endY = p4.y; }
3614
+ point.width = point.endX - point.startX; point.height = point.endY - point.startY;
3615
+ if (object) {
3616
+ object['activePoint'] = point;
3617
+ }
3618
+ return point;
3619
+ }
3620
+
3621
+ private updateZOrder(obj: SelectionPoint | Object, value: string): void {
3622
+ const parent: ImageEditor = this.parent;
3623
+ value = value.toLowerCase();
3624
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3625
+ const object: any = obj;
3626
+ if (isNullOrUndefined(object.order)) {return; }
3627
+ let index: number; let prevIndex: number;
3628
+ const highestOrder: number = this.getHighestOrder();
3629
+ this.updateShapeColl();
3630
+ if (parent.shapeColl.length === 0) {
3631
+ return;
3632
+ }
3633
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3634
+ let coll: any;
3635
+ for (let i: number = 0; i < parent.shapeColl.length; i++) {
3636
+ coll = parent.shapeColl[i as number];
3637
+ if (object.id && object.id.indexOf('pen') > -1) {
3638
+ if (coll.id && coll.id === object.id) {
3639
+ parent.shapeColl.splice(i, 1);
3640
+ }
3641
+ } else if (coll.shape && coll.shape.indexOf('crop-') > -1) {
3642
+ parent.shapeColl.splice(i, 1);
3643
+ }
3644
+ }
3645
+ switch (value) {
3646
+ case 'sendtoback':
3647
+ prevIndex = object.order;
3648
+ index = object.order;
3649
+ object.order = 1;
3650
+ break;
3651
+ case 'sendbackward':
3652
+ object.order -= 1;
3653
+ index = object.order;
3654
+ break;
3655
+ case 'bringtofront':
3656
+ prevIndex = object.order;
3657
+ index = highestOrder;
3658
+ object.order = index;
3659
+ break;
3660
+ case 'bringforward':
3661
+ object.order += 1;
3662
+ index = object.order;
3663
+ break;
3664
+ }
3665
+ this.reArrangeObjColl(index, value, prevIndex);
3666
+ if (object.id && object.id.indexOf('pen') > -1) {
3667
+ this.reUpdateShapeColl(object);
3668
+ }
3669
+ }
3670
+
3671
+ private reArrangeObjColl(index: number, value: string, prevIndex: number): void {
3672
+ const parent: ImageEditor = this.parent;
3673
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3674
+ let obj: any;
3675
+ switch (value) {
3676
+ case 'sendtoback':
3677
+ for (let i: number = 0, len: number = parent.shapeColl.length; i < len; i++) {
3678
+ obj = parent.shapeColl[i as number];
3679
+ if (obj.order < prevIndex && obj.order <= index) {
3680
+ obj.order += 1;
3681
+ this.reUpdateShapeColl(obj);
3682
+ }
3683
+ }
3684
+ break;
3685
+ case 'sendbackward':
3686
+ for (let i: number = 0, len: number = parent.shapeColl.length; i < len; i++) {
3687
+ obj = parent.shapeColl[i as number];
3688
+ if (obj.order === index) {
3689
+ obj.order += 1;
3690
+ this.reUpdateShapeColl(obj);
3691
+ break;
3692
+ }
3693
+ }
3694
+ break;
3695
+ case 'bringtofront':
3696
+ for (let i: number = 0, len: number = parent.shapeColl.length; i < len; i++) {
3697
+ obj = parent.shapeColl[i as number];
3698
+ if (obj.order > prevIndex && obj.order <= index) {
3699
+ obj.order -= 1;
3700
+ this.reUpdateShapeColl(obj);
3701
+ }
3702
+ }
3703
+ break;
3704
+ case 'bringforward':
3705
+ for (let i: number = 0, len: number = parent.shapeColl.length; i < len; i++) {
3706
+ obj = parent.shapeColl[i as number];
3707
+ if (obj.order === index) {
3708
+ obj.order -= 1;
3709
+ this.reUpdateShapeColl(obj);
3710
+ break;
3711
+ }
3712
+ }
3713
+ break;
3714
+ }
3715
+ }
3716
+
3717
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3718
+ private reorderRedact(tempObjColl: SelectionPoint[] | any): SelectionPoint[] | any {
3719
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3720
+ const nonRedact: any = tempObjColl.filter((item: SelectionPoint) => item.shape !== 'redact');
3721
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3722
+ const redact: any = tempObjColl.filter((item: SelectionPoint) => item.shape === 'redact');
3723
+ return redact.concat(nonRedact);
3724
+ }
3725
+
3726
+ private updateShapeColl(): void {
3727
+ const parent: ImageEditor = this.parent;
3728
+ let isOrdered: boolean = false; let tempOrder: number = 1;
3729
+ let tempObjColl: SelectionPoint[] = extend([], parent.objColl, [], true) as SelectionPoint[];
3730
+ tempObjColl = this.reorderRedact(tempObjColl);
3731
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3732
+ let tempPointColl: any = extend([], parent.pointColl, [], true);
3733
+ if (parent.shapeColl.length > 0 &&
3734
+ parent.shapeColl.length === parent.objColl.length + parent.pointColl.length) {
3735
+ for (let i: number = 0; i < parent.shapeColl.length; i++) {
3736
+ if (parent.shapeColl[i as number].order === tempOrder) {
3737
+ isOrdered = true; tempOrder++;
3738
+ } else {
3739
+ isOrdered = false;
3740
+ break;
3741
+ }
3742
+ }
3743
+ if (isOrdered) {
3744
+ for (let i: number = 0; i < parent.shapeColl.length; i++) {
3745
+ if (parent.shapeColl[i as number].currIndex &&
3746
+ parent.shapeColl[i as number].currIndex.indexOf('shape') > -1) {
3747
+ for (let j: number = 0; j < tempObjColl.length; j++) {
3748
+ if (parent.shapeColl[i as number].currIndex === tempObjColl[j as number].currIndex) {
3749
+ parent.shapeColl[i as number] = extend({}, tempObjColl[j as number], {}, true);
3750
+ tempObjColl.splice(j, 1);
3751
+ break;
3752
+ }
3753
+ }
3754
+ } else if (parent.shapeColl[i as number].id && parent.shapeColl[i as number].id.indexOf('pen') > -1) {
3755
+ for (let j: number = 0; j < tempPointColl.length; j++) {
3756
+ if (parent.shapeColl[i as number].id === tempPointColl[j as number].id) {
3757
+ parent.shapeColl[i as number] = extend([], tempPointColl[j as number], [], true);
3758
+ tempPointColl.splice(j, 1);
3759
+ break;
3760
+ }
3761
+ }
3762
+ }
3763
+ }
3764
+ return;
3765
+ }
3766
+ }
3767
+ tempObjColl = extend([], parent.objColl, [], true) as SelectionPoint[];
3768
+ tempPointColl = extend([], parent.pointColl, [], true);
3769
+ parent.shapeColl = []; let order: number = 1; let isBreak: boolean; let isCrop: boolean = false;
3770
+ while (tempObjColl.length !== 0 || tempPointColl.length !== 0) {
3771
+ isBreak = isCrop = false;
3772
+ for (let i: number = 0; i < tempObjColl.length; i++) {
3773
+ if (tempObjColl[i as number].order === order ||
3774
+ (!tempObjColl[i as number].order && tempObjColl[i as number].shape &&
3775
+ tempObjColl[i as number].shape.indexOf('crop-') > -1)) {
3776
+ parent.shapeColl.push(extend({}, tempObjColl[i as number], {}, true));
3777
+ if (tempObjColl[i as number].shape && tempObjColl[i as number].shape.indexOf('crop-') > -1) {
3778
+ isCrop = true;
3779
+ }
3780
+ tempObjColl.splice(i, 1);
3781
+ isBreak = true;
3782
+ break;
3783
+ }
3784
+ }
3785
+ if (!isBreak) {
3786
+ for (let i: number = 0; i < tempPointColl.length; i++) {
3787
+ if (tempPointColl[i as number].order === order) {
3788
+ parent.shapeColl.push(extend([], tempPointColl[i as number], [], true));
3789
+ tempPointColl.splice(i, 1);
3790
+ isBreak = true;
3791
+ break;
3792
+ }
3793
+ }
3794
+ }
3795
+ if (!isCrop) {order++; }
3796
+ }
3797
+ }
3798
+
3799
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3800
+ private reUpdateShapeColl(obj: any): void {
3801
+ const parent: ImageEditor = this.parent;
3802
+ if (obj.id && obj.id.indexOf('pen') > -1) {
3803
+ if (parent.freehandCounter > 0) {
3804
+ for (let i: number = 0; i < parent.freehandCounter; i++) {
3805
+ if (parent.pointColl[i as number].id === obj.id) {
3806
+ parent.pointColl[i as number].order = obj.order;
3807
+ }
3808
+ }
3809
+ }
3810
+ } else if (obj.currIndex && obj.currIndex.indexOf('shape') > -1) {
3811
+ for (let i: number = 0; i < parent.objColl.length; i++) {
3812
+ if (parent.objColl[i as number].currIndex === obj.currIndex) {
3813
+ parent.objColl[i as number].order = obj.order;
3814
+ }
3815
+ }
3816
+ }
3817
+ }
3818
+
3819
+ private drawAnnotations(ctx: CanvasRenderingContext2D, shape: string, pen: string, isPreventApply: boolean,
3820
+ x: number, y: number, panRegion: string): void {
3821
+ const parent: ImageEditor = this.parent;
3822
+ const activeObj: SelectionPoint = extend({}, parent.activeObj, {}, true) as SelectionPoint;
3823
+ const tempObjColl: SelectionPoint[] = extend([], parent.objColl, [], true) as SelectionPoint[];
3824
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3825
+ const tempPointColl: any = extend([], parent.pointColl, [], true);
3826
+ const tempSelPointCollObj: Object = {selPointColl: null };
3827
+ parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false,
3828
+ value: {obj: tempSelPointCollObj }});
3829
+ const selPointCollObj: Object = {selPointColl: null };
3830
+ parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false,
3831
+ value: {obj: selPointCollObj }});
3832
+ this.updateShapeColl();
3833
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3834
+ let tempShapeColl: any = extend([], parent.shapeColl, [], true);
3835
+ tempShapeColl = this.reorderRedact(tempShapeColl);
3836
+ let isPrevented: boolean = false;
3837
+ if (!this.preventFrameAnnotation) {this.preventFrameAnnotation = isPrevented = true; }
3838
+ for (let i: number = 0; i < tempShapeColl.length; i++) {
3839
+ const isPenId: string = tempShapeColl[i as number].id;
3840
+ if ((tempShapeColl[i as number].order) ||
3841
+ (!tempShapeColl[i as number].order && tempShapeColl[i as number].shape && tempShapeColl[i as number].shape.indexOf('crop-') > -1) ||
3842
+ (!tempShapeColl[i as number].order && tempShapeColl[i as number].shape === 'path' && parent.drawingShape === 'path')) {
3843
+ if (tempShapeColl[i as number].currIndex && tempShapeColl[i as number].currIndex.indexOf('shape') > -1) {
3844
+ parent.objColl = [];
3845
+ parent.objColl.push(extend({}, tempShapeColl[i as number], {}, true) as SelectionPoint);
3846
+ if (shape === 'iterate') {
3847
+ const temp: string = this.lowerContext.filter;
3848
+ this.lowerContext.filter = 'none';
3849
+ this.iterateObjColl();
3850
+ this.lowerContext.filter = temp;
3851
+ } else if (shape === 'zoom' || shape === 'pan') {
3852
+ let tempObjCollIndex: number = -1;
3853
+ for (let i: number = 0; i < tempObjColl.length; i++) {
3854
+ if (JSON.stringify(tempObjColl[i as number]) === JSON.stringify(parent.objColl[0])) {
3855
+ tempObjCollIndex = i;
3856
+ break;
3857
+ }
3858
+ }
3859
+ if (shape === 'zoom') {
3860
+ this.zoomObjColl(isPreventApply);
3861
+ } else {
3862
+ this.panObjColl(x, y, panRegion);
3863
+ }
3864
+ if (tempObjCollIndex > -1) {
3865
+ tempObjColl[tempObjCollIndex as number] = extend({}, parent.objColl[0], {}, true) as SelectionPoint;
3866
+ }
3867
+ }
3868
+ } else if (tempShapeColl[i as number].id && tempShapeColl[i as number].id.indexOf('pen') > -1) {
3869
+ parent.pointColl = []; parent.freehandCounter = 0;
3870
+ parent.notify('freehand-draw', { prop: 'setSelPointColl', onPropertyChange: false, value: {obj: {selPointColl: [] } }});
3871
+ parent.pointColl.push(extend({}, tempShapeColl[i as number], {}, true));
3872
+ parent.notify('freehand-draw', { prop: 'pushSelPointColl', onPropertyChange: false,
3873
+ value: {obj: {selPointColl: selPointCollObj['selPointColl'][i as number] } }});
3874
+ parent.freehandCounter = parent.pointColl.length;
3875
+ if (pen === 'iterate') {
3876
+ parent.notify('freehand-draw', { prop: 'freehandRedraw', onPropertyChange: false,
3877
+ value: {context: ctx, points: null} });
3878
+ } else if (pen === 'zoom' || pen === 'pan') {
3879
+ if (pen === 'zoom') {
3880
+ parent.notify('freehand-draw', { prop: 'zoomFHDColl', onPropertyChange: false,
3881
+ value: {isPreventApply: isPreventApply}});
3882
+ } else {
3883
+ parent.notify('freehand-draw', { prop: 'panFHDColl', onPropertyChange: false,
3884
+ value: {xDiff: x, yDiff: y, panRegion: panRegion}});
3885
+ }
3886
+ for (let i: number = 0; i < tempPointColl.length; i++) {
3887
+ if (tempPointColl[i as number].id === parent.pointColl[0].id) {
3888
+ tempPointColl[i as number] = extend({}, parent.pointColl[0], {}, true);
3889
+ break;
3890
+ }
3891
+ }
3892
+ for (let i: number = 0, len: number = tempSelPointCollObj['selPointColl'].length; i < len; i++) {
3893
+ if (tempSelPointCollObj['selPointColl'][i as number].id === selPointCollObj['selPointColl'][i as number].id) {
3894
+ tempSelPointCollObj['selPointColl'][i as number] = extend({}, selPointCollObj['selPointColl'][i as number], {}, true);
3895
+ break;
3896
+ }
3897
+ }
3898
+ }
3899
+ }
3900
+ } else if ((!tempShapeColl[i as number].shape && !isPenId) ||
3901
+ (!tempShapeColl[i as number].currIndex && !isPenId)) {
3902
+ tempShapeColl.splice(i, 1);
3903
+ }
3904
+ }
3905
+ if (pen && pen === 'zoom') {
3906
+ parent.pointColl = []; parent.freehandCounter = 0;
3907
+ parent.notify('freehand-draw', { prop: 'zoomFHDColl', onPropertyChange: false, value: {isPreventApply: isPreventApply}});
3908
+ }
3909
+ parent.objColl = tempObjColl; parent.pointColl = tempPointColl; parent.freehandCounter = parent.pointColl.length;
3910
+ parent.notify('freehand-draw', { prop: 'setSelPointColl', onPropertyChange: false, value: {obj: {selPointColl: tempSelPointCollObj['selPointColl'] } }});
3911
+ if (isPrevented && this.preventFrameAnnotation) {
3912
+ parent.notify('draw', { prop: 'applyFrame', value: { ctx: this.lowerContext, frame: parent.frameObj.type, preventImg: true } });
3913
+ this.preventFrameAnnotation = false;
3914
+ }
3915
+ parent.activeObj = activeObj;
3916
+ }
3917
+ }