fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
1 lines • 11.4 kB
Source Map (JSON)
{"version":3,"file":"skew.min.mjs","sources":["../../../src/controls/skew.ts"],"sourcesContent":["import type {\n ControlCursorCallback,\n TPointerEvent,\n Transform,\n TransformActionHandler,\n} from '../EventTypeDefs';\nimport { resolveOrigin } from '../util/misc/resolveOrigin';\nimport { Point } from '../Point';\nimport type { TAxis, TAxisKey } from '../typedefs';\nimport {\n degreesToRadians,\n radiansToDegrees,\n} from '../util/misc/radiansDegreesConversion';\nimport {\n findCornerQuadrant,\n getLocalPoint,\n isLocked,\n NOT_ALLOWED_CURSOR,\n} from './util';\nimport { wrapWithFireEvent } from './wrapWithFireEvent';\nimport { wrapWithFixedAnchor } from './wrapWithFixedAnchor';\nimport {\n CENTER,\n SCALE_X,\n SCALE_Y,\n SKEWING,\n SKEW_X,\n SKEW_Y,\n} from '../constants';\n\nexport type SkewTransform = Transform & { skewingSide: -1 | 1 };\n\nconst AXIS_KEYS: Record<\n TAxis,\n {\n counterAxis: TAxis;\n scale: TAxisKey<'scale'>;\n skew: TAxisKey<'skew'>;\n lockSkewing: TAxisKey<'lockSkewing'>;\n origin: TAxisKey<'origin'>;\n flip: TAxisKey<'flip'>;\n }\n> = {\n x: {\n counterAxis: 'y',\n scale: SCALE_X,\n skew: SKEW_X,\n lockSkewing: 'lockSkewingX',\n origin: 'originX',\n flip: 'flipX',\n },\n y: {\n counterAxis: 'x',\n scale: SCALE_Y,\n skew: SKEW_Y,\n lockSkewing: 'lockSkewingY',\n origin: 'originY',\n flip: 'flipY',\n },\n};\n\nconst skewMap = ['ns', 'nesw', 'ew', 'nwse'];\n\n/**\n * return the correct cursor style for the skew action\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 skewCursorStyleHandler: ControlCursorCallback = (\n eventData,\n control,\n fabricObject,\n) => {\n if (control.x !== 0 && isLocked(fabricObject, 'lockSkewingY')) {\n return NOT_ALLOWED_CURSOR;\n }\n if (control.y !== 0 && isLocked(fabricObject, 'lockSkewingX')) {\n return NOT_ALLOWED_CURSOR;\n }\n const n = findCornerQuadrant(fabricObject, control) % 4;\n return `${skewMap[n]}-resize`;\n};\n\n/**\n * Since skewing is applied before scaling, calculations are done in a scaleless plane\n * @see https://github.com/fabricjs/fabric.js/pull/8380\n */\nfunction skewObject(\n axis: TAxis,\n { target, ex, ey, skewingSide, ...transform }: SkewTransform,\n pointer: Point,\n) {\n const { skew: skewKey } = AXIS_KEYS[axis],\n offset = pointer\n .subtract(new Point(ex, ey))\n .divide(new Point(target.scaleX, target.scaleY))[axis],\n skewingBefore = target[skewKey],\n skewingStart = transform[skewKey],\n shearingStart = Math.tan(degreesToRadians(skewingStart)),\n // let a, b be the size of target\n // let a' be the value of a after applying skewing\n // then:\n // a' = a + b * skewA => skewA = (a' - a) / b\n // the value b is tricky since skewY is applied before skewX\n b =\n axis === 'y'\n ? target._getTransformedDimensions({\n scaleX: 1,\n scaleY: 1,\n // since skewY is applied before skewX, b (=width) is not affected by skewX\n skewX: 0,\n }).x\n : target._getTransformedDimensions({\n scaleX: 1,\n scaleY: 1,\n }).y;\n\n const shearing =\n (2 * offset * skewingSide) /\n // we max out fractions to safeguard from asymptotic behavior\n Math.max(b, 1) +\n // add starting state\n shearingStart;\n\n const skewing = radiansToDegrees(Math.atan(shearing));\n\n target.set(skewKey, skewing);\n const changed = skewingBefore !== target[skewKey];\n\n if (changed && axis === 'y') {\n // we don't want skewing to affect scaleX\n // so we factor it by the inverse skewing diff to make it seem unchanged to the viewer\n const { skewX, scaleX } = target,\n dimBefore = target._getTransformedDimensions({ skewY: skewingBefore }),\n dimAfter = target._getTransformedDimensions(),\n compensationFactor = skewX !== 0 ? dimBefore.x / dimAfter.x : 1;\n compensationFactor !== 1 &&\n target.set(SCALE_X, compensationFactor * scaleX);\n }\n\n return changed;\n}\n\n/**\n * Wrapped Action handler for skewing on a given axis, takes care of the\n * skew direction and determines the correct transform origin for the anchor point\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 */\nfunction skewHandler(\n axis: TAxis,\n eventData: TPointerEvent,\n transform: Transform,\n x: number,\n y: number,\n) {\n const { target } = transform,\n {\n counterAxis,\n origin: originKey,\n lockSkewing: lockSkewingKey,\n skew: skewKey,\n flip: flipKey,\n } = AXIS_KEYS[axis];\n if (isLocked(target, lockSkewingKey)) {\n return false;\n }\n\n const { origin: counterOriginKey, flip: counterFlipKey } =\n AXIS_KEYS[counterAxis],\n counterOriginFactor =\n resolveOrigin(transform[counterOriginKey]) *\n (target[counterFlipKey] ? -1 : 1),\n // if the counter origin is top/left (= -0.5) then we are skewing x/y values on the bottom/right side of target respectively.\n // if the counter origin is bottom/right (= 0.5) then we are skewing x/y values on the top/left side of target respectively.\n // skewing direction on the top/left side of target is OPPOSITE to the direction of the movement of the pointer,\n // so we factor skewing direction by this value.\n skewingSide = (-Math.sign(counterOriginFactor) *\n (target[flipKey] ? -1 : 1)) as 1 | -1,\n skewingDirection =\n ((target[skewKey] === 0 &&\n // in case skewing equals 0 we use the pointer offset from target center to determine the direction of skewing\n getLocalPoint(transform, CENTER, CENTER, x, y)[axis] > 0) ||\n // in case target has skewing we use that as the direction\n target[skewKey] > 0\n ? 1\n : -1) * skewingSide,\n // anchor to the opposite side of the skewing direction\n // normalize value from [-1, 1] to origin value [0, 1]\n origin = -skewingDirection * 0.5 + 0.5;\n\n const finalHandler = wrapWithFireEvent<SkewTransform>(\n SKEWING,\n wrapWithFixedAnchor((eventData, transform, x, y) =>\n skewObject(axis, transform, new Point(x, y)),\n ),\n );\n\n return finalHandler(\n eventData,\n {\n ...transform,\n [originKey]: origin,\n skewingSide,\n },\n x,\n y,\n );\n}\n\n/**\n * Wrapped Action handler for skewing on the X axis, takes care of the\n * skew direction and determines the correct transform origin for the anchor point\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 */\nexport const skewHandlerX: TransformActionHandler = (\n eventData,\n transform,\n x,\n y,\n) => {\n return skewHandler('x', eventData, transform, x, y);\n};\n\n/**\n * Wrapped Action handler for skewing on the Y axis, takes care of the\n * skew direction and determines the correct transform origin for the anchor point\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 */\nexport const skewHandlerY: TransformActionHandler = (\n eventData,\n transform,\n x,\n y,\n) => {\n return skewHandler('y', eventData, transform, x, y);\n};\n"],"names":["AXIS_KEYS","x","counterAxis","scale","SCALE_X","skew","SKEW_X","lockSkewing","origin","flip","y","SCALE_Y","SKEW_Y","skewMap","skewCursorStyleHandler","eventData","control","fabricObject","isLocked","NOT_ALLOWED_CURSOR","n","findCornerQuadrant","concat","skewHandler","axis","transform","target","originKey","lockSkewingKey","skewKey","flipKey","counterOriginKey","counterFlipKey","counterOriginFactor","resolveOrigin","skewingSide","Math","sign","getLocalPoint","CENTER","finalHandler","wrapWithFireEvent","SKEWING","wrapWithFixedAnchor","_ref","pointer","ex","ey","_objectWithoutProperties","_excluded","offset","subtract","Point","divide","scaleX","scaleY","skewingBefore","skewingStart","shearingStart","tan","degreesToRadians","b","_getTransformedDimensions","skewX","shearing","max","skewing","radiansToDegrees","atan","set","changed","dimBefore","skewY","dimAfter","compensationFactor","skewObject","_objectSpread","skewHandlerX","skewHandlerY"],"mappings":"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"}