import { Injectable } from '@angular/core'; import { CoordsInterface, DimensionsInterface, LayoutBoxInterface, ProductViewImageInterface, ProductViewImageModel, } from './../../../models/index'; import { RoundingFunctions, } from './../index'; export default class ImageTransformsFunctions { public static getLayoutBoxDimensions( parentDimensions: DimensionsInterface, layoutBox: LayoutBoxInterface, ) { return { height: layoutBox.dimensionsPercentages.height * parentDimensions.height, width: layoutBox.dimensionsPercentages.width * parentDimensions.width, }; } public static aspectFillImage( parentContainerDimensions: DimensionsInterface, productViewImage: ProductViewImageInterface, ) { const baseHeight = this._getBaseViewHeightOfProductView( productViewImage, parentContainerDimensions.width, ); const baseWidth = parentContainerDimensions.width * productViewImage.baseWidthPercent; const imageDimensions = productViewImage.rotation % 180 === 0 ? { height: baseHeight, width: baseWidth, } : { height: baseWidth, width: baseHeight, }; const zoomHeight = parentContainerDimensions.height / imageDimensions.height; const zoomWidth = parentContainerDimensions.width / imageDimensions.width; return ProductViewImageModel.setZoom( productViewImage, Math.max( zoomHeight, zoomWidth, ), ); } public static rotateImage( productViewImage: ProductViewImageInterface, rotationIncrements: number, ): ProductViewImageInterface { const { rotation = 0} = productViewImage; const newRotation = rotation + rotationIncrements; return { ...productViewImage, rotation: newRotation < 360 ? newRotation : 0, }; } public static updateImageQuality( productViewImage: ProductViewImageInterface, layoutBoxDimensions: DimensionsInterface, ): ProductViewImageInterface { const renderedImageWidth = this._getRenderedImageWidth( productViewImage, layoutBoxDimensions, ); const isTooLowQualityToPrint = ( renderedImageWidth > productViewImage.picture.dimensions.width ); return { ...productViewImage, isTooLowQualityToPrint, }; } public static zoomInImage( productViewImage: ProductViewImageInterface, zoomIncrements: number, layoutBoxDimens: DimensionsInterface, ): ProductViewImageInterface { return this.updateImageQuality({ ...productViewImage, zoom: productViewImage.zoom + zoomIncrements, zoomCount: productViewImage.zoomCount + 1, }, layoutBoxDimens); } public static zoomOutImage( productViewImage: ProductViewImageInterface, zoomIncrements: number, layoutBoxDimens: DimensionsInterface, ): ProductViewImageInterface { return this.updateImageQuality({ ...productViewImage, zoom: productViewImage.zoom - zoomIncrements, zoomCount: productViewImage.zoomCount - 1, }, layoutBoxDimens); } public static centerHorizontally( productViewImage: ProductViewImageInterface, ): ProductViewImageInterface { return { ...productViewImage, relativeStartPoint: { x: 0, y: productViewImage.relativeStartPoint.y, }, }; } public static centerVertically( parentContainerDimensions: DimensionsInterface, productViewImage: ProductViewImageInterface, ): ProductViewImageInterface { const viewHeightOfProductView = this._getBaseViewHeightOfProductView( productViewImage, parentContainerDimensions.width, ); const differenceBetweenParent = parentContainerDimensions.height - viewHeightOfProductView; const expectedDistanceFromTop = differenceBetweenParent / 2; const newStartY = expectedDistanceFromTop / viewHeightOfProductView; return { ...productViewImage, relativeStartPoint: { x: productViewImage.relativeStartPoint.x, y: newStartY, }, }; } public static centerImage( parentContainerDimensions: DimensionsInterface, productViewImage: ProductViewImageInterface, ) { return this.centerVertically( parentContainerDimensions, this.centerHorizontally( productViewImage, ), ); } public static onImageDraggedToMovePosition( dragMovement: CoordsInterface, productViewImage: ProductViewImageInterface, ): ProductViewImageInterface { const newStartPointX = productViewImage.relativeStartPoint.x + dragMovement.x; const newStartPointY = productViewImage.relativeStartPoint.y + dragMovement.y; return { ...productViewImage, relativeStartPoint: { x: newStartPointX, y: newStartPointY, }, }; } public static adjustImageToRemainInLayoutBox( parentDimensions: DimensionsInterface, layoutBox: LayoutBoxInterface, ): ProductViewImageInterface { const layoutBoxDimens = this.getLayoutBoxDimensions( parentDimensions, layoutBox, ); const productViewImage = layoutBox.containedItem as ProductViewImageInterface; const totalImageWidth = this._getRenderedImageWidth( productViewImage, layoutBoxDimens, ); const baseImageHeight = this._getBaseViewHeightOfProductView( productViewImage, layoutBoxDimens.width, ); const totalImageHeight = baseImageHeight * productViewImage.zoom; const isHorizontalImage = productViewImage.rotation % 180 === 0; const imageWidthAsPercentOfLayoutBox = (isHorizontalImage ? totalImageWidth : totalImageHeight) / layoutBoxDimens.width; const xWithAllowance = (imageWidthAsPercentOfLayoutBox - 1) / 2; const roundedX = this._roundForCalculations( productViewImage.relativeStartPoint.x, ); const roundedXWithAllowance = this._roundForCalculations( xWithAllowance, ); const newX = roundedX < -xWithAllowance ? -xWithAllowance : roundedX > xWithAllowance ? xWithAllowance : roundedX; const imageTotalVerticalDimens = isHorizontalImage ? totalImageHeight : totalImageWidth; const imageBaseVerticalDimens = isHorizontalImage ? baseImageHeight : layoutBoxDimens.width * productViewImage.baseWidthPercent; const initialAmountAboveTop = isHorizontalImage ? -( imageBaseVerticalDimens / 2 ) * (productViewImage.zoom - 1) : -(totalImageWidth / 2 - baseImageHeight / 2); const translateAdjustPosition = productViewImage.relativeStartPoint.y * baseImageHeight; const startPoint = this._roundForCalculations( initialAmountAboveTop + translateAdjustPosition, ); let newY = productViewImage.relativeStartPoint.y; if (startPoint > 0) { newY = -(initialAmountAboveTop / baseImageHeight); } else if ( startPoint + imageTotalVerticalDimens < layoutBoxDimens.height ) { const distanceToMakeUp = layoutBoxDimens.height - (initialAmountAboveTop + imageTotalVerticalDimens); newY = distanceToMakeUp / baseImageHeight; } return { ...productViewImage, relativeStartPoint: { x: newX, y: newY, }, }; } public static setInitialImageTransforms( parentContainerDimensions: DimensionsInterface, productViewImage: ProductViewImageInterface, ) { if (!productViewImage.picture) { return productViewImage; } const aspectFilledImage = this.aspectFillImage( parentContainerDimensions, productViewImage, ); const imageWithQuality = this.updateImageQuality( aspectFilledImage, parentContainerDimensions, ); const centeredVertically = this.centerVertically( parentContainerDimensions, imageWithQuality, ); const centeredHorizontally = this.centerHorizontally( centeredVertically, ); centeredHorizontally.zoomCount = 0; return centeredHorizontally; } private static _getRenderedImageWidth( productViewImage: ProductViewImageInterface, layoutBoxDimens: DimensionsInterface, ) { return productViewImage.baseWidthPercent * productViewImage.zoom * layoutBoxDimens.width; } private static _getBaseViewHeightOfProductView( productViewImage: ProductViewImageInterface, parentContainerWidth: number, ) { const imageHeightAsAPercentOfWidth = productViewImage.picture.dimensions.height / productViewImage.picture.dimensions.width; return parentContainerWidth * imageHeightAsAPercentOfWidth * productViewImage.baseWidthPercent; } private static _roundForCalculations( value: number, ) { return RoundingFunctions.roundToDps( value, 10, ); } }