All files / roosterjs-content-model-plugins/lib/imageEdit/Cropper cropperContext.ts

88.24% Statements 30/34
90% Branches 27/30
66.67% Functions 2/3
90% Lines 27/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 941x                 1x   45x 45x                 270x   45x                             90x 45x 45x   45x           45x 45x   45x       45x       45x       45x       45x 45x 45x 45x 45x 45x   45x                           120x 120x 120x 120x    
import { rotateCoordinate } from '../utils/imageEditUtils';
import type { DragAndDropContext } from '../types/DragAndDropContext';
import type { DragAndDropHandler } from '../../pluginUtils/DragAndDrop/DragAndDropHandler';
import type { ImageCropMetadataFormat } from 'roosterjs-content-model-types';
 
/**
 * @internal
 * Crop handle for DragAndDropHelper
 */
export const Cropper: DragAndDropHandler<DragAndDropContext, ImageCropMetadataFormat> = {
    onDragStart: ({ editInfo }) => ({ ...editInfo }),
    onDragging: ({ editInfo, x, y, options }, e, base, dx, dy) => {
        [dx, dy] = rotateCoordinate(dx, dy, editInfo.angleRad ?? 0);
 
        const {
            widthPx,
            heightPx,
            leftPercent,
            rightPercent,
            topPercent,
            bottomPercent,
        } = editInfo;
 
        Iif (
            leftPercent === undefined ||
            rightPercent === undefined ||
            topPercent === undefined ||
            bottomPercent === undefined ||
            base.leftPercent === undefined ||
            base.rightPercent === undefined ||
            base.topPercent === undefined ||
            base.bottomPercent === undefined ||
            widthPx === undefined ||
            heightPx === undefined
        ) {
            return false;
        }
 
        const { minWidth, minHeight } = options;
        const widthPercent = 1 - leftPercent - rightPercent;
        const heightPercent = 1 - topPercent - bottomPercent;
 
        Eif (
            widthPercent > 0 &&
            heightPercent > 0 &&
            minWidth !== undefined &&
            minHeight !== undefined
        ) {
            const fullWidth = widthPx / widthPercent;
            const fullHeight = heightPx / heightPercent;
            const newLeft =
                x != 'e'
                    ? crop(base.leftPercent, dx, fullWidth, rightPercent, minWidth)
                    : leftPercent;
            const newRight =
                x != 'w'
                    ? crop(base.rightPercent, -dx, fullWidth, leftPercent, minWidth)
                    : rightPercent;
            const newTop =
                y != 's'
                    ? crop(base.topPercent, dy, fullHeight, bottomPercent, minHeight)
                    : topPercent;
            const newBottom =
                y != 'n'
                    ? crop(base.bottomPercent, -dy, fullHeight, topPercent, minHeight)
                    : bottomPercent;
 
            editInfo.leftPercent = newLeft;
            editInfo.rightPercent = newRight;
            editInfo.topPercent = newTop;
            editInfo.bottomPercent = newBottom;
            editInfo.widthPx = fullWidth * (1 - newLeft - newRight);
            editInfo.heightPx = fullHeight * (1 - newTop - newBottom);
 
            return true;
        } else {
            return false;
        }
    },
};
 
function crop(
    basePercentage: number,
    deltaValue: number,
    fullValue: number,
    currentPercentage: number,
    minValue: number
): number {
    const maxValue = fullValue * (1 - currentPercentage) - minValue;
    const newValue = fullValue * basePercentage + deltaValue;
    const validValue = Math.max(Math.min(newValue, maxValue), 0);
    return validValue / fullValue;
}