@rangertechnologies/ngnxt
Version:
This library was used for creating dymanic UI based on the input JSON/data
562 lines • 95.6 kB
JavaScript
import { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, HostListener, Input, Output, signal, ViewChild } from '@angular/core';
import { CropperState } from './cropper.state';
import { MoveTypes } from '../interfaces/move-start.interface';
import { CropService } from '../services/crop.service';
import { LoadImageService } from '../services/load-image.service';
import { getEventForKey, getInvertedPositionForKey, getPositionForKey } from '../utils/keyboard.utils';
import { first, takeUntil } from 'rxjs/operators';
import { fromEvent, merge, Subject } from 'rxjs';
import { NgIf } from '@angular/common';
import { checkCropperPosition, checkCropperWithinMaxSizeBounds, getClientX, getClientY, moveCropper, resizeCropper } from '../utils/cropper-position.utils';
import * as i0 from "@angular/core";
import * as i1 from "@angular/platform-browser";
export class ImageCropperComponent {
sanitizer;
cd;
zone;
pinchStart$ = new Subject();
cropService = new CropService();
loadImageService = new LoadImageService();
setImageMaxSizeRetries = 0;
moveStart;
resizedWhileHidden = false;
moveTypes = MoveTypes;
state = new CropperState();
safeImgDataUrl = signal(undefined);
safeTransformStyle;
marginLeft = '0px';
imageVisible = false;
wrapper;
sourceImage;
imageChangedEvent;
imageURL;
imageBase64;
imageFile;
imageAltText;
options;
cropperFrameAriaLabel;
output;
format;
autoCrop;
cropper;
transform;
maintainAspectRatio;
aspectRatio;
resetCropOnAspectRatioChange;
resizeToWidth;
resizeToHeight;
cropperMinWidth;
cropperMinHeight;
cropperMaxHeight;
cropperMaxWidth;
cropperStaticWidth;
cropperStaticHeight;
canvasRotation;
initialStepSize;
roundCropper;
onlyScaleDown;
imageQuality;
backgroundColor;
containWithinAspectRatio;
hideResizeSquares;
allowMoveImage = false;
checkImageType = true;
alignImage;
disabled = false;
hidden = false;
imageCropped = new EventEmitter();
startCropImage = new EventEmitter();
imageLoaded = new EventEmitter();
cropperReady = new EventEmitter();
loadImageFailed = new EventEmitter();
transformChange = new EventEmitter();
cropperChange = new EventEmitter();
get alignImageStyle() {
return this.state.options.alignImage;
}
constructor(sanitizer, cd, zone) {
this.sanitizer = sanitizer;
this.cd = cd;
this.zone = zone;
this.reset();
}
ngOnInit() {
this.state.stepSize = this.initialStepSize || this.state.stepSize;
}
ngOnChanges(changes) {
const previousCropperPosition = this.state.cropper;
const previousTransform = this.state.transform;
const previousBackgroundColor = this.state.options.backgroundColor;
this.state.setOptionsFromChanges(changes);
this.onChangesInputImage(changes);
if (changes['transform'] && this.transform) {
this.state.transform = this.transform;
this.setCssTransform();
}
if (!this.state.loadedImage?.transformed.image.complete || !this.state.maxSize) {
return;
}
if ((this.containWithinAspectRatio && changes['aspectRatio']) || changes['containWithinAspectRatio'] || changes['canvasRotation']) {
this.loadImageService
.transformLoadedImage(this.state.loadedImage, this.state)
.then((res) => this.setLoadedImage(res))
.catch((err) => this.loadImageError(err));
return;
}
if (changes['cropper'] && this.cropper) {
this.state.cropper = checkCropperPosition(this.cropper, this.state, true);
}
const cropperChanged = !this.state.equalsCropperPosition(previousCropperPosition);
if (cropperChanged && (!this.cropper || !this.state.equalsCropperPosition(this.cropper))) {
this.cropperChange.emit(this.state.cropper);
}
if (cropperChanged
|| !this.state.equalsTransform(previousTransform)
|| this.state.options.backgroundColor !== previousBackgroundColor) {
this.doAutoCrop();
}
if (changes['hidden'] && this.resizedWhileHidden && !this.hidden) {
setTimeout(() => {
this.onResize();
this.resizedWhileHidden = false;
});
}
}
onChangesInputImage(changes) {
if (changes['imageChangedEvent'] || changes['imageURL'] || changes['imageBase64'] || changes['imageFile']) {
this.reset();
}
if (changes['imageChangedEvent'] && this.isValidImageChangedEvent()) {
this.loadImageFile(this.imageChangedEvent.target.files[0]);
}
if (changes['imageURL'] && this.imageURL) {
this.loadImageFromURL(this.imageURL);
}
if (changes['imageBase64'] && this.imageBase64) {
this.loadBase64Image(this.imageBase64);
}
if (changes['imageFile'] && this.imageFile) {
this.loadImageFile(this.imageFile);
}
}
isValidImageChangedEvent() {
const files = this.imageChangedEvent?.target?.files;
return files instanceof FileList && files.length > 0;
}
reset() {
this.safeImgDataUrl.set('data:image/png;base64,iVBORw0KGg'
+ 'oAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAU'
+ 'AAarVyFEAAAAASUVORK5CYII=');
this.state.loadedImage = undefined;
this.state.maxSize = undefined;
this.imageVisible = false;
}
loadImageFile(file) {
this.loadImageService
.loadImageFile(file, this.state)
.then((res) => this.setLoadedImage(res))
.catch((err) => this.loadImageError(err));
}
loadBase64Image(imageBase64) {
this.loadImageService
.loadBase64Image(imageBase64, this.state)
.then((res) => this.setLoadedImage(res))
.catch((err) => this.loadImageError(err));
}
loadImageFromURL(url) {
this.loadImageService
.loadImageFromURL(url, this.state)
.then((res) => this.setLoadedImage(res))
.catch((err) => this.loadImageError(err));
}
setLoadedImage(loadedImage) {
this.state.loadedImage = loadedImage;
this.safeImgDataUrl.set(this.sanitizer.bypassSecurityTrustResourceUrl(loadedImage.transformed.objectUrl));
}
loadImageError(error) {
console.error(error);
this.loadImageFailed.emit();
}
setCssTransform() {
const translateUnit = this.state.transform?.translateUnit || '%';
this.safeTransformStyle = this.sanitizer.bypassSecurityTrustStyle(`translate(${this.state.transform.translateH || 0}${translateUnit}, ${this.state.transform.translateV || 0}${translateUnit})` +
' scaleX(' + (this.state.transform.scale || 1) * (this.state.transform.flipH ? -1 : 1) + ')' +
' scaleY(' + (this.state.transform.scale || 1) * (this.state.transform.flipV ? -1 : 1) + ')' +
' rotate(' + (this.state.transform.rotate || 0) + 'deg)');
}
imageLoadedInView() {
if (this.state.loadedImage != null) {
this.imageLoaded.emit(this.state.loadedImage);
this.setImageMaxSizeRetries = 0;
setTimeout(() => this.checkImageMaxSizeRecursively());
}
}
checkImageMaxSizeRecursively() {
if (this.setImageMaxSizeRetries > 40) {
this.loadImageFailed.emit();
}
else if (this.sourceImageLoaded()) {
this.setMaxSize();
if (this.cropper && (!this.maintainAspectRatio || this.state.aspectRatioIsCorrect())) {
this.state.cropper = checkCropperPosition(this.cropper, this.state, true);
this.emitCropperPositionChange(this.cropper);
}
else {
this.state.cropper = checkCropperPosition(this.state.maxSizeCropperPosition(), this.state, true);
this.cropperChange.emit(this.state.cropper);
}
this.imageVisible = true;
this.cropperReady.emit({ ...this.state.maxSize });
this.doAutoCrop();
this.cd.markForCheck();
}
else {
this.setImageMaxSizeRetries++;
setTimeout(() => this.checkImageMaxSizeRecursively(), 50);
}
}
sourceImageLoaded() {
return this.sourceImage?.nativeElement?.offsetWidth > 1;
}
onResize() {
if (!this.state.loadedImage) {
return;
}
if (this.hidden) {
this.resizedWhileHidden = true;
}
else {
const oldMaxSize = { ...this.state.maxSize };
this.setMaxSize();
this.state.resizeCropperPosition(oldMaxSize);
this.cd.markForCheck();
}
}
keyboardAccess(event) {
this.changeKeyboardStepSize(event);
this.keyboardMoveCropper(event);
}
changeKeyboardStepSize(event) {
const key = +event.key;
if (key >= 1 && key <= 9) {
this.state.stepSize = key;
}
}
keyboardMoveCropper(event) {
const keyboardWhiteList = ['ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft'];
if (!(keyboardWhiteList.includes(event.key))) {
return;
}
const moveType = event.shiftKey ? MoveTypes.Resize : MoveTypes.Move;
const position = event.altKey ? getInvertedPositionForKey(event.key) : getPositionForKey(event.key);
const moveEvent = getEventForKey(event.key, this.state.stepSize);
event.preventDefault();
event.stopPropagation();
this.moveStart = {
active: true,
type: moveType,
position,
clientX: 0,
clientY: 0,
transform: this.state.transform,
cropper: this.state.cropper
};
this.handleMouseMove(moveEvent);
this.handleMouseUp();
}
startMove(event, moveType, position = null) {
if (this.disabled
|| this.moveStart?.active && this.moveStart?.type === MoveTypes.Pinch
|| moveType === MoveTypes.Drag && !this.allowMoveImage) {
return;
}
if ('preventDefault' in event) {
event.preventDefault();
}
this.moveStart = {
active: true,
type: moveType,
position,
clientX: getClientX(event),
clientY: getClientY(event),
transform: this.state.transform,
cropper: this.state.cropper
};
this.initMouseMove();
}
initMouseMove() {
merge(fromEvent(document, 'mousemove'), fromEvent(document, 'touchmove')).pipe(takeUntil(merge(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend'), this.pinchStart$).pipe(first()))).subscribe({
next: (event) => this.zone.run(() => {
this.handleMouseMove(event);
this.cd.markForCheck();
}),
complete: () => this.zone.run(() => {
this.handleMouseUp();
this.cd.markForCheck();
})
});
}
handleMouseMove(event) {
if (!this.moveStart?.active) {
return;
}
if ('stopPropagation' in event) {
event.stopPropagation();
}
if ('preventDefault' in event) {
event.preventDefault();
}
if (this.moveStart.type === MoveTypes.Move) {
this.state.cropper = checkCropperWithinMaxSizeBounds(moveCropper(event, this.moveStart), this.state, true);
}
else if (this.moveStart.type === MoveTypes.Resize) {
if (!this.cropperStaticWidth && !this.cropperStaticHeight) {
this.state.cropper = checkCropperWithinMaxSizeBounds(resizeCropper(event, this.moveStart, this.state), this.state, false);
}
}
else if (this.moveStart.type === MoveTypes.Drag) {
const diffX = getClientX(event) - this.moveStart.clientX;
const diffY = getClientY(event) - this.moveStart.clientY;
this.state.transform = {
...this.state.transform,
translateH: (this.moveStart.transform?.translateH || 0) + diffX,
translateV: (this.moveStart.transform?.translateV || 0) + diffY
};
this.setCssTransform();
}
}
handleMouseUp() {
if (!this.moveStart?.active || this.moveStart?.type === MoveTypes.Pinch) {
return;
}
if (!this.state.equalsCropperPosition(this.moveStart.cropper) || this.moveStart.transform && !this.state.equalsTransform(this.moveStart.transform)) {
if (this.moveStart.type === MoveTypes.Drag) {
this.transformChange.emit(this.state.transform);
}
else {
this.cropperChange.emit(this.state.cropper);
}
this.doAutoCrop();
}
this.moveStart = undefined;
}
startPinch(event) {
if (this.disabled || !this.sourceImageLoaded() || event.touches.length < 2) {
return;
}
if ('preventDefault' in event) {
event.preventDefault();
}
this.moveStart = {
active: true,
type: MoveTypes.Pinch,
position: 'center',
clientX: this.state.cropper.x1 + (this.state.cropper.x2 - this.state.cropper.x1) / 2,
clientY: this.state.cropper.y1 + (this.state.cropper.y2 - this.state.cropper.y1) / 2,
cropper: this.state.cropper
};
this.initPinch();
}
initPinch() {
this.pinchStart$.next();
fromEvent(document, 'touchmove')
.pipe(takeUntil(fromEvent(document, 'touchend')))
.subscribe({
next: (event) => this.zone.run(() => {
this.handlePinchMove(event);
this.cd.markForCheck();
}),
complete: () => this.zone.run(() => {
this.handlePinchStop();
this.cd.markForCheck();
})
});
}
handlePinchMove(event) {
if (!this.moveStart?.active) {
return;
}
if (event.preventDefault) {
event.preventDefault();
}
if (this.moveStart.type === MoveTypes.Pinch) {
if (!this.cropperStaticWidth && !this.cropperStaticHeight) {
this.state.cropper = checkCropperWithinMaxSizeBounds(resizeCropper(event, this.moveStart, this.state), this.state, false);
}
}
this.cd.markForCheck();
}
handlePinchStop() {
if (!this.moveStart?.active) {
return;
}
if (!this.state.equalsCropperPosition(this.moveStart.cropper)) {
this.emitCropperPositionChange(this.moveStart.cropper);
this.doAutoCrop();
}
this.moveStart = undefined;
}
setMaxSize() {
if (this.sourceImage) {
const sourceImageStyle = getComputedStyle(this.sourceImage.nativeElement);
this.state.setMaxSize(parseFloat(sourceImageStyle.width), parseFloat(sourceImageStyle.height));
this.marginLeft = this.sanitizer.bypassSecurityTrustStyle('calc(50% - ' + this.state.maxSize.width / 2 + 'px)');
}
}
emitCropperPositionChange(previousPosition) {
if (!this.state.equalsCropperPosition(previousPosition)) {
this.cropperChange.emit(this.state.cropper);
}
}
doAutoCrop() {
if (this.state.options.autoCrop) {
void this.crop();
}
}
crop(output = this.state.options.output) {
if (this.state.loadedImage?.transformed?.image != null) {
this.startCropImage.emit();
if (output === 'blob') {
return this.cropToBlob();
}
else if (output === 'base64') {
return this.cropToBase64();
}
}
return null;
}
cropToBlob() {
return new Promise((resolve, reject) => this.zone.run(async () => {
const result = await this.cropService.crop(this.state, 'blob');
if (result) {
this.imageCropped.emit(result);
resolve(result);
}
else {
reject('Crop image failed');
}
}));
}
cropToBase64() {
const result = this.cropService.crop(this.state, 'base64');
if (result) {
this.imageCropped.emit(result);
return result;
}
return null;
}
ngOnDestroy() {
this.pinchStart$.complete();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageCropperComponent, deps: [{ token: i1.DomSanitizer }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ImageCropperComponent, isStandalone: true, selector: "image-cropper", inputs: { imageChangedEvent: "imageChangedEvent", imageURL: "imageURL", imageBase64: "imageBase64", imageFile: "imageFile", imageAltText: "imageAltText", options: "options", cropperFrameAriaLabel: "cropperFrameAriaLabel", output: "output", format: "format", autoCrop: "autoCrop", cropper: "cropper", transform: "transform", maintainAspectRatio: "maintainAspectRatio", aspectRatio: "aspectRatio", resetCropOnAspectRatioChange: "resetCropOnAspectRatioChange", resizeToWidth: "resizeToWidth", resizeToHeight: "resizeToHeight", cropperMinWidth: "cropperMinWidth", cropperMinHeight: "cropperMinHeight", cropperMaxHeight: "cropperMaxHeight", cropperMaxWidth: "cropperMaxWidth", cropperStaticWidth: "cropperStaticWidth", cropperStaticHeight: "cropperStaticHeight", canvasRotation: "canvasRotation", initialStepSize: "initialStepSize", roundCropper: "roundCropper", onlyScaleDown: "onlyScaleDown", imageQuality: "imageQuality", backgroundColor: "backgroundColor", containWithinAspectRatio: "containWithinAspectRatio", hideResizeSquares: "hideResizeSquares", allowMoveImage: "allowMoveImage", checkImageType: "checkImageType", alignImage: "alignImage", disabled: "disabled", hidden: "hidden" }, outputs: { imageCropped: "imageCropped", startCropImage: "startCropImage", imageLoaded: "imageLoaded", cropperReady: "cropperReady", loadImageFailed: "loadImageFailed", transformChange: "transformChange", cropperChange: "cropperChange" }, host: { listeners: { "window:resize": "onResize()" }, properties: { "class.disabled": "this.disabled", "class.ngx-ic-hidden": "this.hidden", "style.text-align": "this.alignImageStyle" } }, viewQueries: [{ propertyName: "wrapper", first: true, predicate: ["wrapper"], descendants: true, static: true }, { propertyName: "sourceImage", first: true, predicate: ["sourceImage"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n [style.background]=\"imageVisible && state.options.backgroundColor\"\n (touchstart)=\"startPinch($event)\"\n>\n <img\n #sourceImage\n class=\"ngx-ic-source-image\"\n role=\"presentation\"\n *ngIf=\"safeImgDataUrl() as src\"\n [src]=\"src\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n [style.transform]=\"safeTransformStyle\"\n [class.ngx-ic-draggable]=\"!disabled && allowMoveImage\"\n [attr.alt]=\"imageAltText\"\n (load)=\"imageLoadedInView()\"\n (mousedown)=\"startMove($event, moveTypes.Drag)\"\n (touchstart)=\"startMove($event, moveTypes.Drag)\"\n (error)=\"loadImageError($event)\"\n >\n <div\n class=\"ngx-ic-overlay\"\n [style.width.px]=\"state.maxSize?.width || 0\"\n [style.height.px]=\"state.maxSize?.height || 0\"\n [style.margin-left]=\"alignImage === 'center' ? marginLeft : null\"\n ></div>\n <div\n class=\"ngx-ic-cropper\"\n *ngIf=\"imageVisible\"\n [class.ngx-ic-round]=\"state.options.roundCropper\"\n [attr.aria-label]=\"state.options.cropperFrameAriaLabel\"\n [style.top.px]=\"state.cropper.y1\"\n [style.left.px]=\"state.cropper.x1\"\n [style.width.px]=\"state.cropper.x2 - state.cropper.x1\"\n [style.height.px]=\"state.cropper.y2 - state.cropper.y1\"\n [style.margin-left]=\"state.options.alignImage === 'center' ? marginLeft : null\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n (keydown)=\"keyboardAccess($event)\"\n tabindex=\"0\"\n >\n <div\n (mousedown)=\"startMove($event, moveTypes.Move)\"\n (touchstart)=\"startMove($event, moveTypes.Move)\"\n class=\"ngx-ic-move\"\n role=\"presentation\">\n </div>\n <ng-container\n *ngIf=\"!state.options.hideResizeSquares && !(state.options.cropperStaticWidth && state.options.cropperStaticHeight)\">\n <span\n class=\"ngx-ic-resize ngx-ic-topleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-top\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-topright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topright')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-right\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-bottomright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottom\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-bottomleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-left\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-top\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'top')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'top')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-right\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'right')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'right')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-bottom\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-left\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'left')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'left')\"\n ></span>\n </ng-container>\n </div>\n</div>\n", styles: [":host{display:flex;position:relative;width:100%;max-width:100%;max-height:100%;overflow:hidden;padding:5px;text-align:center}:host>div{width:100%;position:relative}:host>div img.ngx-ic-source-image{max-width:100%;max-height:100%;transform-origin:center}:host>div img.ngx-ic-source-image.ngx-ic-draggable{user-drag:none;-webkit-user-drag:none;user-select:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;cursor:grab}:host .ngx-ic-overlay{position:absolute;pointer-events:none;touch-action:none;outline:var(--cropper-overlay-color, white) solid 100vw;top:0;left:0}:host .ngx-ic-cropper{position:absolute;display:flex;color:#53535c;background:transparent;outline:rgba(255,255,255,.3) solid 100vw;outline:var(--cropper-outline-color, rgba(255, 255, 255, .3)) solid 100vw;touch-action:none}@media (orientation: portrait){:host .ngx-ic-cropper{outline-width:100vh}}:host .ngx-ic-cropper:after{position:absolute;content:\"\";inset:0;pointer-events:none;border:dashed 1px;opacity:.75;color:inherit;z-index:1}:host .ngx-ic-cropper .ngx-ic-move{width:100%;cursor:move;border:var(--cropper-move-border, 1px solid rgba(255, 255, 255, .5))}:host .ngx-ic-cropper:focus .ngx-ic-move{border-color:#1e90ff;border-width:2px}:host .ngx-ic-cropper .ngx-ic-resize{position:absolute;display:inline-block;line-height:6px;padding:8px;opacity:.85;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize .ngx-ic-square{display:inline-block;background:#53535c;width:6px;height:6px;border:1px solid rgba(255,255,255,.5);box-sizing:content-box}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topleft{top:-12px;left:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-top{top:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topright{top:-12px;right:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-right{top:calc(50% - 12px);right:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomright{bottom:-12px;right:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottom{bottom:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomleft{bottom:-12px;left:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-left{top:calc(50% - 12px);left:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar{position:absolute;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-top{top:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-right{top:11px;right:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-bottom{bottom:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-left{top:11px;left:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper.ngx-ic-round{outline-color:transparent}:host .ngx-ic-cropper.ngx-ic-round:after{border-radius:100%;box-shadow:0 0 0 100vw #ffffff4d;box-shadow:0 0 0 100vw var(--cropper-outline-color, rgba(255, 255, 255, .3))}@media (orientation: portrait){:host .ngx-ic-cropper.ngx-ic-round:after{box-shadow:0 0 0 100vh #ffffff4d;box-shadow:0 0 0 100vh var(--cropper-outline-color, rgba(255, 255, 255, .3))}}:host .ngx-ic-cropper.ngx-ic-round .ngx-ic-move{border-radius:100%}:host.disabled .ngx-ic-cropper .ngx-ic-resize,:host.disabled .ngx-ic-cropper .ngx-ic-resize-bar,:host.disabled .ngx-ic-cropper .ngx-ic-move{display:none}:host.ngx-ic-hidden{display:none}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageCropperComponent, decorators: [{
type: Component,
args: [{ selector: 'image-cropper', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [NgIf], template: "<div\n [style.background]=\"imageVisible && state.options.backgroundColor\"\n (touchstart)=\"startPinch($event)\"\n>\n <img\n #sourceImage\n class=\"ngx-ic-source-image\"\n role=\"presentation\"\n *ngIf=\"safeImgDataUrl() as src\"\n [src]=\"src\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n [style.transform]=\"safeTransformStyle\"\n [class.ngx-ic-draggable]=\"!disabled && allowMoveImage\"\n [attr.alt]=\"imageAltText\"\n (load)=\"imageLoadedInView()\"\n (mousedown)=\"startMove($event, moveTypes.Drag)\"\n (touchstart)=\"startMove($event, moveTypes.Drag)\"\n (error)=\"loadImageError($event)\"\n >\n <div\n class=\"ngx-ic-overlay\"\n [style.width.px]=\"state.maxSize?.width || 0\"\n [style.height.px]=\"state.maxSize?.height || 0\"\n [style.margin-left]=\"alignImage === 'center' ? marginLeft : null\"\n ></div>\n <div\n class=\"ngx-ic-cropper\"\n *ngIf=\"imageVisible\"\n [class.ngx-ic-round]=\"state.options.roundCropper\"\n [attr.aria-label]=\"state.options.cropperFrameAriaLabel\"\n [style.top.px]=\"state.cropper.y1\"\n [style.left.px]=\"state.cropper.x1\"\n [style.width.px]=\"state.cropper.x2 - state.cropper.x1\"\n [style.height.px]=\"state.cropper.y2 - state.cropper.y1\"\n [style.margin-left]=\"state.options.alignImage === 'center' ? marginLeft : null\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n (keydown)=\"keyboardAccess($event)\"\n tabindex=\"0\"\n >\n <div\n (mousedown)=\"startMove($event, moveTypes.Move)\"\n (touchstart)=\"startMove($event, moveTypes.Move)\"\n class=\"ngx-ic-move\"\n role=\"presentation\">\n </div>\n <ng-container\n *ngIf=\"!state.options.hideResizeSquares && !(state.options.cropperStaticWidth && state.options.cropperStaticHeight)\">\n <span\n class=\"ngx-ic-resize ngx-ic-topleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-top\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-topright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topright')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-right\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-bottomright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottom\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-bottomleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-left\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-top\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'top')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'top')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-right\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'right')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'right')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-bottom\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-left\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'left')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'left')\"\n ></span>\n </ng-container>\n </div>\n</div>\n", styles: [":host{display:flex;position:relative;width:100%;max-width:100%;max-height:100%;overflow:hidden;padding:5px;text-align:center}:host>div{width:100%;position:relative}:host>div img.ngx-ic-source-image{max-width:100%;max-height:100%;transform-origin:center}:host>div img.ngx-ic-source-image.ngx-ic-draggable{user-drag:none;-webkit-user-drag:none;user-select:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;cursor:grab}:host .ngx-ic-overlay{position:absolute;pointer-events:none;touch-action:none;outline:var(--cropper-overlay-color, white) solid 100vw;top:0;left:0}:host .ngx-ic-cropper{position:absolute;display:flex;color:#53535c;background:transparent;outline:rgba(255,255,255,.3) solid 100vw;outline:var(--cropper-outline-color, rgba(255, 255, 255, .3)) solid 100vw;touch-action:none}@media (orientation: portrait){:host .ngx-ic-cropper{outline-width:100vh}}:host .ngx-ic-cropper:after{position:absolute;content:\"\";inset:0;pointer-events:none;border:dashed 1px;opacity:.75;color:inherit;z-index:1}:host .ngx-ic-cropper .ngx-ic-move{width:100%;cursor:move;border:var(--cropper-move-border, 1px solid rgba(255, 255, 255, .5))}:host .ngx-ic-cropper:focus .ngx-ic-move{border-color:#1e90ff;border-width:2px}:host .ngx-ic-cropper .ngx-ic-resize{position:absolute;display:inline-block;line-height:6px;padding:8px;opacity:.85;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize .ngx-ic-square{display:inline-block;background:#53535c;width:6px;height:6px;border:1px solid rgba(255,255,255,.5);box-sizing:content-box}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topleft{top:-12px;left:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-top{top:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topright{top:-12px;right:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-right{top:calc(50% - 12px);right:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomright{bottom:-12px;right:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottom{bottom:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomleft{bottom:-12px;left:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-left{top:calc(50% - 12px);left:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar{position:absolute;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-top{top:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-right{top:11px;right:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-bottom{bottom:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-left{top:11px;left:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper.ngx-ic-round{outline-color:transparent}:host .ngx-ic-cropper.ngx-ic-round:after{border-radius:100%;box-shadow:0 0 0 100vw #ffffff4d;box-shadow:0 0 0 100vw var(--cropper-outline-color, rgba(255, 255, 255, .3))}@media (orientation: portrait){:host .ngx-ic-cropper.ngx-ic-round:after{box-shadow:0 0 0 100vh #ffffff4d;box-shadow:0 0 0 100vh var(--cropper-outline-color, rgba(255, 255, 255, .3))}}:host .ngx-ic-cropper.ngx-ic-round .ngx-ic-move{border-radius:100%}:host.disabled .ngx-ic-cropper .ngx-ic-resize,:host.disabled .ngx-ic-cropper .ngx-ic-resize-bar,:host.disabled .ngx-ic-cropper .ngx-ic-move{display:none}:host.ngx-ic-hidden{display:none}\n"] }]
}], ctorParameters: () => [{ type: i1.DomSanitizer }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }], propDecorators: { wrapper: [{
type: ViewChild,
args: ['wrapper', { static: true }]
}], sourceImage: [{
type: ViewChild,
args: ['sourceImage', { static: false }]
}], imageChangedEvent: [{
type: Input
}], imageURL: [{
type: Input
}], imageBase64: [{
type: Input
}], imageFile: [{
type: Input
}], imageAltText: [{
type: Input
}], options: [{
type: Input
}], cropperFrameAriaLabel: [{
type: Input
}], output: [{
type: Input
}], format: [{
type: Input
}], autoCrop: [{
type: Input
}], cropper: [{
type: Input
}], transform: [{
type: Input
}], maintainAspectRatio: [{
type: Input
}], aspectRatio: [{
type: Input
}], resetCropOnAspectRatioChange: [{
type: Input
}], resizeToWidth: [{
type: Input
}], resizeToHeight: [{
type: Input
}], cropperMinWidth: [{
type: Input
}], cropperMinHeight: [{
type: Input
}], cropperMaxHeight: [{
type: Input
}], cropperMaxWidth: [{
type: Input
}], cropperStaticWidth: [{
type: Input
}], cropperStaticHeight: [{
type: Input
}], canvasRotation: [{
type: Input
}], initialStepSize: [{
type: Input
}], roundCropper: [{
type: Input
}], onlyScaleDown: [{
type: Input
}], imageQuality: [{
type: Input
}], backgroundColor: [{
type: Input
}], containWithinAspectRatio: [{
type: Input
}], hideResizeSquares: [{
type: Input
}], allowMoveImage: [{
type: Input
}], checkImageType: [{
type: Input
}], alignImage: [{
type: Input
}], disabled: [{
type: HostBinding,
args: ['class.disabled']
}, {
type: Input
}], hidden: [{
type: HostBinding,
args: ['class.ngx-ic-hidden']
}, {
type: Input
}], imageCropped: [{
type: Output
}], startCropImage: [{
type: Output
}], imageLoaded: [{
type: Output
}], cropperReady: [{
type: Output
}], loadImageFailed: [{
type: Output
}], transformChange: [{
type: Output
}], cropperChange: [{
type: Output
}], alignImageStyle: [{
type: HostBinding,
args: ['style.text-align']
}], onResize: [{
type: HostListener,
args: ['window:resize']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtY3JvcHBlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9ueHQtYXBwL3NyYy9saWIvY29tcG9uZW50cy9pbWFnZS1jcm9wcGVyL2NvbXBvbmVudC9pbWFnZS1jcm9wcGVyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL254dC1hcHAvc3JjL2xpYi9jb21wb25lbnRzL2ltYWdlLWNyb3BwZXIvY29tcG9uZW50L2ltYWdlLWNyb3BwZXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUV2QixTQUFTLEVBRVQsWUFBWSxFQUNaLFdBQVcsRUFDWCxZQUFZLEVBQ1osS0FBSyxFQUtMLE1BQU0sRUFBRSxNQUFNLEVBRWQsU0FBUyxFQUNWLE1BQU0sZUFBZSxDQUFDO0FBWXZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsU0FBUyxFQUFZLE1BQU0sb0NBQW9DLENBQUM7QUFDekUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxjQUFjLEVBQUUseUJBQXlCLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RyxPQUFPLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNqRCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFdkMsT0FBTyxFQUNMLG9CQUFvQixFQUNwQiwrQkFBK0IsRUFDL0IsVUFBVSxFQUNWLFVBQVUs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