{"version":3,"file":"rotate.mjs","names":[],"sources":["../../../src/controls/rotate.ts"],"sourcesContent":["import type {\n  ControlCursorCallback,\n  TransformActionHandler,\n} from '../EventTypeDefs';\nimport { ROTATING } from '../constants';\nimport { radiansToDegrees } from '../util/misc/radiansDegreesConversion';\nimport { isLocked, NOT_ALLOWED_CURSOR } from './util';\nimport { wrapWithFireEvent } from './wrapWithFireEvent';\nimport { wrapWithFixedAnchor } from './wrapWithFixedAnchor';\n\n/**\n * Find the correct style for the control that is used for rotation.\n * this function is very simple and it just take care of not-allowed or standard cursor\n * @param {Event} eventData the javascript event that is causing the scale\n * @param {Control} control the control that is interested in the action\n * @param {FabricObject} fabricObject the fabric object that is interested in the action\n * @return {String} a valid css string for the cursor\n */\nexport const rotationStyleHandler: ControlCursorCallback = (\n  eventData,\n  control,\n  fabricObject,\n) => {\n  if (fabricObject.lockRotation) {\n    return NOT_ALLOWED_CURSOR;\n  }\n  return control.cursorStyle;\n};\n\n/**\n * Action handler for rotation and snapping, without anchor point.\n * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n * @private\n */\nconst rotateObjectWithSnapping: TransformActionHandler = (\n  eventData,\n  { target, ex, ey, theta, originX, originY },\n  x,\n  y,\n) => {\n  const pivotPoint = target.getPositionByOrigin(originX, originY);\n\n  if (isLocked(target, 'lockRotation')) {\n    return false;\n  }\n\n  const lastAngle = Math.atan2(ey - pivotPoint.y, ex - pivotPoint.x),\n    curAngle = Math.atan2(y - pivotPoint.y, x - pivotPoint.x);\n  let angle = radiansToDegrees(curAngle - lastAngle + theta);\n\n  if (target.snapAngle && target.snapAngle > 0) {\n    const snapAngle = target.snapAngle,\n      snapThreshold = target.snapThreshold || snapAngle,\n      rightAngleLocked = Math.ceil(angle / snapAngle) * snapAngle,\n      leftAngleLocked = Math.floor(angle / snapAngle) * snapAngle;\n\n    if (Math.abs(angle - leftAngleLocked) < snapThreshold) {\n      angle = leftAngleLocked;\n    } else if (Math.abs(angle - rightAngleLocked) < snapThreshold) {\n      angle = rightAngleLocked;\n    }\n  }\n\n  // normalize angle to positive value\n  if (angle < 0) {\n    angle = 360 + angle;\n  }\n  angle %= 360;\n\n  const hasRotated = target.angle !== angle;\n  // TODO: why aren't we using set?\n  target.angle = angle;\n  return hasRotated;\n};\n\nexport const rotationWithSnapping = wrapWithFireEvent(\n  ROTATING,\n  wrapWithFixedAnchor(rotateObjectWithSnapping),\n);\n"],"mappings":";;;;;;;;;;;;;;AAkBA,MAAa,wBACX,WACA,SACA,iBACG;AACH,KAAI,aAAa,aACf,QAAO;AAET,QAAO,QAAQ;;;;;;;;;;;;AAajB,MAAM,4BACJ,WACA,EAAE,QAAQ,IAAI,IAAI,OAAO,SAAS,WAClC,GACA,MACG;CACH,MAAM,aAAa,OAAO,oBAAoB,SAAS,QAAQ;AAE/D,KAAI,SAAS,QAAQ,eAAe,CAClC,QAAO;CAGT,MAAM,YAAY,KAAK,MAAM,KAAK,WAAW,GAAG,KAAK,WAAW,EAAE;CAElE,IAAI,QAAQ,iBADC,KAAK,MAAM,IAAI,WAAW,GAAG,IAAI,WAAW,EAAE,GACnB,YAAY,MAAM;AAE1D,KAAI,OAAO,aAAa,OAAO,YAAY,GAAG;EAC5C,MAAM,YAAY,OAAO,WACvB,gBAAgB,OAAO,iBAAiB,WACxC,mBAAmB,KAAK,KAAK,QAAQ,UAAU,GAAG,WAClD,kBAAkB,KAAK,MAAM,QAAQ,UAAU,GAAG;AAEpD,MAAI,KAAK,IAAI,QAAQ,gBAAgB,GAAG,cACtC,SAAQ;WACC,KAAK,IAAI,QAAQ,iBAAiB,GAAG,cAC9C,SAAQ;;AAKZ,KAAI,QAAQ,EACV,SAAQ,MAAM;AAEhB,UAAS;CAET,MAAM,aAAa,OAAO,UAAU;AAEpC,QAAO,QAAQ;AACf,QAAO;;AAGT,MAAa,uBAAuB,kBAClC,UACA,oBAAoB,yBAAyB,CAC9C"}