/** * @module modifiers/aspectRatio * * @description * This module forces elements to be resized with a specified dx/dy ratio. * * ```js * interact(target).resizable({ * modifiers: [ * interact.modifiers.snapSize({ * targets: [ interact.snappers.grid({ x: 20, y: 20 }) ], * }), * interact.aspectRatio({ ratio: 'preserve' }), * ], * }); * ``` */import type { Point, Rect, EdgeOptions } from '@interactjs/types/index'import extend from '@interactjs/utils/extend'import { addEdges } from '@interactjs/utils/rect'import Modification from './Modification'import type { Modifier, ModifierModule, ModifierState } from './base'import { makeModifier } from './base'export interface AspectRatioOptions { ratio?: number | 'preserve' equalDelta?: boolean modifiers?: Modifier[] enabled?: boolean}export type AspectRatioState = ModifierState<AspectRatioOptions,{ startCoords: Point startRect: Rect linkedEdges: EdgeOptions ratio: number equalDelta: boolean xIsPrimaryAxis: boolean edgeSign: 1 | -1 subModification: Modification}>const aspectRatio: ModifierModule<AspectRatioOptions, AspectRatioState> = { start (arg) { const { state, rect, edges: originalEdges, pageCoords: coords } = arg let { ratio } = state.options const { equalDelta, modifiers } = state.options if (ratio === 'preserve') { ratio = rect.width / rect.height } state.startCoords = extend({}, coords) state.startRect = extend({}, rect) state.ratio = ratio state.equalDelta = equalDelta const linkedEdges = (state.linkedEdges = { top: originalEdges.top || (originalEdges.left && !originalEdges.bottom), left: originalEdges.left || (originalEdges.top && !originalEdges.right), bottom: originalEdges.bottom || (originalEdges.right && !originalEdges.top), right: originalEdges.right || (originalEdges.bottom && !originalEdges.left), }) state.xIsPrimaryAxis = !!(originalEdges.left || originalEdges.right) if (state.equalDelta) { state.edgeSign = ((linkedEdges.left ? 1 : -1) * (linkedEdges.top ? 1 : -1)) as 1 | -1 } else { const negativeSecondaryEdge = state.xIsPrimaryAxis ? linkedEdges.top : linkedEdges.left state.edgeSign = negativeSecondaryEdge ? -1 : 1 } extend(arg.edges, linkedEdges) if (!modifiers || !modifiers.length) return const subModification = new Modification(arg.interaction) subModification.copyFrom(arg.interaction.modification) subModification.prepareStates(modifiers) state.subModification = subModification subModification.startAll({ ...arg }) }, set (arg) { const { state, rect, coords } = arg const initialCoords = extend({}, coords) const aspectMethod = state.equalDelta ? setEqualDelta : setRatio aspectMethod(state, state.xIsPrimaryAxis, coords, rect) if (!state.subModification) { return null } const correctedRect = extend({}, rect) addEdges(state.linkedEdges, correctedRect, { x: coords.x - initialCoords.x, y: coords.y - initialCoords.y, }) const result = state.subModification.setAll({ ...arg, rect: correctedRect, edges: state.linkedEdges, pageCoords: coords, prevCoords: coords, prevRect: correctedRect, }) const { delta } = result if (result.changed) { const xIsCriticalAxis = Math.abs(delta.x) > Math.abs(delta.y) // do aspect modification again with critical edge axis as primary aspectMethod(state, xIsCriticalAxis, result.coords, result.rect) extend(coords, result.coords) } return result.eventProps }, defaults: { ratio: 'preserve', equalDelta: false, modifiers: [], enabled: false, },}function setEqualDelta ({ startCoords, edgeSign }: AspectRatioState, xIsPrimaryAxis: boolean, coords: Point) { if (xIsPrimaryAxis) { coords.y = startCoords.y + (coords.x - startCoords.x) * edgeSign } else { coords.x = startCoords.x + (coords.y - startCoords.y) * edgeSign }}function setRatio ( { startRect, startCoords, ratio, edgeSign }: AspectRatioState, xIsPrimaryAxis: boolean, coords: Point, rect: Rect,) { if (xIsPrimaryAxis) { const newHeight = rect.width / ratio coords.y = startCoords.y + (newHeight - startRect.height) * edgeSign } else { const newWidth = rect.height * ratio coords.x = startCoords.x + (newWidth - startRect.width) * edgeSign }}export default makeModifier(aspectRatio, 'aspectRatio')export { aspectRatio }