import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, } from '@angular/core'; import { PIGService, } from './../../helpers/services/index'; import { CoordsInterface, ImageEditorImageInterface, MaskImageMapInterface, PIGLayerImageInterface, } from './../../models/index'; import { Subscription, } from 'rxjs'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'image-editor-with-data-component', styleUrls: [ './image-editor-with-data.component.scss', ], templateUrl: './image-editor-with-data.component.template.pug', }) export class ImageEditorWithDataComponent implements OnChanges { @Input() public colorOverlay: string; @Input() public templateId: string; @Input() public imageVariantName: string; @Input() public guideAreaColor = '#E27B7B'; @Input() public guideAreaStrokeWidth: number; @Input() public showPrintArea = false; @Input() public showImageOverspill = false; @Input() public imageOverSpillBorderColor: string; @Input() public imageEditorImages: ImageEditorImageInterface[]; @Input() public showGridLines: boolean; @Input() public gridLinesColor: string; @Input() public gridLinesOpacity: number; @Input() public gridLineStrokeWidth: number; @Input() public distanceToSnapToGrid: number; @Input() public showRotationControl: boolean; @Input() public showRotationMeasurement: boolean; @Input() public distanceToSnapToRotation: number; @Input() public showScaleControl: boolean; @Input() public showDeleteButton: boolean; @Input() public enableAspectFit: boolean = false; @Input() public enableBorderEditing: boolean = false; @Input() public dpi: number = 0; @Output() public updateTranslations = new EventEmitter<[ MaskImageMapInterface, CoordsInterface ]>(); @Output() public onPinchRotateImage = new EventEmitter<[ MaskImageMapInterface, number ]>(); @Output() public onPinchScaleImage = new EventEmitter<[ MaskImageMapInterface, number ]>(); @Output() public onRotationControlRotate = new EventEmitter<[ MaskImageMapInterface, number ]>(); @Output() public onScaleControlScaleAndTranslate = new EventEmitter<[ MaskImageMapInterface, number, CoordsInterface ]>(); @Output() public onDeleteButtonClicked = new EventEmitter(); public isLoading = true; public layerComponents: PIGLayerImageInterface; public maskImageMap: MaskImageMapInterface[]; public foregroundBlendMode: string; public foregroundUrl: string; private _pigLayerComponentSubscription$: Subscription; public get appliedColorOverlay() { return this.layerComponents.color_overlay ? this.colorOverlay : null; } constructor( private _pigService: PIGService, private _changeDetectorRef: ChangeDetectorRef, ) {} public ngOnInit() { if (this.enableBorderEditing && !this.dpi) { throw Error('dpi is a required property to enable border editing'); } } public ngOnChanges(changes: SimpleChanges) { if ( changes.templateId || changes.imageVariantName ) { this.initaliseLayerComponents(changes); } else if ( changes.imageEditorImages || changes.showPrintArea || changes.guideAreaColor || changes.showImageOverspill ) { this.initaliseMasks(); } } public initaliseLayerComponents(changes) { if (this.templateId) { this.isLoading = true; if ( this._pigLayerComponentSubscription$ && !this._pigLayerComponentSubscription$.closed ) { this._pigLayerComponentSubscription$.unsubscribe(); } this._pigLayerComponentSubscription$ = this._pigService.getLayerComponents$( this.templateId, this.imageVariantName, ).subscribe((resp) => { this.layerComponents = resp; if (this.enableAspectFit && this.checkForNewTemplateFit(changes) && this.imageEditorImages[0].url_preview) { this.imageEditorImages[0].tx = 0; this.imageEditorImages[0].ty = 0; this.fitImage(this.imageEditorImages[0].url_preview); } else { this.initaliseMasks(); this.isLoading = false; } }); } } public initaliseMasks(useNewScale = false, imgWidth = null, imgHeight = null) { if (this.layerComponents) { this.maskImageMap = this.layerComponents .masks.map((mask, index) => { const imageEditorImage = this.imageEditorImages && this.imageEditorImages[index]; if (useNewScale) { this.isLoading = true; const fitWidth = this.layerComponents.asset_size.width; const fitHeight = this.layerComponents.asset_size.height; const pigScale = Math.max(fitWidth / imgWidth, fitHeight / imgHeight); const newImgWidth = pigScale * imgWidth; const newImgHeight = pigScale * imgHeight; const newScale = Math.min(fitWidth / newImgWidth, fitHeight / newImgHeight); imageEditorImage.scale = newScale; this.isLoading = false; } return { imageEditorImage: imageEditorImage && { ...imageEditorImage, urlToRender: this._pigService.getUrlWithFilters( imageEditorImage.url_preview, this.templateId, imageEditorImage.filters, ), }, mask, }; }); this.foregroundBlendMode = this.layerComponents.foreground && this.layerComponents.foreground.blend_mode; this.foregroundUrl = this.layerComponents.foreground && this.layerComponents.foreground.image; this._changeDetectorRef.markForCheck(); } } public checkForNewTemplateFit(changes) { return ( (Object.keys(changes).length === 1 && changes.templateId) && (changes.templateId.previousValue !== changes.templateId.currentValue) ); } public fitImage(imageUrl: string) { const img = new Image(); img.src = imageUrl; img.onload = () => { this.initaliseMasks(true, img.width, img.height); }; } public onUpdateTranslations(event: [ MaskImageMapInterface, CoordsInterface ]) { this.updateTranslations.emit(event); } public pinchRotateImage(event: [ MaskImageMapInterface, number ]) { this.onPinchRotateImage.emit(event); } public pinchScaleImage(event: [ MaskImageMapInterface, number ]) { this.onPinchScaleImage.emit(event); } public rotationControlRotate(event: [ MaskImageMapInterface, number ]) { this.onRotationControlRotate.emit(event); } public scaleControlScaleAndTranslate(event: [ MaskImageMapInterface, number, CoordsInterface ]) { this.onScaleControlScaleAndTranslate.emit(event); } public deleteButtonClicked(maskImageMap: MaskImageMapInterface) { this.onDeleteButtonClicked.emit(maskImageMap); } }