@acorex/components 22.0.3 → 22.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/acorex-components-audio-wave.mjs +15 -0
- package/fesm2022/acorex-components-audio-wave.mjs.map +1 -1
- package/fesm2022/acorex-components-conversation-acorex-components-conversation-BtkyQUlh.mjs +16548 -0
- package/fesm2022/acorex-components-conversation-acorex-components-conversation-BtkyQUlh.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-D4ca9Mvt.mjs +51 -0
- package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-D4ca9Mvt.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-image-picker-editor-dialog.component-QVs1XWYf.mjs +85 -0
- package/fesm2022/acorex-components-conversation-image-picker-editor-dialog.component-QVs1XWYf.mjs.map +1 -0
- package/fesm2022/{acorex-components-conversation-open-composer-picker-for-files-DnSW908R.mjs → acorex-components-conversation-open-composer-picker-for-files-BKKO_8x6.mjs} +3 -3
- package/fesm2022/{acorex-components-conversation-open-composer-picker-for-files-DnSW908R.mjs.map → acorex-components-conversation-open-composer-picker-for-files-BKKO_8x6.mjs.map} +1 -1
- package/fesm2022/acorex-components-conversation-picker-rename-file-dialog.component-BNKFb5yO.mjs +65 -0
- package/fesm2022/acorex-components-conversation-picker-rename-file-dialog.component-BNKFb5yO.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation.mjs +1 -15531
- package/fesm2022/acorex-components-conversation.mjs.map +1 -1
- package/fesm2022/acorex-components-image-editor.mjs +600 -409
- package/fesm2022/acorex-components-image-editor.mjs.map +1 -1
- package/fesm2022/acorex-components-range-slider.mjs +2 -2
- package/fesm2022/acorex-components-range-slider.mjs.map +1 -1
- package/package.json +3 -3
- package/types/acorex-components-audio-wave.d.ts +3 -0
- package/types/acorex-components-conversation.d.ts +1407 -1295
- package/types/acorex-components-image-editor.d.ts +54 -49
- package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-DCcRJYfF.mjs +0 -50
- package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-DCcRJYfF.mjs.map +0 -1
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import { AXComponent, MXBaseComponent, MXInputBaseValueComponent, MXLookComponent, AXFocusableComponent, AXValuableComponent } from '@acorex/cdk/common';
|
|
2
2
|
import * as i1 from '@acorex/components/decorators';
|
|
3
3
|
import { AXDecoratorModule, AXDecoratorIconComponent } from '@acorex/components/decorators';
|
|
4
|
-
import { AXLoadingSpinnerComponent
|
|
4
|
+
import { AXLoadingSpinnerComponent } from '@acorex/components/loading';
|
|
5
|
+
import { AXTranslatorPipe } from '@acorex/core/translation';
|
|
6
|
+
import { isPlatformBrowser, AsyncPipe } from '@angular/common';
|
|
5
7
|
import * as i0 from '@angular/core';
|
|
6
|
-
import { signal, Injectable, input, inject, NgZone, ElementRef, viewChild, Renderer2, PLATFORM_ID, effect, afterNextRender, ViewEncapsulation, Component,
|
|
8
|
+
import { signal, Injectable, input, inject, NgZone, ElementRef, viewChild, Renderer2, PLATFORM_ID, effect, untracked, afterNextRender, ChangeDetectionStrategy, ViewEncapsulation, Component, DestroyRef, contentChild, forwardRef, output, computed, NgModule } from '@angular/core';
|
|
7
9
|
import * as i1$1 from '@angular/forms';
|
|
8
10
|
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
9
11
|
import { classes } from 'polytype';
|
|
10
|
-
import {
|
|
11
|
-
import { AXButtonComponent, AXButtonModule } from '@acorex/components/button';
|
|
12
|
+
import { AXButtonComponent } from '@acorex/components/button';
|
|
12
13
|
import * as i2 from '@acorex/components/tooltip';
|
|
13
14
|
import { AXTooltipModule, AXTooltipDirective } from '@acorex/components/tooltip';
|
|
14
|
-
import { AXTranslatorPipe } from '@acorex/core/translation';
|
|
15
15
|
import * as i2$1 from '@acorex/components/toolbar';
|
|
16
16
|
import { AXToolBarModule } from '@acorex/components/toolbar';
|
|
17
|
-
import { AXColorBoxComponent
|
|
18
|
-
import { AXRangeSliderComponent
|
|
19
|
-
import { AXDialogModule } from '@acorex/components/dialog';
|
|
20
|
-
import { AXPopoverModule } from '@acorex/components/popover';
|
|
21
|
-
import { AXSelectBoxModule } from '@acorex/components/select-box';
|
|
17
|
+
import { AXColorBoxComponent } from '@acorex/components/color-box';
|
|
18
|
+
import { AXRangeSliderComponent } from '@acorex/components/range-slider';
|
|
22
19
|
|
|
23
20
|
class AXImageEditorService {
|
|
24
21
|
constructor() {
|
|
@@ -38,6 +35,8 @@ class AXImageEditorService {
|
|
|
38
35
|
...(ngDevMode ? [{ debugName: "rotate" }] : /* istanbul ignore next */ []));
|
|
39
36
|
this.isImageLoad = signal(false, /* @ts-ignore */
|
|
40
37
|
...(ngDevMode ? [{ debugName: "isImageLoad" }] : /* istanbul ignore next */ []));
|
|
38
|
+
this.loadError = signal(false, /* @ts-ignore */
|
|
39
|
+
...(ngDevMode ? [{ debugName: "loadError" }] : /* istanbul ignore next */ []));
|
|
41
40
|
this.newImage = null;
|
|
42
41
|
this.initialImage = null;
|
|
43
42
|
this.imageBlob = signal([], /* @ts-ignore */
|
|
@@ -46,6 +45,10 @@ class AXImageEditorService {
|
|
|
46
45
|
...(ngDevMode ? [{ debugName: "undoPressed" }] : /* istanbul ignore next */ []));
|
|
47
46
|
this.redoPressed = signal(false, /* @ts-ignore */
|
|
48
47
|
...(ngDevMode ? [{ debugName: "redoPressed" }] : /* istanbul ignore next */ []));
|
|
48
|
+
this.canUndo = signal(false, /* @ts-ignore */
|
|
49
|
+
...(ngDevMode ? [{ debugName: "canUndo" }] : /* istanbul ignore next */ []));
|
|
50
|
+
this.canRedo = signal(false, /* @ts-ignore */
|
|
51
|
+
...(ngDevMode ? [{ debugName: "canRedo" }] : /* istanbul ignore next */ []));
|
|
49
52
|
this.cropperRatio = signal(null, /* @ts-ignore */
|
|
50
53
|
...(ngDevMode ? [{ debugName: "cropperRatio" }] : /* istanbul ignore next */ []));
|
|
51
54
|
this.cropperSize = signal(150, /* @ts-ignore */
|
|
@@ -54,6 +57,7 @@ class AXImageEditorService {
|
|
|
54
57
|
toggleTool(tool) {
|
|
55
58
|
if (this.activeToolState() === tool) {
|
|
56
59
|
this.activeToolState.set(null);
|
|
60
|
+
this.penType.set(null);
|
|
57
61
|
return;
|
|
58
62
|
}
|
|
59
63
|
this.activateTool(tool);
|
|
@@ -62,7 +66,21 @@ class AXImageEditorService {
|
|
|
62
66
|
this.activeToolState.set(tool);
|
|
63
67
|
if (tool === 'pen' || tool === 'highlight') {
|
|
64
68
|
this.penType.set(tool);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.penType.set(null);
|
|
72
|
+
}
|
|
73
|
+
undo() {
|
|
74
|
+
if (!this.canUndo()) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.undoPressed.set(true);
|
|
78
|
+
}
|
|
79
|
+
redo() {
|
|
80
|
+
if (!this.canRedo()) {
|
|
81
|
+
return;
|
|
65
82
|
}
|
|
83
|
+
this.redoPressed.set(true);
|
|
66
84
|
}
|
|
67
85
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
68
86
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorService }); }
|
|
@@ -91,63 +109,42 @@ class AXImageEditorCropperWindowComponent {
|
|
|
91
109
|
this.elementRef = inject(ElementRef);
|
|
92
110
|
this.cropperWindow = viewChild('r', /* @ts-ignore */
|
|
93
111
|
...(ngDevMode ? [{ debugName: "cropperWindow" }] : /* istanbul ignore next */ []));
|
|
94
|
-
this.currentX = signal(
|
|
112
|
+
this.currentX = signal(0, /* @ts-ignore */
|
|
95
113
|
...(ngDevMode ? [{ debugName: "currentX" }] : /* istanbul ignore next */ []));
|
|
96
|
-
this.currentY = signal(
|
|
114
|
+
this.currentY = signal(0, /* @ts-ignore */
|
|
97
115
|
...(ngDevMode ? [{ debugName: "currentY" }] : /* istanbul ignore next */ []));
|
|
98
|
-
this.
|
|
99
|
-
...(ngDevMode ? [{ debugName: "prevX" }] : /* istanbul ignore next */ []));
|
|
100
|
-
this.prevY = signal(0, /* @ts-ignore */
|
|
101
|
-
...(ngDevMode ? [{ debugName: "prevY" }] : /* istanbul ignore next */ []));
|
|
102
|
-
this.aspectWidth = signal(0, /* @ts-ignore */
|
|
116
|
+
this.aspectWidth = signal(1, /* @ts-ignore */
|
|
103
117
|
...(ngDevMode ? [{ debugName: "aspectWidth" }] : /* istanbul ignore next */ []));
|
|
104
|
-
this.aspectHeight = signal(
|
|
118
|
+
this.aspectHeight = signal(1, /* @ts-ignore */
|
|
105
119
|
...(ngDevMode ? [{ debugName: "aspectHeight" }] : /* istanbul ignore next */ []));
|
|
106
120
|
this.isMousePressed = signal(false, /* @ts-ignore */
|
|
107
121
|
...(ngDevMode ? [{ debugName: "isMousePressed" }] : /* istanbul ignore next */ []));
|
|
108
122
|
this.renderer = inject(Renderer2);
|
|
109
123
|
this.platformID = inject(PLATFORM_ID);
|
|
110
|
-
this
|
|
124
|
+
this.positioned = false;
|
|
125
|
+
this.#sizeEffect = effect(() => {
|
|
111
126
|
const host = this.elementRef.nativeElement;
|
|
112
|
-
let width;
|
|
113
|
-
let height;
|
|
114
127
|
const scale = this.size() ?? this.service.cropperSize();
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
default:
|
|
129
|
-
[width, height] = this.service.cropperRatio().split(':').map(Number);
|
|
130
|
-
}
|
|
131
|
-
if (width >= height) {
|
|
132
|
-
const aspect = width / height;
|
|
133
|
-
width = aspect;
|
|
134
|
-
height = 1;
|
|
135
|
-
this.aspectWidth.set(aspect);
|
|
136
|
-
this.aspectHeight.set(1);
|
|
128
|
+
const ratio = this.service.cropperRatio();
|
|
129
|
+
const { width, height } = this.normalizeRatio(ratio);
|
|
130
|
+
this.aspectWidth.set(width);
|
|
131
|
+
this.aspectHeight.set(height);
|
|
132
|
+
const parent = host.parentElement;
|
|
133
|
+
const maxW = parent?.clientWidth || scale * width;
|
|
134
|
+
const maxH = parent?.clientHeight || scale * height;
|
|
135
|
+
const nextWidth = Math.min(width * scale, maxW * 0.9);
|
|
136
|
+
const nextHeight = (nextWidth * height) / width;
|
|
137
|
+
host.style.width = `${Math.max(20, nextWidth)}px`;
|
|
138
|
+
host.style.height = `${Math.max(20, Math.min(nextHeight, maxH * 0.9))}px`;
|
|
139
|
+
if (this.positioned) {
|
|
140
|
+
untracked(() => this.clampToParent());
|
|
137
141
|
}
|
|
138
|
-
else {
|
|
139
|
-
const aspect = height / width;
|
|
140
|
-
width = 1;
|
|
141
|
-
height = aspect;
|
|
142
|
-
this.aspectWidth.set(1);
|
|
143
|
-
this.aspectHeight.set(aspect);
|
|
144
|
-
}
|
|
145
|
-
host.style.width = `${width * scale}px`;
|
|
146
|
-
host.style.height = `${height * scale}px`;
|
|
147
142
|
}, /* @ts-ignore */
|
|
148
|
-
...(ngDevMode ? [{ debugName: "#
|
|
143
|
+
...(ngDevMode ? [{ debugName: "#sizeEffect" }] : /* istanbul ignore next */ []));
|
|
149
144
|
this.#init = afterNextRender(() => {
|
|
150
145
|
const host = this.elementRef.nativeElement;
|
|
146
|
+
this.centerOnParent();
|
|
147
|
+
this.positioned = true;
|
|
151
148
|
this.ngZone.runOutsideAngular(() => {
|
|
152
149
|
this.mouseMoveEvent = this.renderer.listen(document, 'pointermove', this.changeSizeHandler.bind(this));
|
|
153
150
|
this.mouseUpEvent = this.renderer.listen(document, 'pointerup', this.clearSelector.bind(this));
|
|
@@ -156,34 +153,26 @@ class AXImageEditorCropperWindowComponent {
|
|
|
156
153
|
this.mouseUpEvent2 = this.renderer.listen(host, 'pointerup', this.panUp.bind(this));
|
|
157
154
|
});
|
|
158
155
|
});
|
|
159
|
-
this
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
156
|
+
this.startX = 0;
|
|
157
|
+
this.startY = 0;
|
|
158
|
+
this.startWidth = 0;
|
|
159
|
+
this.startHeight = 0;
|
|
160
|
+
this.startLeft = 0;
|
|
161
|
+
this.startTop = 0;
|
|
163
162
|
}
|
|
164
|
-
#
|
|
163
|
+
#sizeEffect;
|
|
165
164
|
#init;
|
|
166
165
|
ngOnDestroy() {
|
|
167
|
-
if (isPlatformBrowser(this.platformID)
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
if (isPlatformBrowser(this.platformID) && this.mouseUpEvent) {
|
|
171
|
-
this.mouseUpEvent();
|
|
172
|
-
}
|
|
173
|
-
if (isPlatformBrowser(this.platformID) && this.mouseDownEvent) {
|
|
174
|
-
this.mouseDownEvent();
|
|
175
|
-
}
|
|
176
|
-
if (isPlatformBrowser(this.platformID) && this.mouseMoveEvent2) {
|
|
177
|
-
this.mouseMoveEvent2();
|
|
178
|
-
}
|
|
179
|
-
if (isPlatformBrowser(this.platformID) && this.mouseUpEvent2) {
|
|
180
|
-
this.mouseUpEvent2();
|
|
181
|
-
}
|
|
182
|
-
if (isPlatformBrowser(this.platformID) && this.mouseLeaveEvent) {
|
|
183
|
-
this.mouseLeaveEvent();
|
|
166
|
+
if (!isPlatformBrowser(this.platformID)) {
|
|
167
|
+
return;
|
|
184
168
|
}
|
|
169
|
+
this.mouseMoveEvent?.();
|
|
170
|
+
this.mouseUpEvent?.();
|
|
171
|
+
this.mouseDownEvent?.();
|
|
172
|
+
this.mouseMoveEvent2?.();
|
|
173
|
+
this.mouseUpEvent2?.();
|
|
174
|
+
this.mouseLeaveEvent?.();
|
|
185
175
|
}
|
|
186
|
-
#positionChange;
|
|
187
176
|
panMove(e) {
|
|
188
177
|
if (!this.isMousePressed())
|
|
189
178
|
return;
|
|
@@ -191,39 +180,27 @@ class AXImageEditorCropperWindowComponent {
|
|
|
191
180
|
return;
|
|
192
181
|
if (!this.panState())
|
|
193
182
|
return;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const deltaY = currentY - this.prevY();
|
|
198
|
-
this.currentX.update((prev) => prev + deltaX);
|
|
199
|
-
this.currentY.update((prev) => prev + deltaY);
|
|
200
|
-
this.prevX.set(currentX);
|
|
201
|
-
this.prevY.set(currentY);
|
|
183
|
+
this.currentX.update((prev) => prev + e.movementX);
|
|
184
|
+
this.currentY.update((prev) => prev + e.movementY);
|
|
185
|
+
this.clampToParent();
|
|
202
186
|
}
|
|
203
187
|
panDown(e) {
|
|
204
|
-
this.isMousePressed.set(true);
|
|
205
188
|
if (this.selectedHandle())
|
|
206
189
|
return;
|
|
190
|
+
this.isMousePressed.set(true);
|
|
207
191
|
this.panState.set(true);
|
|
208
|
-
|
|
209
|
-
this.prevY.set(e.clientY);
|
|
192
|
+
e.currentTarget?.setPointerCapture?.(e.pointerId);
|
|
210
193
|
}
|
|
211
194
|
panUp() {
|
|
212
195
|
this.isMousePressed.set(false);
|
|
213
|
-
if (this.selectedHandle())
|
|
214
|
-
return;
|
|
215
196
|
this.panState.set(false);
|
|
216
197
|
}
|
|
217
198
|
getCropperArea() {
|
|
218
199
|
return this.elementRef.nativeElement.getBoundingClientRect();
|
|
219
200
|
}
|
|
220
|
-
setPosition(posX, posY) {
|
|
221
|
-
const el = this.elementRef.nativeElement;
|
|
222
|
-
el.style.transform = `translate(${posX}px, ${posY}px)`;
|
|
223
|
-
}
|
|
224
201
|
handleSelector(e, value) {
|
|
225
|
-
|
|
226
|
-
|
|
202
|
+
e.stopPropagation();
|
|
203
|
+
e.preventDefault();
|
|
227
204
|
const host = this.elementRef.nativeElement;
|
|
228
205
|
this.startX = e.clientX;
|
|
229
206
|
this.startY = e.clientY;
|
|
@@ -232,6 +209,8 @@ class AXImageEditorCropperWindowComponent {
|
|
|
232
209
|
this.startLeft = host.offsetLeft;
|
|
233
210
|
this.startTop = host.offsetTop;
|
|
234
211
|
this.selectedHandle.set(value);
|
|
212
|
+
this.isMousePressed.set(true);
|
|
213
|
+
e.currentTarget?.setPointerCapture?.(e.pointerId);
|
|
235
214
|
}
|
|
236
215
|
changeSizeHandler(e) {
|
|
237
216
|
if (!this.isMousePressed())
|
|
@@ -243,164 +222,176 @@ class AXImageEditorCropperWindowComponent {
|
|
|
243
222
|
const host = this.elementRef.nativeElement;
|
|
244
223
|
const dy = e.clientY - this.startY;
|
|
245
224
|
const dx = e.clientX - this.startX;
|
|
246
|
-
let newWidth;
|
|
247
|
-
let newHeight;
|
|
248
225
|
const minSize = 20;
|
|
226
|
+
const locked = !!this.service.cropperRatio();
|
|
227
|
+
const aspect = this.aspectWidth() / this.aspectHeight();
|
|
228
|
+
let width = this.startWidth;
|
|
229
|
+
let height = this.startHeight;
|
|
230
|
+
let left = this.startLeft;
|
|
231
|
+
let top = this.startTop;
|
|
249
232
|
switch (this.selectedHandle()) {
|
|
250
233
|
case 'right':
|
|
251
|
-
|
|
252
|
-
host.style.width = `${newWidth}px`;
|
|
234
|
+
width = Math.max(minSize, this.startWidth + dx);
|
|
253
235
|
break;
|
|
254
236
|
case 'top':
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
host.style.top = `${this.startTop + (this.startHeight - newHeight)}px`;
|
|
237
|
+
height = Math.max(minSize, this.startHeight - dy);
|
|
238
|
+
top = this.startTop + (this.startHeight - height);
|
|
258
239
|
break;
|
|
259
240
|
case 'left':
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
host.style.left = `${this.startLeft + (this.startWidth - newWidth)}px`;
|
|
241
|
+
width = Math.max(minSize, this.startWidth - dx);
|
|
242
|
+
left = this.startLeft + (this.startWidth - width);
|
|
263
243
|
break;
|
|
264
244
|
case 'bottom':
|
|
265
|
-
|
|
266
|
-
host.style.height = `${newHeight}px`;
|
|
245
|
+
height = Math.max(minSize, this.startHeight + dy);
|
|
267
246
|
break;
|
|
268
247
|
case 'right-top':
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
newWidth = (newHeight * this.aspectWidth()) / this.aspectHeight();
|
|
275
|
-
}
|
|
276
|
-
host.style.width = `${newWidth}px`;
|
|
277
|
-
host.style.height = `${newHeight}px`;
|
|
278
|
-
host.style.top = `${this.startTop + (this.startHeight - newHeight)}px`;
|
|
279
|
-
}
|
|
280
|
-
else {
|
|
281
|
-
newWidth = Math.max(minSize, this.startWidth + dx);
|
|
282
|
-
newHeight = Math.max(minSize, this.startHeight - dy);
|
|
283
|
-
host.style.width = `${newWidth}px`;
|
|
284
|
-
host.style.height = `${newHeight}px`;
|
|
285
|
-
host.style.top = `${this.startTop + (this.startHeight - newHeight)}px`;
|
|
248
|
+
width = Math.max(minSize, this.startWidth + dx);
|
|
249
|
+
height = locked ? width / aspect : Math.max(minSize, this.startHeight - dy);
|
|
250
|
+
if (locked && height < minSize) {
|
|
251
|
+
height = minSize;
|
|
252
|
+
width = height * aspect;
|
|
286
253
|
}
|
|
254
|
+
top = this.startTop + (this.startHeight - height);
|
|
287
255
|
break;
|
|
288
256
|
case 'bottom-right':
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
newWidth = (newHeight * this.aspectWidth()) / this.aspectHeight();
|
|
295
|
-
}
|
|
296
|
-
host.style.width = `${newWidth}px`;
|
|
297
|
-
host.style.height = `${newHeight}px`;
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
newWidth = Math.max(minSize, this.startWidth + dx);
|
|
301
|
-
newHeight = Math.max(minSize, this.startHeight + dy);
|
|
302
|
-
host.style.width = `${newWidth}px`;
|
|
303
|
-
host.style.height = `${newHeight}px`;
|
|
257
|
+
width = Math.max(minSize, this.startWidth + dx);
|
|
258
|
+
height = locked ? width / aspect : Math.max(minSize, this.startHeight + dy);
|
|
259
|
+
if (locked && height < minSize) {
|
|
260
|
+
height = minSize;
|
|
261
|
+
width = height * aspect;
|
|
304
262
|
}
|
|
305
263
|
break;
|
|
306
264
|
case 'bottom-left':
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
newWidth = (newHeight * this.aspectWidth()) / this.aspectHeight();
|
|
313
|
-
}
|
|
314
|
-
host.style.width = `${newWidth}px`;
|
|
315
|
-
host.style.height = `${newHeight}px`;
|
|
316
|
-
host.style.left = `${this.startLeft + (this.startWidth - newWidth)}px`;
|
|
317
|
-
}
|
|
318
|
-
else {
|
|
319
|
-
newWidth = Math.max(minSize, this.startWidth - dx);
|
|
320
|
-
newHeight = Math.max(minSize, this.startHeight + dy);
|
|
321
|
-
host.style.width = `${newWidth}px`;
|
|
322
|
-
host.style.height = `${newHeight}px`;
|
|
323
|
-
host.style.left = `${this.startLeft + (this.startWidth - newWidth)}px`;
|
|
265
|
+
width = Math.max(minSize, this.startWidth - dx);
|
|
266
|
+
height = locked ? width / aspect : Math.max(minSize, this.startHeight + dy);
|
|
267
|
+
if (locked && height < minSize) {
|
|
268
|
+
height = minSize;
|
|
269
|
+
width = height * aspect;
|
|
324
270
|
}
|
|
271
|
+
left = this.startLeft + (this.startWidth - width);
|
|
325
272
|
break;
|
|
326
273
|
case 'left-top':
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
newWidth = (newHeight * this.aspectWidth()) / this.aspectHeight();
|
|
333
|
-
}
|
|
334
|
-
host.style.width = `${newWidth}px`;
|
|
335
|
-
host.style.height = `${newHeight}px`;
|
|
336
|
-
host.style.left = `${this.startLeft + (this.startWidth - newWidth)}px`;
|
|
337
|
-
host.style.top = `${this.startTop + (this.startHeight - newHeight)}px`;
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
newWidth = Math.max(minSize, this.startWidth - dx);
|
|
341
|
-
newHeight = Math.max(minSize, this.startHeight - dy);
|
|
342
|
-
host.style.width = `${newWidth}px`;
|
|
343
|
-
host.style.height = `${newHeight}px`;
|
|
344
|
-
host.style.left = `${this.startLeft + (this.startWidth - newWidth)}px`;
|
|
345
|
-
host.style.top = `${this.startTop + (this.startHeight - newHeight)}px`;
|
|
274
|
+
width = Math.max(minSize, this.startWidth - dx);
|
|
275
|
+
height = locked ? width / aspect : Math.max(minSize, this.startHeight - dy);
|
|
276
|
+
if (locked && height < minSize) {
|
|
277
|
+
height = minSize;
|
|
278
|
+
width = height * aspect;
|
|
346
279
|
}
|
|
280
|
+
left = this.startLeft + (this.startWidth - width);
|
|
281
|
+
top = this.startTop + (this.startHeight - height);
|
|
347
282
|
break;
|
|
348
283
|
}
|
|
284
|
+
host.style.width = `${width}px`;
|
|
285
|
+
host.style.height = `${height}px`;
|
|
286
|
+
this.currentX.set(left);
|
|
287
|
+
this.currentY.set(top);
|
|
288
|
+
this.clampToParent();
|
|
349
289
|
}
|
|
350
290
|
clearSelector() {
|
|
351
|
-
if (this.panState())
|
|
352
|
-
return;
|
|
353
291
|
this.selectedHandle.set(null);
|
|
292
|
+
this.isMousePressed.set(false);
|
|
293
|
+
this.panState.set(false);
|
|
294
|
+
}
|
|
295
|
+
normalizeRatio(ratio) {
|
|
296
|
+
let width = 1;
|
|
297
|
+
let height = 1;
|
|
298
|
+
if (ratio && ratio.includes(':')) {
|
|
299
|
+
const [rawW, rawH] = ratio.split(':').map(Number);
|
|
300
|
+
if (rawW > 0 && rawH > 0) {
|
|
301
|
+
width = rawW;
|
|
302
|
+
height = rawH;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (width >= height) {
|
|
306
|
+
return { width: width / height, height: 1 };
|
|
307
|
+
}
|
|
308
|
+
return { width: 1, height: height / width };
|
|
309
|
+
}
|
|
310
|
+
centerOnParent() {
|
|
311
|
+
const host = this.elementRef.nativeElement;
|
|
312
|
+
const parent = host.parentElement;
|
|
313
|
+
if (!parent) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const left = Math.max(0, (parent.clientWidth - host.offsetWidth) / 2);
|
|
317
|
+
const top = Math.max(0, (parent.clientHeight - host.offsetHeight) / 2);
|
|
318
|
+
this.currentX.set(left);
|
|
319
|
+
this.currentY.set(top);
|
|
320
|
+
this.applyPosition();
|
|
321
|
+
}
|
|
322
|
+
clampToParent() {
|
|
323
|
+
const host = this.elementRef.nativeElement;
|
|
324
|
+
const parent = host.parentElement;
|
|
325
|
+
if (!parent) {
|
|
326
|
+
this.applyPosition();
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const maxX = Math.max(0, parent.clientWidth - host.offsetWidth);
|
|
330
|
+
const maxY = Math.max(0, parent.clientHeight - host.offsetHeight);
|
|
331
|
+
this.currentX.set(Math.min(Math.max(0, this.currentX()), maxX));
|
|
332
|
+
this.currentY.set(Math.min(Math.max(0, this.currentY()), maxY));
|
|
333
|
+
this.applyPosition();
|
|
334
|
+
}
|
|
335
|
+
applyPosition() {
|
|
336
|
+
const host = this.elementRef.nativeElement;
|
|
337
|
+
host.style.left = `${this.currentX()}px`;
|
|
338
|
+
host.style.top = `${this.currentY()}px`;
|
|
354
339
|
}
|
|
355
340
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorCropperWindowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
356
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXImageEditorCropperWindowComponent, isStandalone: true, selector: "ax-image-editor-cropper-window", inputs: { showGrid: { classPropertyName: "showGrid", publicName: "showGrid", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: AXComponent, useExisting: AXImageEditorCropperWindowComponent }], viewQueries: [{ propertyName: "cropperWindow", first: true, predicate: ["r"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [style.border]=\"!showGrid() ? '1px dashed white' : null\" #r class=\"ax-image-cropper-window-container\">\n @if (!service.cropperRatio()) {\n <div (pointerdown)=\"handleSelector($event, 'right')\" class=\"ax-image-right-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'top')\" class=\"ax-image-top-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'left')\" class=\"ax-image-left-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'bottom')\" class=\"ax-image-bottom-handle ax-handle-shape\"></div>\n }\n\n <div (pointerdown)=\"handleSelector($event, 'right-top')\" class=\"ax-image-right-top-handle ax-handle-shape\"></div>\n <div\n (pointerdown)=\"handleSelector($event, 'bottom-right')\"\n class=\"ax-image-bottom-right-handle ax-handle-shape\"\n ></div>\n <div (pointerdown)=\"handleSelector($event, 'bottom-left')\" class=\"ax-image-bottom-left-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'left-top')\" class=\"ax-image-left-top-handle ax-handle-shape\"></div>\n\n @if (showGrid()) {\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n }\n</div>\n", styles: ["@layer properties;@layer components{ax-image-editor-cropper-window{position:absolute;top:
|
|
341
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXImageEditorCropperWindowComponent, isStandalone: true, selector: "ax-image-editor-cropper-window", inputs: { showGrid: { classPropertyName: "showGrid", publicName: "showGrid", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: AXComponent, useExisting: AXImageEditorCropperWindowComponent }], viewQueries: [{ propertyName: "cropperWindow", first: true, predicate: ["r"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [style.border]=\"!showGrid() ? '1px dashed white' : null\" #r class=\"ax-image-cropper-window-container\">\n @if (!service.cropperRatio()) {\n <div (pointerdown)=\"handleSelector($event, 'right')\" class=\"ax-image-right-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'top')\" class=\"ax-image-top-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'left')\" class=\"ax-image-left-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'bottom')\" class=\"ax-image-bottom-handle ax-handle-shape\"></div>\n }\n\n <div (pointerdown)=\"handleSelector($event, 'right-top')\" class=\"ax-image-right-top-handle ax-handle-shape\"></div>\n <div\n (pointerdown)=\"handleSelector($event, 'bottom-right')\"\n class=\"ax-image-bottom-right-handle ax-handle-shape\"\n ></div>\n <div (pointerdown)=\"handleSelector($event, 'bottom-left')\" class=\"ax-image-bottom-left-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'left-top')\" class=\"ax-image-left-top-handle ax-handle-shape\"></div>\n\n @if (showGrid()) {\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n }\n</div>\n", styles: ["@layer properties;@layer components{ax-image-editor-cropper-window{position:absolute;top:calc(var(--spacing, .25rem) * 0);left:calc(var(--spacing, .25rem) * 0);touch-action:none;-webkit-user-select:none;user-select:none}ax-image-editor-cropper-window .ax-image-cropper-window-container{position:relative;display:grid;height:100%;cursor:move;grid-template-columns:repeat(3,minmax(0,1fr));outline-style:var(--tw-outline-style);outline-width:100vmax;outline-color:color-mix(in srgb,#000 70%,transparent);--tw-outline-style: solid;outline-style:solid}@supports (color: color-mix(in lab,red,red)){ax-image-editor-cropper-window .ax-image-cropper-window-container{outline-color:color-mix(in oklab,var(--color-black, #000) 70%,transparent)}}ax-image-editor-cropper-window .ax-image-cropper-window-container .ax-grid-item{border-style:var(--tw-border-style);border-width:1px;--tw-border-style: dashed;border-style:dashed;border-color:color-mix(in srgb,#fff 50%,transparent)}@supports (color: color-mix(in lab,red,red)){ax-image-editor-cropper-window .ax-image-cropper-window-container .ax-grid-item{border-color:color-mix(in oklab,var(--color-white, #fff) 50%,transparent)}}ax-image-editor-cropper-window .ax-handle-shape{position:absolute;height:calc(var(--spacing, .25rem) * 4);width:calc(var(--spacing, .25rem) * 4);border-style:var(--tw-border-style);border-width:1px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-white, #fff);background-color:var(--color-gray-500, oklch(55.1% .027 264.364));-webkit-user-select:none;user-select:none}ax-image-editor-cropper-window .ax-image-right-top-handle{top:calc(var(--spacing, .25rem) * -2);right:calc(var(--spacing, .25rem) * -2);cursor:ne-resize}ax-image-editor-cropper-window .ax-image-bottom-right-handle{right:calc(var(--spacing, .25rem) * -2);bottom:calc(var(--spacing, .25rem) * -2);cursor:se-resize}ax-image-editor-cropper-window .ax-image-right-handle{top:calc(50% - .5rem);right:calc(var(--spacing, .25rem) * -2);cursor:e-resize}ax-image-editor-cropper-window .ax-image-bottom-left-handle{bottom:calc(var(--spacing, .25rem) * -2);left:calc(var(--spacing, .25rem) * -2);cursor:sw-resize}ax-image-editor-cropper-window .ax-image-left-top-handle{top:calc(var(--spacing, .25rem) * -2);left:calc(var(--spacing, .25rem) * -2);cursor:nw-resize}ax-image-editor-cropper-window .ax-image-bottom-handle{right:calc(50% - .5rem);bottom:calc(var(--spacing, .25rem) * -2);cursor:s-resize}ax-image-editor-cropper-window .ax-image-left-handle{top:calc(50% - .5rem);left:calc(var(--spacing, .25rem) * -2);cursor:w-resize}ax-image-editor-cropper-window .ax-image-top-handle{top:calc(var(--spacing, .25rem) * -2);right:calc(50% - .5rem);cursor:n-resize}}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-outline-style: solid;--tw-border-style: solid}}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
357
342
|
}
|
|
358
343
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorCropperWindowComponent, decorators: [{
|
|
359
344
|
type: Component,
|
|
360
|
-
args: [{ selector: 'ax-image-editor-cropper-window', encapsulation: ViewEncapsulation.None, providers: [{ provide: AXComponent, useExisting: AXImageEditorCropperWindowComponent }], template: "<div [style.border]=\"!showGrid() ? '1px dashed white' : null\" #r class=\"ax-image-cropper-window-container\">\n @if (!service.cropperRatio()) {\n <div (pointerdown)=\"handleSelector($event, 'right')\" class=\"ax-image-right-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'top')\" class=\"ax-image-top-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'left')\" class=\"ax-image-left-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'bottom')\" class=\"ax-image-bottom-handle ax-handle-shape\"></div>\n }\n\n <div (pointerdown)=\"handleSelector($event, 'right-top')\" class=\"ax-image-right-top-handle ax-handle-shape\"></div>\n <div\n (pointerdown)=\"handleSelector($event, 'bottom-right')\"\n class=\"ax-image-bottom-right-handle ax-handle-shape\"\n ></div>\n <div (pointerdown)=\"handleSelector($event, 'bottom-left')\" class=\"ax-image-bottom-left-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'left-top')\" class=\"ax-image-left-top-handle ax-handle-shape\"></div>\n\n @if (showGrid()) {\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n }\n</div>\n", styles: ["@layer properties;@layer components{ax-image-editor-cropper-window{position:absolute;top:
|
|
345
|
+
args: [{ selector: 'ax-image-editor-cropper-window', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: AXComponent, useExisting: AXImageEditorCropperWindowComponent }], template: "<div [style.border]=\"!showGrid() ? '1px dashed white' : null\" #r class=\"ax-image-cropper-window-container\">\n @if (!service.cropperRatio()) {\n <div (pointerdown)=\"handleSelector($event, 'right')\" class=\"ax-image-right-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'top')\" class=\"ax-image-top-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'left')\" class=\"ax-image-left-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'bottom')\" class=\"ax-image-bottom-handle ax-handle-shape\"></div>\n }\n\n <div (pointerdown)=\"handleSelector($event, 'right-top')\" class=\"ax-image-right-top-handle ax-handle-shape\"></div>\n <div\n (pointerdown)=\"handleSelector($event, 'bottom-right')\"\n class=\"ax-image-bottom-right-handle ax-handle-shape\"\n ></div>\n <div (pointerdown)=\"handleSelector($event, 'bottom-left')\" class=\"ax-image-bottom-left-handle ax-handle-shape\"></div>\n <div (pointerdown)=\"handleSelector($event, 'left-top')\" class=\"ax-image-left-top-handle ax-handle-shape\"></div>\n\n @if (showGrid()) {\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n <div class=\"ax-grid-item\"></div>\n }\n</div>\n", styles: ["@layer properties;@layer components{ax-image-editor-cropper-window{position:absolute;top:calc(var(--spacing, .25rem) * 0);left:calc(var(--spacing, .25rem) * 0);touch-action:none;-webkit-user-select:none;user-select:none}ax-image-editor-cropper-window .ax-image-cropper-window-container{position:relative;display:grid;height:100%;cursor:move;grid-template-columns:repeat(3,minmax(0,1fr));outline-style:var(--tw-outline-style);outline-width:100vmax;outline-color:color-mix(in srgb,#000 70%,transparent);--tw-outline-style: solid;outline-style:solid}@supports (color: color-mix(in lab,red,red)){ax-image-editor-cropper-window .ax-image-cropper-window-container{outline-color:color-mix(in oklab,var(--color-black, #000) 70%,transparent)}}ax-image-editor-cropper-window .ax-image-cropper-window-container .ax-grid-item{border-style:var(--tw-border-style);border-width:1px;--tw-border-style: dashed;border-style:dashed;border-color:color-mix(in srgb,#fff 50%,transparent)}@supports (color: color-mix(in lab,red,red)){ax-image-editor-cropper-window .ax-image-cropper-window-container .ax-grid-item{border-color:color-mix(in oklab,var(--color-white, #fff) 50%,transparent)}}ax-image-editor-cropper-window .ax-handle-shape{position:absolute;height:calc(var(--spacing, .25rem) * 4);width:calc(var(--spacing, .25rem) * 4);border-style:var(--tw-border-style);border-width:1px;--tw-border-style: dashed;border-style:dashed;border-color:var(--color-white, #fff);background-color:var(--color-gray-500, oklch(55.1% .027 264.364));-webkit-user-select:none;user-select:none}ax-image-editor-cropper-window .ax-image-right-top-handle{top:calc(var(--spacing, .25rem) * -2);right:calc(var(--spacing, .25rem) * -2);cursor:ne-resize}ax-image-editor-cropper-window .ax-image-bottom-right-handle{right:calc(var(--spacing, .25rem) * -2);bottom:calc(var(--spacing, .25rem) * -2);cursor:se-resize}ax-image-editor-cropper-window .ax-image-right-handle{top:calc(50% - .5rem);right:calc(var(--spacing, .25rem) * -2);cursor:e-resize}ax-image-editor-cropper-window .ax-image-bottom-left-handle{bottom:calc(var(--spacing, .25rem) * -2);left:calc(var(--spacing, .25rem) * -2);cursor:sw-resize}ax-image-editor-cropper-window .ax-image-left-top-handle{top:calc(var(--spacing, .25rem) * -2);left:calc(var(--spacing, .25rem) * -2);cursor:nw-resize}ax-image-editor-cropper-window .ax-image-bottom-handle{right:calc(50% - .5rem);bottom:calc(var(--spacing, .25rem) * -2);cursor:s-resize}ax-image-editor-cropper-window .ax-image-left-handle{top:calc(50% - .5rem);left:calc(var(--spacing, .25rem) * -2);cursor:w-resize}ax-image-editor-cropper-window .ax-image-top-handle{top:calc(var(--spacing, .25rem) * -2);right:calc(50% - .5rem);cursor:n-resize}}@property --tw-outline-style{syntax: \"*\"; inherits: false; initial-value: solid;}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-outline-style: solid;--tw-border-style: solid}}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"] }]
|
|
361
346
|
}], propDecorators: { showGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGrid", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], cropperWindow: [{ type: i0.ViewChild, args: ['r', { isSignal: true }] }] } });
|
|
362
347
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const imageWidth = image.width;
|
|
371
|
-
const imageHeight = image.height;
|
|
372
|
-
this.originalWidth.set(imageWidth);
|
|
373
|
-
this.originalHeight.set(imageHeight);
|
|
374
|
-
if (imageWidth > imageHeight) {
|
|
375
|
-
this.canvasElem().nativeElement.width = imageWidth;
|
|
376
|
-
this.canvasElem().nativeElement.height = imageWidth;
|
|
377
|
-
}
|
|
378
|
-
else {
|
|
379
|
-
this.canvasElem().nativeElement.width = imageHeight;
|
|
380
|
-
this.canvasElem().nativeElement.height = imageHeight;
|
|
348
|
+
const IMAGE_EDITOR_MAX_BUFFER = 4096;
|
|
349
|
+
const IMAGE_EDITOR_EXPORT_QUALITY = 1;
|
|
350
|
+
function loadHtmlImage(src) {
|
|
351
|
+
return new Promise((resolve, reject) => {
|
|
352
|
+
const image = new Image();
|
|
353
|
+
if (!src.startsWith('data:') && !src.startsWith('blob:')) {
|
|
354
|
+
image.crossOrigin = 'anonymous';
|
|
381
355
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
this.canvasElem().nativeElement.width = recalculateWidth;
|
|
394
|
-
this.canvasElem().nativeElement.height = recalculateWidth;
|
|
395
|
-
if (imageWidth > imageHeight) {
|
|
396
|
-
this.ctx().drawImage(image, 0, recalculateWidth / 2 - this.originalHeight() / scale / 2, recalculateWidth, this.originalHeight() / scale);
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
this.ctx().drawImage(image, recalculateWidth / 2 - this.originalWidth() / scale / 2, 0, this.originalWidth() / scale, recalculateWidth);
|
|
356
|
+
image.onload = () => resolve(image);
|
|
357
|
+
image.onerror = () => reject(new Error('Failed to load image'));
|
|
358
|
+
image.src = src;
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
function canvasToBlob(canvas, type, quality) {
|
|
362
|
+
return new Promise((resolve, reject) => {
|
|
363
|
+
canvas.toBlob((blob) => {
|
|
364
|
+
if (blob) {
|
|
365
|
+
resolve(blob);
|
|
366
|
+
return;
|
|
400
367
|
}
|
|
401
|
-
|
|
368
|
+
reject(new Error(`toBlob returned null for type ${type}`));
|
|
369
|
+
}, type, quality);
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
async function canvasToEditorBlobs(canvas) {
|
|
373
|
+
const jpeg = await canvasToBlob(canvas, 'image/jpeg', IMAGE_EDITOR_EXPORT_QUALITY);
|
|
374
|
+
const extra = await Promise.allSettled([
|
|
375
|
+
canvasToBlob(canvas, 'image/png'),
|
|
376
|
+
canvasToBlob(canvas, 'image/webp', IMAGE_EDITOR_EXPORT_QUALITY),
|
|
377
|
+
]);
|
|
378
|
+
const blobs = [jpeg];
|
|
379
|
+
for (const result of extra) {
|
|
380
|
+
if (result.status === 'fulfilled') {
|
|
381
|
+
blobs.push(result.value);
|
|
382
|
+
}
|
|
402
383
|
}
|
|
403
|
-
|
|
384
|
+
return blobs;
|
|
385
|
+
}
|
|
386
|
+
function bufferSizeForImage(width, height, max = IMAGE_EDITOR_MAX_BUFFER) {
|
|
387
|
+
const scale = Math.min(1, max / Math.max(width, height, 1));
|
|
388
|
+
return {
|
|
389
|
+
width: Math.max(1, Math.round(width * scale)),
|
|
390
|
+
height: Math.max(1, Math.round(height * scale)),
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
class AXImageEditorViewComponent extends MXBaseComponent {
|
|
404
395
|
constructor() {
|
|
405
396
|
super();
|
|
406
397
|
/**
|
|
@@ -442,44 +433,80 @@ class AXImageEditorViewComponent extends MXBaseComponent {
|
|
|
442
433
|
...(ngDevMode ? [{ debugName: "isDrawRectangleCreated" }] : /* istanbul ignore next */ []));
|
|
443
434
|
/** @ignore */
|
|
444
435
|
this.parent = inject(AXImageEditorContainerComponent);
|
|
445
|
-
|
|
446
|
-
this.
|
|
436
|
+
this.destroyRef = inject(DestroyRef);
|
|
437
|
+
this.host = inject((ElementRef));
|
|
447
438
|
/** @ignore */
|
|
448
439
|
this.imageEditorHistory = signal([], /* @ts-ignore */
|
|
449
440
|
...(ngDevMode ? [{ debugName: "imageEditorHistory" }] : /* istanbul ignore next */ []));
|
|
450
441
|
/** @ignore */
|
|
451
|
-
this.imageEditorHistoryPointer =
|
|
442
|
+
this.imageEditorHistoryPointer = signal(-1, /* @ts-ignore */
|
|
452
443
|
...(ngDevMode ? [{ debugName: "imageEditorHistoryPointer" }] : /* istanbul ignore next */ []));
|
|
453
|
-
this.
|
|
454
|
-
...(ngDevMode ? [{ debugName: "
|
|
455
|
-
this.
|
|
456
|
-
|
|
457
|
-
this.
|
|
458
|
-
|
|
444
|
+
this.canvasReady = signal(false, /* @ts-ignore */
|
|
445
|
+
...(ngDevMode ? [{ debugName: "canvasReady" }] : /* istanbul ignore next */ []));
|
|
446
|
+
this.drawing = false;
|
|
447
|
+
this.didDraw = false;
|
|
448
|
+
this.highlightSnapshot = null;
|
|
449
|
+
this.highlightPoints = [];
|
|
450
|
+
this.persistGeneration = 0;
|
|
451
|
+
this.sourceToken = 0;
|
|
459
452
|
afterNextRender(() => {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
453
|
+
const canvas = this.canvasElem()?.nativeElement;
|
|
454
|
+
if (!canvas) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
const ctx = canvas.getContext('2d', { willReadFrequently: true });
|
|
458
|
+
if (!ctx) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
ctx.lineJoin = 'round';
|
|
462
|
+
ctx.lineCap = 'round';
|
|
463
|
+
this.ctx.set(ctx);
|
|
464
|
+
this.canvasReady.set(true);
|
|
465
|
+
const onResize = () => this.fitCanvasDisplay();
|
|
466
|
+
window.addEventListener('resize', onResize);
|
|
467
|
+
this.destroyRef.onDestroy(() => window.removeEventListener('resize', onResize));
|
|
465
468
|
});
|
|
466
469
|
effect(() => {
|
|
467
|
-
this.
|
|
470
|
+
const src = this.src();
|
|
471
|
+
const ready = this.canvasReady();
|
|
472
|
+
if (!ready) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
untracked(() => void this.loadSource(src));
|
|
468
476
|
});
|
|
469
477
|
effect(() => {
|
|
470
478
|
if (!this.service.undoPressed()) {
|
|
471
|
-
|
|
479
|
+
return;
|
|
472
480
|
}
|
|
481
|
+
untracked(() => {
|
|
482
|
+
this.applyUndo();
|
|
483
|
+
this.service.undoPressed.set(false);
|
|
484
|
+
});
|
|
473
485
|
});
|
|
474
486
|
effect(() => {
|
|
475
487
|
if (!this.service.redoPressed()) {
|
|
476
|
-
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
untracked(() => {
|
|
491
|
+
this.applyRedo();
|
|
492
|
+
this.service.redoPressed.set(false);
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
effect(() => {
|
|
496
|
+
const rotate = this.service.rotate();
|
|
497
|
+
const ctx = this.ctx();
|
|
498
|
+
if (!rotate.userInteract || !ctx) {
|
|
499
|
+
return;
|
|
477
500
|
}
|
|
501
|
+
untracked(() => void this.rotateImage());
|
|
478
502
|
});
|
|
479
503
|
effect(() => {
|
|
480
|
-
if (!this.service.
|
|
504
|
+
if (!this.service.isImageLoad()) {
|
|
481
505
|
return;
|
|
482
|
-
|
|
506
|
+
}
|
|
507
|
+
untracked(() => {
|
|
508
|
+
requestAnimationFrame(() => this.fitCanvasDisplay());
|
|
509
|
+
});
|
|
483
510
|
});
|
|
484
511
|
effect(() => {
|
|
485
512
|
const size = this.cropperSize();
|
|
@@ -489,167 +516,351 @@ class AXImageEditorViewComponent extends MXBaseComponent {
|
|
|
489
516
|
});
|
|
490
517
|
}
|
|
491
518
|
/** @ignore */
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
this.resizeEventListener();
|
|
495
|
-
}
|
|
496
|
-
if (this.imageLoadEventListener) {
|
|
497
|
-
this.imageLoadEventListener();
|
|
498
|
-
}
|
|
519
|
+
resizeWindow() {
|
|
520
|
+
this.fitCanvasDisplay();
|
|
499
521
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
this.
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
522
|
+
/** @ignore */
|
|
523
|
+
canvasResponsive(image) {
|
|
524
|
+
this.paintImage(image);
|
|
525
|
+
}
|
|
526
|
+
async loadSource(src) {
|
|
527
|
+
const token = ++this.sourceToken;
|
|
528
|
+
this.service.loadError.set(false);
|
|
529
|
+
this.service.isImageLoad.set(false);
|
|
530
|
+
this.service.imageBlob.set([]);
|
|
531
|
+
this.service.newImage = null;
|
|
532
|
+
this.service.initialImage = null;
|
|
533
|
+
if (!src) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
try {
|
|
537
|
+
const image = await loadHtmlImage(src);
|
|
538
|
+
if (token !== this.sourceToken) {
|
|
539
|
+
return;
|
|
510
540
|
}
|
|
511
|
-
|
|
512
|
-
|
|
541
|
+
this.service.initialImage = image;
|
|
542
|
+
this.service.newImage = image;
|
|
543
|
+
this.replaceHistory(image);
|
|
544
|
+
this.paintImage(image);
|
|
545
|
+
this.service.isImageLoad.set(true);
|
|
546
|
+
}
|
|
547
|
+
catch {
|
|
548
|
+
if (token !== this.sourceToken) {
|
|
549
|
+
return;
|
|
513
550
|
}
|
|
514
|
-
|
|
551
|
+
this.service.loadError.set(true);
|
|
552
|
+
this.service.isImageLoad.set(false);
|
|
553
|
+
}
|
|
515
554
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
this.canvasResponsive(this.imageEditorHistory()[this.imageEditorHistoryPointer()]);
|
|
555
|
+
paintImage(image) {
|
|
556
|
+
const canvas = this.canvasElem()?.nativeElement;
|
|
557
|
+
const ctx = this.ctx();
|
|
558
|
+
if (!canvas || !ctx || !image) {
|
|
559
|
+
return;
|
|
522
560
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
561
|
+
const buffer = bufferSizeForImage(image.naturalWidth || image.width, image.naturalHeight || image.height);
|
|
562
|
+
canvas.width = buffer.width;
|
|
563
|
+
canvas.height = buffer.height;
|
|
564
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
565
|
+
ctx.globalAlpha = 1;
|
|
566
|
+
ctx.globalCompositeOperation = 'source-over';
|
|
567
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
568
|
+
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
569
|
+
this.fitCanvasDisplay();
|
|
570
|
+
}
|
|
571
|
+
fitCanvasDisplay() {
|
|
572
|
+
const canvas = this.canvasElem()?.nativeElement;
|
|
573
|
+
if (!canvas?.width || !canvas.height) {
|
|
574
|
+
return;
|
|
527
575
|
}
|
|
528
|
-
this.
|
|
529
|
-
|
|
576
|
+
const parent = this.host.nativeElement;
|
|
577
|
+
const maxW = Math.max(parent?.clientWidth || 0, 240);
|
|
578
|
+
const maxH = Math.min(window.innerHeight * 0.55, 560);
|
|
579
|
+
const scale = Math.min(maxW / canvas.width, maxH / canvas.height, 1);
|
|
580
|
+
canvas.style.width = `${Math.max(1, Math.round(canvas.width * scale))}px`;
|
|
581
|
+
canvas.style.height = `${Math.max(1, Math.round(canvas.height * scale))}px`;
|
|
582
|
+
}
|
|
583
|
+
replaceHistory(image) {
|
|
584
|
+
this.imageEditorHistory.set([image]);
|
|
585
|
+
this.imageEditorHistoryPointer.set(0);
|
|
586
|
+
this.syncHistoryFlags();
|
|
587
|
+
}
|
|
588
|
+
pushHistory(image) {
|
|
589
|
+
const pointer = this.imageEditorHistoryPointer();
|
|
590
|
+
const next = this.imageEditorHistory().slice(0, pointer + 1);
|
|
591
|
+
next.push(image);
|
|
592
|
+
this.imageEditorHistory.set(next);
|
|
593
|
+
this.imageEditorHistoryPointer.set(next.length - 1);
|
|
594
|
+
this.syncHistoryFlags();
|
|
595
|
+
}
|
|
596
|
+
syncHistoryFlags() {
|
|
597
|
+
const pointer = this.imageEditorHistoryPointer();
|
|
598
|
+
const length = this.imageEditorHistory().length;
|
|
599
|
+
this.service.canUndo.set(pointer > 0);
|
|
600
|
+
this.service.canRedo.set(pointer >= 0 && pointer < length - 1);
|
|
601
|
+
}
|
|
602
|
+
applyUndo() {
|
|
603
|
+
const pointer = this.imageEditorHistoryPointer();
|
|
604
|
+
if (pointer < 1) {
|
|
605
|
+
this.syncHistoryFlags();
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
const nextPointer = pointer - 1;
|
|
609
|
+
const image = this.imageEditorHistory()[nextPointer];
|
|
610
|
+
this.imageEditorHistoryPointer.set(nextPointer);
|
|
611
|
+
this.service.newImage = image;
|
|
612
|
+
this.paintImage(image);
|
|
613
|
+
this.syncHistoryFlags();
|
|
614
|
+
void this.persistCanvas({ skipHistory: true });
|
|
615
|
+
}
|
|
616
|
+
applyRedo() {
|
|
617
|
+
const history = this.imageEditorHistory();
|
|
618
|
+
const pointer = this.imageEditorHistoryPointer();
|
|
619
|
+
if (pointer >= history.length - 1) {
|
|
620
|
+
this.syncHistoryFlags();
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
const nextPointer = pointer + 1;
|
|
624
|
+
const image = history[nextPointer];
|
|
625
|
+
this.imageEditorHistoryPointer.set(nextPointer);
|
|
626
|
+
this.service.newImage = image;
|
|
627
|
+
this.paintImage(image);
|
|
628
|
+
this.syncHistoryFlags();
|
|
629
|
+
void this.persistCanvas({ skipHistory: true });
|
|
630
|
+
}
|
|
631
|
+
canvasPoint(event) {
|
|
632
|
+
const canvas = this.canvasElem().nativeElement;
|
|
633
|
+
const rect = canvas.getBoundingClientRect();
|
|
634
|
+
const width = rect.width || 1;
|
|
635
|
+
const height = rect.height || 1;
|
|
636
|
+
return {
|
|
637
|
+
x: ((event.clientX - rect.left) / width) * canvas.width,
|
|
638
|
+
y: ((event.clientY - rect.top) / height) * canvas.height,
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
isDrawTool() {
|
|
642
|
+
const tool = this.service.penType();
|
|
643
|
+
return tool === 'pen' || tool === 'highlight';
|
|
530
644
|
}
|
|
531
645
|
/** @ignore */
|
|
532
646
|
penConfigHandler(penType) {
|
|
647
|
+
const ctx = this.ctx();
|
|
648
|
+
if (!ctx) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
ctx.lineJoin = 'round';
|
|
652
|
+
ctx.lineCap = 'round';
|
|
533
653
|
switch (penType) {
|
|
534
654
|
case 'pen':
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
655
|
+
ctx.globalAlpha = 1;
|
|
656
|
+
ctx.globalCompositeOperation = 'source-over';
|
|
657
|
+
ctx.strokeStyle = this.service.penColor();
|
|
658
|
+
ctx.lineWidth = this.service.penWidth();
|
|
538
659
|
break;
|
|
539
660
|
case 'highlight':
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
661
|
+
ctx.globalAlpha = 0.4;
|
|
662
|
+
ctx.globalCompositeOperation = 'multiply';
|
|
663
|
+
ctx.strokeStyle = this.service.highlightColor();
|
|
664
|
+
ctx.lineWidth = this.service.highlightWidth();
|
|
543
665
|
break;
|
|
544
666
|
}
|
|
545
667
|
}
|
|
668
|
+
strokeHighlight(points) {
|
|
669
|
+
const ctx = this.ctx();
|
|
670
|
+
if (!ctx || points.length === 0) {
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
this.penConfigHandler('highlight');
|
|
674
|
+
ctx.beginPath();
|
|
675
|
+
ctx.moveTo(points[0].x, points[0].y);
|
|
676
|
+
for (let i = 1; i < points.length; i++) {
|
|
677
|
+
ctx.lineTo(points[i].x, points[i].y);
|
|
678
|
+
}
|
|
679
|
+
if (points.length === 1) {
|
|
680
|
+
ctx.lineTo(points[0].x, points[0].y);
|
|
681
|
+
}
|
|
682
|
+
ctx.stroke();
|
|
683
|
+
}
|
|
546
684
|
/** @ignore */
|
|
547
|
-
mouseDownHandler(
|
|
548
|
-
this.
|
|
549
|
-
|
|
685
|
+
mouseDownHandler(event) {
|
|
686
|
+
if (!this.isDrawTool() || this.parent.disabled) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
const ctx = this.ctx();
|
|
690
|
+
const canvas = this.canvasElem()?.nativeElement;
|
|
691
|
+
const penType = this.service.penType();
|
|
692
|
+
if (!ctx || !canvas || !penType) {
|
|
550
693
|
return;
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
this.
|
|
555
|
-
this.
|
|
694
|
+
}
|
|
695
|
+
event.preventDefault();
|
|
696
|
+
canvas.setPointerCapture(event.pointerId);
|
|
697
|
+
this.isMouseDown.set(true);
|
|
698
|
+
this.drawing = true;
|
|
699
|
+
this.didDraw = false;
|
|
700
|
+
const point = this.canvasPoint(event);
|
|
701
|
+
this.penConfigHandler(penType);
|
|
702
|
+
if (penType === 'highlight') {
|
|
703
|
+
this.highlightSnapshot = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
704
|
+
this.highlightPoints = [point];
|
|
705
|
+
this.strokeHighlight(this.highlightPoints);
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
ctx.beginPath();
|
|
709
|
+
ctx.moveTo(point.x, point.y);
|
|
710
|
+
ctx.lineTo(point.x, point.y);
|
|
711
|
+
ctx.stroke();
|
|
712
|
+
}
|
|
713
|
+
this.didDraw = true;
|
|
556
714
|
}
|
|
557
715
|
/** @ignore */
|
|
558
|
-
mouseMoveHandler(
|
|
559
|
-
if (!this.
|
|
716
|
+
mouseMoveHandler(event) {
|
|
717
|
+
if (!this.drawing || !this.isDrawTool()) {
|
|
560
718
|
return;
|
|
561
|
-
|
|
719
|
+
}
|
|
720
|
+
const ctx = this.ctx();
|
|
721
|
+
const canvas = this.canvasElem()?.nativeElement;
|
|
722
|
+
const penType = this.service.penType();
|
|
723
|
+
if (!ctx || !canvas || !penType) {
|
|
562
724
|
return;
|
|
563
|
-
|
|
564
|
-
this.
|
|
725
|
+
}
|
|
726
|
+
const point = this.canvasPoint(event);
|
|
727
|
+
if (penType === 'highlight' && this.highlightSnapshot) {
|
|
728
|
+
ctx.putImageData(this.highlightSnapshot, 0, 0);
|
|
729
|
+
this.highlightPoints.push(point);
|
|
730
|
+
this.strokeHighlight(this.highlightPoints);
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
ctx.lineTo(point.x, point.y);
|
|
734
|
+
ctx.stroke();
|
|
735
|
+
}
|
|
736
|
+
this.didDraw = true;
|
|
565
737
|
}
|
|
566
738
|
/** @ignore */
|
|
567
|
-
mouseUpHandler() {
|
|
739
|
+
mouseUpHandler(event) {
|
|
740
|
+
const canvas = this.canvasElem()?.nativeElement;
|
|
741
|
+
if (event && canvas?.hasPointerCapture(event.pointerId)) {
|
|
742
|
+
canvas.releasePointerCapture(event.pointerId);
|
|
743
|
+
}
|
|
744
|
+
const wasDrawing = this.drawing && this.didDraw;
|
|
745
|
+
this.drawing = false;
|
|
746
|
+
this.didDraw = false;
|
|
568
747
|
this.isMouseDown.set(false);
|
|
569
|
-
this.
|
|
570
|
-
this.
|
|
748
|
+
this.highlightSnapshot = null;
|
|
749
|
+
this.highlightPoints = [];
|
|
750
|
+
const ctx = this.ctx();
|
|
751
|
+
if (ctx) {
|
|
752
|
+
ctx.closePath();
|
|
753
|
+
ctx.globalAlpha = 1;
|
|
754
|
+
ctx.globalCompositeOperation = 'source-over';
|
|
755
|
+
}
|
|
756
|
+
if (wasDrawing) {
|
|
757
|
+
void this.persistCanvas();
|
|
758
|
+
}
|
|
571
759
|
}
|
|
572
|
-
/**
|
|
760
|
+
/** Applies the current cropper selection. */
|
|
573
761
|
async crop() {
|
|
574
762
|
const cropper = this.cropperWindow();
|
|
575
|
-
|
|
763
|
+
const ctx = this.ctx();
|
|
764
|
+
const canvas = this.canvasElem()?.nativeElement;
|
|
765
|
+
if (this.service.activeToolState() !== 'crop' || !cropper || !ctx || !canvas) {
|
|
576
766
|
return;
|
|
577
767
|
}
|
|
578
768
|
const cropRect = cropper.getCropperArea();
|
|
579
|
-
const canvas = this.canvasElem().nativeElement;
|
|
580
769
|
const canvasRect = canvas.getBoundingClientRect();
|
|
581
|
-
const scaleX = canvas.width / canvasRect.width;
|
|
582
|
-
const scaleY = canvas.height / canvasRect.height;
|
|
583
|
-
const dx = (cropRect.x - canvasRect.x) * scaleX;
|
|
584
|
-
const dy = (cropRect.y - canvasRect.y) * scaleY;
|
|
585
|
-
const cropWidth = cropRect.width * scaleX;
|
|
586
|
-
const cropHeight = cropRect.height * scaleY;
|
|
587
|
-
const
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
this.
|
|
770
|
+
const scaleX = canvas.width / (canvasRect.width || 1);
|
|
771
|
+
const scaleY = canvas.height / (canvasRect.height || 1);
|
|
772
|
+
const dx = Math.max(0, Math.round((cropRect.x - canvasRect.x) * scaleX));
|
|
773
|
+
const dy = Math.max(0, Math.round((cropRect.y - canvasRect.y) * scaleY));
|
|
774
|
+
const cropWidth = Math.max(1, Math.round(cropRect.width * scaleX));
|
|
775
|
+
const cropHeight = Math.max(1, Math.round(cropRect.height * scaleY));
|
|
776
|
+
const width = Math.min(cropWidth, canvas.width - dx);
|
|
777
|
+
const height = Math.min(cropHeight, canvas.height - dy);
|
|
778
|
+
const imageData = ctx.getImageData(dx, dy, width, height);
|
|
779
|
+
canvas.width = width;
|
|
780
|
+
canvas.height = height;
|
|
781
|
+
ctx.putImageData(imageData, 0, 0);
|
|
782
|
+
this.fitCanvasDisplay();
|
|
594
783
|
this.service.activeToolState.set(null);
|
|
784
|
+
this.service.penType.set(null);
|
|
785
|
+
await this.persistCanvas();
|
|
595
786
|
}
|
|
596
|
-
/**
|
|
597
|
-
|
|
598
|
-
this.
|
|
599
|
-
this.
|
|
600
|
-
this.ctx().clearRect(0, 0, this.canvasElem().nativeElement.width, this.canvasElem().nativeElement.height);
|
|
601
|
-
// Calculate scale factor to fit rotated image within canvas
|
|
602
|
-
const rotationAngle = (this.service.rotate().state * Math.PI) / 180;
|
|
603
|
-
const cos = Math.abs(Math.cos(rotationAngle));
|
|
604
|
-
const sin = Math.abs(Math.sin(rotationAngle));
|
|
605
|
-
const rotatedWidth = this.service.newImage.width * cos + this.service.newImage.height * sin;
|
|
606
|
-
const rotatedHeight = this.service.newImage.width * sin + this.service.newImage.height * cos;
|
|
607
|
-
const scaleX = this.canvasElem().nativeElement.width / rotatedWidth;
|
|
608
|
-
const scaleY = this.canvasElem().nativeElement.height / rotatedHeight;
|
|
609
|
-
const scale = Math.min(scaleX, scaleY);
|
|
610
|
-
this.ctx().translate(this.canvasElem().nativeElement.width / 2, this.canvasElem().nativeElement.height / 2);
|
|
611
|
-
this.ctx().rotate(rotationAngle);
|
|
612
|
-
this.ctx().scale(scale, scale);
|
|
613
|
-
this.ctx().drawImage(this.service.newImage, -this.service.newImage.width / 2, -this.service.newImage.height / 2);
|
|
614
|
-
this.ctx().restore();
|
|
615
|
-
this.saveImageChange();
|
|
616
|
-
this.service.rotate.update((prev) => {
|
|
617
|
-
return { state: prev.state, userInteract: false };
|
|
618
|
-
});
|
|
787
|
+
/** Encodes the current canvas into JPEG, PNG, and WebP blobs. */
|
|
788
|
+
async commitChanges() {
|
|
789
|
+
await this.persistCanvas();
|
|
790
|
+
return this.service.imageBlob();
|
|
619
791
|
}
|
|
620
792
|
/** @ignore */
|
|
621
|
-
async
|
|
622
|
-
const canvas = this.canvasElem()
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
const
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
793
|
+
async rotateImage() {
|
|
794
|
+
const canvas = this.canvasElem()?.nativeElement;
|
|
795
|
+
const ctx = this.ctx();
|
|
796
|
+
if (!canvas || !ctx || !canvas.width || !canvas.height) {
|
|
797
|
+
this.service.rotate.update((prev) => ({ state: prev.state, userInteract: false }));
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const source = document.createElement('canvas');
|
|
801
|
+
source.width = canvas.width;
|
|
802
|
+
source.height = canvas.height;
|
|
803
|
+
const sourceCtx = source.getContext('2d');
|
|
804
|
+
if (!sourceCtx) {
|
|
805
|
+
this.service.rotate.update((prev) => ({ state: prev.state, userInteract: false }));
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
sourceCtx.drawImage(canvas, 0, 0);
|
|
809
|
+
const degrees = this.service.rotate().state;
|
|
810
|
+
const radians = (degrees * Math.PI) / 180;
|
|
811
|
+
const cos = Math.abs(Math.cos(radians));
|
|
812
|
+
const sin = Math.abs(Math.sin(radians));
|
|
813
|
+
const rotatedWidth = Math.max(1, Math.round(source.width * cos + source.height * sin));
|
|
814
|
+
const rotatedHeight = Math.max(1, Math.round(source.width * sin + source.height * cos));
|
|
815
|
+
canvas.width = rotatedWidth;
|
|
816
|
+
canvas.height = rotatedHeight;
|
|
817
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
818
|
+
ctx.globalAlpha = 1;
|
|
819
|
+
ctx.globalCompositeOperation = 'source-over';
|
|
820
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
821
|
+
ctx.save();
|
|
822
|
+
ctx.translate(canvas.width / 2, canvas.height / 2);
|
|
823
|
+
ctx.rotate(radians);
|
|
824
|
+
ctx.drawImage(source, -source.width / 2, -source.height / 2);
|
|
825
|
+
ctx.restore();
|
|
826
|
+
this.fitCanvasDisplay();
|
|
827
|
+
await this.persistCanvas();
|
|
828
|
+
this.service.rotate.update((prev) => ({ state: prev.state, userInteract: false }));
|
|
829
|
+
}
|
|
830
|
+
async persistCanvas(options) {
|
|
831
|
+
const canvas = this.canvasElem()?.nativeElement;
|
|
832
|
+
if (!canvas?.width || !canvas.height) {
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
const generation = ++this.persistGeneration;
|
|
836
|
+
try {
|
|
837
|
+
const blobs = await canvasToEditorBlobs(canvas);
|
|
838
|
+
if (generation !== this.persistGeneration) {
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
this.service.imageBlob.set(blobs);
|
|
842
|
+
const dataUrl = canvas.toDataURL('image/jpeg', 1);
|
|
843
|
+
const image = await loadHtmlImage(dataUrl);
|
|
844
|
+
if (generation !== this.persistGeneration) {
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
this.service.newImage = image;
|
|
848
|
+
if (!options?.skipHistory) {
|
|
849
|
+
this.pushHistory(image);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
catch {
|
|
853
|
+
if (generation !== this.persistGeneration) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
646
857
|
}
|
|
647
858
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
648
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXImageEditorViewComponent, isStandalone: true, selector: "ax-image-editor-view", inputs: { showGrid: { classPropertyName: "showGrid", publicName: "showGrid", isSignal: true, isRequired: false, transformFunction: null }, cropperSize: { classPropertyName: "cropperSize", publicName: "cropperSize", isSignal: true, isRequired: false, transformFunction: null }, src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: AXComponent, useExisting: AXImageEditorViewComponent }], viewQueries: [{ propertyName: "canvasElem", first: true, predicate: ["canvasElem"], descendants: true, isSignal: true }, { propertyName: "cropperWindow", first: true, predicate: ["f"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<canvas\n
|
|
859
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXImageEditorViewComponent, isStandalone: true, selector: "ax-image-editor-view", inputs: { showGrid: { classPropertyName: "showGrid", publicName: "showGrid", isSignal: true, isRequired: false, transformFunction: null }, cropperSize: { classPropertyName: "cropperSize", publicName: "cropperSize", isSignal: true, isRequired: false, transformFunction: null }, src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: AXComponent, useExisting: AXImageEditorViewComponent }], viewQueries: [{ propertyName: "canvasElem", first: true, predicate: ["canvasElem"], descendants: true, isSignal: true }, { propertyName: "cropperWindow", first: true, predicate: ["f"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-image-editor-stage\">\n <canvas\n tabindex=\"0\"\n (pointerdown)=\"mouseDownHandler($event)\"\n (pointerup)=\"mouseUpHandler($event)\"\n (pointercancel)=\"mouseUpHandler($event)\"\n (pointermove)=\"mouseMoveHandler($event)\"\n class=\"ax-canvas-element\"\n #canvasElem\n ></canvas>\n\n @if (service.activeToolState() === 'crop') {\n <ax-image-editor-cropper-window [showGrid]=\"showGrid()\" #f></ax-image-editor-cropper-window>\n }\n</div>\n", styles: ["@layer components{ax-image-editor-view{position:relative;display:flex;width:100%;touch-action:none;align-items:center;justify-content:center;overflow:hidden;background-color:var(--color-white, #fff)}ax-image-editor-view .ax-image-editor-stage{position:relative;display:inline-flex;max-height:100%;max-width:100%;align-items:center;justify-content:center}ax-image-editor-view .ax-canvas-element{max-height:100%;max-width:100%;cursor:crosshair;background-color:var(--color-black, #000);touch-action:none}ax-image-editor-view .ax-crop-save{position:absolute;top:calc(var(--spacing, .25rem) * 0);right:calc(var(--spacing, .25rem) * 0);margin:calc(var(--spacing, .25rem) * 4)}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: AXImageEditorCropperWindowComponent, selector: "ax-image-editor-cropper-window", inputs: ["showGrid", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
649
860
|
}
|
|
650
861
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorViewComponent, decorators: [{
|
|
651
862
|
type: Component,
|
|
652
|
-
args: [{ selector: 'ax-image-editor-view', encapsulation: ViewEncapsulation.None, imports: [AXImageEditorCropperWindowComponent], providers: [{ provide: AXComponent, useExisting: AXImageEditorViewComponent }], template: "<canvas\n
|
|
863
|
+
args: [{ selector: 'ax-image-editor-view', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [AXImageEditorCropperWindowComponent], providers: [{ provide: AXComponent, useExisting: AXImageEditorViewComponent }], template: "<div class=\"ax-image-editor-stage\">\n <canvas\n tabindex=\"0\"\n (pointerdown)=\"mouseDownHandler($event)\"\n (pointerup)=\"mouseUpHandler($event)\"\n (pointercancel)=\"mouseUpHandler($event)\"\n (pointermove)=\"mouseMoveHandler($event)\"\n class=\"ax-canvas-element\"\n #canvasElem\n ></canvas>\n\n @if (service.activeToolState() === 'crop') {\n <ax-image-editor-cropper-window [showGrid]=\"showGrid()\" #f></ax-image-editor-cropper-window>\n }\n</div>\n", styles: ["@layer components{ax-image-editor-view{position:relative;display:flex;width:100%;touch-action:none;align-items:center;justify-content:center;overflow:hidden;background-color:var(--color-white, #fff)}ax-image-editor-view .ax-image-editor-stage{position:relative;display:inline-flex;max-height:100%;max-width:100%;align-items:center;justify-content:center}ax-image-editor-view .ax-canvas-element{max-height:100%;max-width:100%;cursor:crosshair;background-color:var(--color-black, #000);touch-action:none}ax-image-editor-view .ax-crop-save{position:absolute;top:calc(var(--spacing, .25rem) * 0);right:calc(var(--spacing, .25rem) * 0);margin:calc(var(--spacing, .25rem) * 4)}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"] }]
|
|
653
864
|
}], ctorParameters: () => [], propDecorators: { showGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGrid", required: false }] }], cropperSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperSize", required: false }] }], src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], canvasElem: [{ type: i0.ViewChild, args: ['canvasElem', { isSignal: true }] }], cropperWindow: [{ type: i0.ViewChild, args: ['f', { isSignal: true }] }] } });
|
|
654
865
|
|
|
655
866
|
/**
|
|
@@ -665,18 +876,18 @@ class AXImageEditorContainerComponent extends classes((MXInputBaseValueComponent
|
|
|
665
876
|
...(ngDevMode ? [{ debugName: "imageEditorContainer" }] : /* istanbul ignore next */ []));
|
|
666
877
|
this.view = contentChild(AXImageEditorViewComponent, /* @ts-ignore */
|
|
667
878
|
...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
|
|
668
|
-
this.#
|
|
669
|
-
|
|
670
|
-
if (
|
|
671
|
-
this.commitValue(
|
|
879
|
+
this.#syncValue = effect(() => {
|
|
880
|
+
const blobs = this.service.imageBlob();
|
|
881
|
+
if (blobs.length) {
|
|
882
|
+
this.commitValue(blobs, true);
|
|
672
883
|
}
|
|
673
884
|
else {
|
|
674
885
|
this.commitValue(null);
|
|
675
886
|
}
|
|
676
887
|
}, /* @ts-ignore */
|
|
677
|
-
...(ngDevMode ? [{ debugName: "#
|
|
888
|
+
...(ngDevMode ? [{ debugName: "#syncValue" }] : /* istanbul ignore next */ []));
|
|
678
889
|
}
|
|
679
|
-
#
|
|
890
|
+
#syncValue;
|
|
680
891
|
/** Applies the current cropper selection. */
|
|
681
892
|
async crop() {
|
|
682
893
|
const oldValue = this.value;
|
|
@@ -686,16 +897,19 @@ class AXImageEditorContainerComponent extends classes((MXInputBaseValueComponent
|
|
|
686
897
|
this.commitValue(blobs, true);
|
|
687
898
|
}
|
|
688
899
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
900
|
+
/** Encodes the current canvas into JPEG, PNG, and WebP blobs. */
|
|
901
|
+
async commitChanges() {
|
|
902
|
+
const view = this.view();
|
|
903
|
+
if (!view) {
|
|
904
|
+
return this.service.imageBlob();
|
|
905
|
+
}
|
|
906
|
+
if (this.service.activeToolState() === 'crop') {
|
|
907
|
+
await view.crop();
|
|
908
|
+
}
|
|
909
|
+
return view.commitChanges();
|
|
696
910
|
}
|
|
697
911
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorContainerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
698
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXImageEditorContainerComponent, isStandalone: true, selector: "ax-image-editor-container", inputs: { look: "look", disabled: "disabled" }, outputs: { onValueChanged: "onValueChanged" }, host: { properties: { "class": "
|
|
912
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXImageEditorContainerComponent, isStandalone: true, selector: "ax-image-editor-container", inputs: { look: "look", disabled: "disabled" }, outputs: { onValueChanged: "onValueChanged" }, host: { properties: { "class.ax-state-disabled": "disabled", "attr.name": "name" } }, providers: [
|
|
699
913
|
AXImageEditorService,
|
|
700
914
|
{ provide: AXComponent, useExisting: AXImageEditorContainerComponent },
|
|
701
915
|
{ provide: AXFocusableComponent, useExisting: AXImageEditorContainerComponent },
|
|
@@ -705,11 +919,14 @@ class AXImageEditorContainerComponent extends classes((MXInputBaseValueComponent
|
|
|
705
919
|
useExisting: forwardRef(() => AXImageEditorContainerComponent),
|
|
706
920
|
multi: true,
|
|
707
921
|
},
|
|
708
|
-
], queries: [{ propertyName: "view", first: true, predicate: AXImageEditorViewComponent, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "imageEditorContainer", first: true, predicate: ["f"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "
|
|
922
|
+
], queries: [{ propertyName: "view", first: true, predicate: AXImageEditorViewComponent, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "imageEditorContainer", first: true, predicate: ["f"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div #f class=\"ax-editor-container ax-default {{ look }}\" [class.ax-image-editor-pending]=\"!service.isImageLoad()\">\n <ng-content select=\"ax-header\"></ng-content>\n\n <ng-content select=\"ax-image-editor-view\"> </ng-content>\n\n <ng-content select=\"ax-footer\"></ng-content>\n</div>\n\n@if (!service.isImageLoad()) {\n @if (service.loadError()) {\n <div class=\"ax-error-container\">{{ '@acorex:image-editor.load-error' | translate | async }}</div>\n } @else {\n <div class=\"ax-loading-spinner-container\">\n <ax-loading-spinner\n [size]=\"16\"\n color=\"primary\"\n [text]=\"('@acorex:image-editor.loading' | translate | async) || ''\"\n ></ax-loading-spinner>\n </div>\n }\n}\n\n<div class=\"ax-error-container\"></div>\n<ng-content select=\"ax-validation-rule\"> </ng-content>\n\n@if (disabled) {\n <div class=\"ax-disable-overlay\"></div>\n}\n", styles: ["@layer components{ax-image-editor-container{position:relative;display:block;width:fit-content}ax-image-editor-container.ax-state-disabled{opacity:50%}ax-image-editor-container .ax-disable-overlay{position:absolute;top:calc(var(--spacing, .25rem) * 0);left:calc(var(--spacing, .25rem) * 0);height:100%;width:100%;cursor:not-allowed}ax-image-editor-container>.ax-editor-container{display:block;height:auto!important;padding:calc(var(--spacing, .25rem) * 0)}ax-image-editor-container>.ax-editor-container.ax-image-editor-pending{position:absolute;height:calc(var(--spacing, .25rem) * 0);width:calc(var(--spacing, .25rem) * 0);overflow:hidden;opacity:0%}ax-image-editor-container .ax-loading-spinner-container,ax-image-editor-container .ax-error-container{display:flex;min-height:calc(var(--spacing, .25rem) * 40);align-items:center;justify-content:center;padding-inline:calc(var(--spacing, .25rem) * 4);text-align:center}ax-image-editor-container ax-footer{width:100%}ax-image-editor-container ax-header{width:100%}ax-image-editor-container ax-header ax-toolbar{justify-content:space-between}ax-image-editor-container ax-header .ax-start-toolbar-divider{display:none}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: AXLoadingSpinnerComponent, selector: "ax-loading-spinner", inputs: ["text", "color", "size", "stroke"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
709
923
|
}
|
|
710
924
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorContainerComponent, decorators: [{
|
|
711
925
|
type: Component,
|
|
712
|
-
args: [{ selector: 'ax-image-editor-container', encapsulation: ViewEncapsulation.None, outputs: ['onValueChanged'], inputs: ['look', 'disabled'],
|
|
926
|
+
args: [{ selector: 'ax-image-editor-container', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, outputs: ['onValueChanged'], inputs: ['look', 'disabled'], host: {
|
|
927
|
+
'[class.ax-state-disabled]': 'disabled',
|
|
928
|
+
'[attr.name]': 'name',
|
|
929
|
+
}, providers: [
|
|
713
930
|
AXImageEditorService,
|
|
714
931
|
{ provide: AXComponent, useExisting: AXImageEditorContainerComponent },
|
|
715
932
|
{ provide: AXFocusableComponent, useExisting: AXImageEditorContainerComponent },
|
|
@@ -719,14 +936,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
719
936
|
useExisting: forwardRef(() => AXImageEditorContainerComponent),
|
|
720
937
|
multi: true,
|
|
721
938
|
},
|
|
722
|
-
], imports: [AXDecoratorModule, AXLoadingSpinnerComponent], template: "
|
|
723
|
-
}], propDecorators: { imageEditorContainer: [{ type: i0.ViewChild, args: ['f', { isSignal: true }] }], view: [{ type: i0.ContentChild, args: [i0.forwardRef(() => AXImageEditorViewComponent), { isSignal: true }] }]
|
|
724
|
-
type: HostBinding,
|
|
725
|
-
args: ['class']
|
|
726
|
-
}], __hostName: [{
|
|
727
|
-
type: HostBinding,
|
|
728
|
-
args: ['attr.name']
|
|
729
|
-
}] } });
|
|
939
|
+
], imports: [AXDecoratorModule, AXLoadingSpinnerComponent, AsyncPipe, AXTranslatorPipe], template: "<div #f class=\"ax-editor-container ax-default {{ look }}\" [class.ax-image-editor-pending]=\"!service.isImageLoad()\">\n <ng-content select=\"ax-header\"></ng-content>\n\n <ng-content select=\"ax-image-editor-view\"> </ng-content>\n\n <ng-content select=\"ax-footer\"></ng-content>\n</div>\n\n@if (!service.isImageLoad()) {\n @if (service.loadError()) {\n <div class=\"ax-error-container\">{{ '@acorex:image-editor.load-error' | translate | async }}</div>\n } @else {\n <div class=\"ax-loading-spinner-container\">\n <ax-loading-spinner\n [size]=\"16\"\n color=\"primary\"\n [text]=\"('@acorex:image-editor.loading' | translate | async) || ''\"\n ></ax-loading-spinner>\n </div>\n }\n}\n\n<div class=\"ax-error-container\"></div>\n<ng-content select=\"ax-validation-rule\"> </ng-content>\n\n@if (disabled) {\n <div class=\"ax-disable-overlay\"></div>\n}\n", styles: ["@layer components{ax-image-editor-container{position:relative;display:block;width:fit-content}ax-image-editor-container.ax-state-disabled{opacity:50%}ax-image-editor-container .ax-disable-overlay{position:absolute;top:calc(var(--spacing, .25rem) * 0);left:calc(var(--spacing, .25rem) * 0);height:100%;width:100%;cursor:not-allowed}ax-image-editor-container>.ax-editor-container{display:block;height:auto!important;padding:calc(var(--spacing, .25rem) * 0)}ax-image-editor-container>.ax-editor-container.ax-image-editor-pending{position:absolute;height:calc(var(--spacing, .25rem) * 0);width:calc(var(--spacing, .25rem) * 0);overflow:hidden;opacity:0%}ax-image-editor-container .ax-loading-spinner-container,ax-image-editor-container .ax-error-container{display:flex;min-height:calc(var(--spacing, .25rem) * 40);align-items:center;justify-content:center;padding-inline:calc(var(--spacing, .25rem) * 4);text-align:center}ax-image-editor-container ax-footer{width:100%}ax-image-editor-container ax-header{width:100%}ax-image-editor-container ax-header ax-toolbar{justify-content:space-between}ax-image-editor-container ax-header .ax-start-toolbar-divider{display:none}}\n/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */\n"] }]
|
|
940
|
+
}], propDecorators: { imageEditorContainer: [{ type: i0.ViewChild, args: ['f', { isSignal: true }] }], view: [{ type: i0.ContentChild, args: [i0.forwardRef(() => AXImageEditorViewComponent), { isSignal: true }] }] } });
|
|
730
941
|
|
|
731
942
|
const IMAGE_EDITOR_ASPECT_RATIO_ACTIVE_SUFFIX = ':active';
|
|
732
943
|
function parseAspectRatioItem(item) {
|
|
@@ -834,17 +1045,17 @@ class AXImageEditorHistoryComponent {
|
|
|
834
1045
|
this.service = inject(AXImageEditorService);
|
|
835
1046
|
}
|
|
836
1047
|
UndoHandler() {
|
|
837
|
-
this.service.
|
|
1048
|
+
this.service.undo();
|
|
838
1049
|
}
|
|
839
1050
|
RedoHandler() {
|
|
840
|
-
this.service.
|
|
1051
|
+
this.service.redo();
|
|
841
1052
|
}
|
|
842
1053
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorHistoryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
843
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.8", type: AXImageEditorHistoryComponent, isStandalone: true, selector: "ax-image-editor-history", providers: [{ provide: AXComponent, useExisting: AXImageEditorHistoryComponent }], ngImport: i0, template: "<div class=\"flex\">\n <ax-button\n class=\"ax-sm\"\n [axTooltip]=\"'@acorex:image-editor.undo' | translate | async\"\n axTooltipPlacement=\"top\"\n (onClick)=\"UndoHandler()\"\n look=\"blank\"\n >\n <ax-icon class=\"ax-icon ax-icon-undo\"></ax-icon>\n </ax-button>\n\n <ax-button\n class=\"ax-sm\"\n [axTooltip]=\"'@acorex:image-editor.redo' | translate | async\"\n axTooltipPlacement=\"top\"\n (onClick)=\"RedoHandler()\"\n look=\"blank\"\n >\n <ax-icon class=\"ax-icon ax-icon-redo\"></ax-icon>\n </ax-button>\n</div>\n", dependencies: [{ kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "directive", type: AXTooltipDirective, selector: "[axTooltip]", inputs: ["axTooltipDisabled", "axTooltip", "axTooltipContext", "axTooltipPlacement", "axTooltipOffsetX", "axTooltipOffsetY", "axTooltipOpenAfter", "axTooltipCloseAfter"] }, { kind: "ngmodule", type: AXTooltipModule }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
1054
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.8", type: AXImageEditorHistoryComponent, isStandalone: true, selector: "ax-image-editor-history", providers: [{ provide: AXComponent, useExisting: AXImageEditorHistoryComponent }], ngImport: i0, template: "<div class=\"flex\">\n <ax-button\n class=\"ax-sm\"\n [axTooltip]=\"'@acorex:image-editor.undo' | translate | async\"\n axTooltipPlacement=\"top\"\n (onClick)=\"UndoHandler()\"\n look=\"blank\"\n [disabled]=\"!service.canUndo()\"\n >\n <ax-icon class=\"ax-icon ax-icon-undo\"></ax-icon>\n </ax-button>\n\n <ax-button\n class=\"ax-sm\"\n [axTooltip]=\"'@acorex:image-editor.redo' | translate | async\"\n axTooltipPlacement=\"top\"\n (onClick)=\"RedoHandler()\"\n look=\"blank\"\n [disabled]=\"!service.canRedo()\"\n >\n <ax-icon class=\"ax-icon ax-icon-redo\"></ax-icon>\n </ax-button>\n</div>\n", dependencies: [{ kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "directive", type: AXTooltipDirective, selector: "[axTooltip]", inputs: ["axTooltipDisabled", "axTooltip", "axTooltipContext", "axTooltipPlacement", "axTooltipOffsetX", "axTooltipOffsetY", "axTooltipOpenAfter", "axTooltipCloseAfter"] }, { kind: "ngmodule", type: AXTooltipModule }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
844
1055
|
}
|
|
845
1056
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorHistoryComponent, decorators: [{
|
|
846
1057
|
type: Component,
|
|
847
|
-
args: [{ selector: 'ax-image-editor-history', encapsulation: ViewEncapsulation.None, imports: [AXButtonComponent, AXDecoratorModule, AXTooltipDirective, AsyncPipe, AXTranslatorPipe, AXTooltipModule], providers: [{ provide: AXComponent, useExisting: AXImageEditorHistoryComponent }], template: "<div class=\"flex\">\n <ax-button\n class=\"ax-sm\"\n [axTooltip]=\"'@acorex:image-editor.undo' | translate | async\"\n axTooltipPlacement=\"top\"\n (onClick)=\"UndoHandler()\"\n look=\"blank\"\n >\n <ax-icon class=\"ax-icon ax-icon-undo\"></ax-icon>\n </ax-button>\n\n <ax-button\n class=\"ax-sm\"\n [axTooltip]=\"'@acorex:image-editor.redo' | translate | async\"\n axTooltipPlacement=\"top\"\n (onClick)=\"RedoHandler()\"\n look=\"blank\"\n >\n <ax-icon class=\"ax-icon ax-icon-redo\"></ax-icon>\n </ax-button>\n</div>\n" }]
|
|
1058
|
+
args: [{ selector: 'ax-image-editor-history', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [AXButtonComponent, AXDecoratorModule, AXTooltipDirective, AsyncPipe, AXTranslatorPipe, AXTooltipModule], providers: [{ provide: AXComponent, useExisting: AXImageEditorHistoryComponent }], template: "<div class=\"flex\">\n <ax-button\n class=\"ax-sm\"\n [axTooltip]=\"'@acorex:image-editor.undo' | translate | async\"\n axTooltipPlacement=\"top\"\n (onClick)=\"UndoHandler()\"\n look=\"blank\"\n [disabled]=\"!service.canUndo()\"\n >\n <ax-icon class=\"ax-icon ax-icon-undo\"></ax-icon>\n </ax-button>\n\n <ax-button\n class=\"ax-sm\"\n [axTooltip]=\"'@acorex:image-editor.redo' | translate | async\"\n axTooltipPlacement=\"top\"\n (onClick)=\"RedoHandler()\"\n look=\"blank\"\n [disabled]=\"!service.canRedo()\"\n >\n <ax-icon class=\"ax-icon ax-icon-redo\"></ax-icon>\n </ax-button>\n</div>\n" }]
|
|
848
1059
|
}] });
|
|
849
1060
|
|
|
850
1061
|
/**
|
|
@@ -1061,7 +1272,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
1061
1272
|
], providers: [{ provide: AXComponent, useExisting: AXImageEditorToolSelectorComponent }], template: "<ax-image-editor-tools-bar>\n <ax-image-editor-pen></ax-image-editor-pen>\n <ax-image-editor-highlight></ax-image-editor-highlight>\n <ax-image-editor-crop [aspectRatio]=\"aspectRatio()\"></ax-image-editor-crop>\n <ax-image-editor-rotate></ax-image-editor-rotate>\n</ax-image-editor-tools-bar>\n" }]
|
|
1062
1273
|
}], propDecorators: { aspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "aspectRatio", required: false }] }] } });
|
|
1063
1274
|
|
|
1064
|
-
const
|
|
1275
|
+
const PUBLIC_COMPONENTS = [
|
|
1065
1276
|
AXImageEditorViewComponent,
|
|
1066
1277
|
AXImageEditorContainerComponent,
|
|
1067
1278
|
AXImageEditorCropComponent,
|
|
@@ -1073,28 +1284,9 @@ const COMPONENT = [
|
|
|
1073
1284
|
AXImageEditorRotateComponent,
|
|
1074
1285
|
AXImageEditorCropperWindowComponent,
|
|
1075
1286
|
];
|
|
1076
|
-
const MODULES = [
|
|
1077
|
-
AXButtonModule,
|
|
1078
|
-
FormsModule,
|
|
1079
|
-
AXRangeSliderModule,
|
|
1080
|
-
AXSelectBoxModule,
|
|
1081
|
-
AXColorBoxModule,
|
|
1082
|
-
AXPopoverModule,
|
|
1083
|
-
AXDecoratorModule,
|
|
1084
|
-
AXLoadingModule,
|
|
1085
|
-
AXDialogModule,
|
|
1086
|
-
];
|
|
1087
1287
|
class AXImageEditorModule {
|
|
1088
1288
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1089
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorModule, imports: [
|
|
1090
|
-
FormsModule,
|
|
1091
|
-
AXRangeSliderModule,
|
|
1092
|
-
AXSelectBoxModule,
|
|
1093
|
-
AXColorBoxModule,
|
|
1094
|
-
AXPopoverModule,
|
|
1095
|
-
AXDecoratorModule,
|
|
1096
|
-
AXLoadingModule,
|
|
1097
|
-
AXDialogModule, AXImageEditorViewComponent,
|
|
1289
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorModule, imports: [AXImageEditorViewComponent,
|
|
1098
1290
|
AXImageEditorContainerComponent,
|
|
1099
1291
|
AXImageEditorCropComponent,
|
|
1100
1292
|
AXImageEditorHistoryComponent,
|
|
@@ -1113,7 +1305,7 @@ class AXImageEditorModule {
|
|
|
1113
1305
|
AXImageEditorHighlightComponent,
|
|
1114
1306
|
AXImageEditorRotateComponent,
|
|
1115
1307
|
AXImageEditorCropperWindowComponent] }); }
|
|
1116
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorModule, imports: [
|
|
1308
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorModule, imports: [AXImageEditorContainerComponent,
|
|
1117
1309
|
AXImageEditorCropComponent,
|
|
1118
1310
|
AXImageEditorHistoryComponent,
|
|
1119
1311
|
AXImageEditorToolSelectorComponent,
|
|
@@ -1125,9 +1317,8 @@ class AXImageEditorModule {
|
|
|
1125
1317
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXImageEditorModule, decorators: [{
|
|
1126
1318
|
type: NgModule,
|
|
1127
1319
|
args: [{
|
|
1128
|
-
imports: [...
|
|
1129
|
-
exports: [...
|
|
1130
|
-
providers: [],
|
|
1320
|
+
imports: [...PUBLIC_COMPONENTS],
|
|
1321
|
+
exports: [...PUBLIC_COMPONENTS],
|
|
1131
1322
|
}]
|
|
1132
1323
|
}] });
|
|
1133
1324
|
|