{ "version": 3, "sources": ["../../../../../src/lib/tools/SelectTool/children/Cropping.ts"], "sourcesContent": ["import {\n\tSelectionHandle,\n\tStateNode,\n\tTLBaseShape,\n\tTLEnterEventHandler,\n\tTLEventHandlers,\n\tTLImageShape,\n\tTLImageShapeCrop,\n\tTLPointerEventInfo,\n\tTLShapePartial,\n\tVec2d,\n\tdeepCopy,\n} from '@tldraw/editor'\nimport { MIN_CROP_SIZE } from './Crop/crop-constants'\nimport { CursorTypeMap } from './PointingResizeHandle'\n\ntype Snapshot = ReturnType\n\nexport class Cropping extends StateNode {\n\tstatic override id = 'cropping'\n\n\tinfo = {} as TLPointerEventInfo & {\n\t\ttarget: 'selection'\n\t\thandle: SelectionHandle\n\t\tonInteractionEnd?: string\n\t}\n\n\tmarkId = ''\n\n\tprivate snapshot = {} as any as Snapshot\n\n\toverride onEnter: TLEnterEventHandler = (\n\t\tinfo: TLPointerEventInfo & {\n\t\t\ttarget: 'selection'\n\t\t\thandle: SelectionHandle\n\t\t\tonInteractionEnd?: string\n\t\t}\n\t) => {\n\t\tthis.info = info\n\t\tthis.markId = 'cropping'\n\t\tthis.editor.mark(this.markId)\n\t\tthis.snapshot = this.createSnapshot()\n\t\tthis.updateShapes()\n\t}\n\n\toverride onPointerMove: TLEventHandlers['onPointerMove'] = () => {\n\t\tthis.updateShapes()\n\t}\n\n\toverride onPointerUp: TLEventHandlers['onPointerUp'] = () => {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete: TLEventHandlers['onComplete'] = () => {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel: TLEventHandlers['onCancel'] = () => {\n\t\tthis.cancel()\n\t}\n\n\tprivate updateCursor() {\n\t\tconst selectedShape = this.editor.selectedShapes[0]\n\t\tif (!selectedShape) return\n\n\t\tconst cursorType = CursorTypeMap[this.info.handle!]\n\t\tthis.editor.updateInstanceState({\n\t\t\tcursor: {\n\t\t\t\ttype: cursorType,\n\t\t\t\trotation: selectedShape.rotation,\n\t\t\t},\n\t\t})\n\t}\n\n\tprivate getDefaultCrop = (): TLImageShapeCrop => ({\n\t\ttopLeft: { x: 0, y: 0 },\n\t\tbottomRight: { x: 1, y: 1 },\n\t})\n\n\tprivate updateShapes() {\n\t\tconst { shape, cursorHandleOffset } = this.snapshot\n\n\t\tif (!shape) return\n\t\tconst util = this.editor.getShapeUtil('image')\n\t\tif (!util) return\n\n\t\tconst props = shape.props\n\n\t\tconst currentPagePoint = this.editor.inputs.currentPagePoint.clone().sub(cursorHandleOffset)\n\t\tconst originPagePoint = this.editor.inputs.originPagePoint.clone().sub(cursorHandleOffset)\n\n\t\tconst change = currentPagePoint.clone().sub(originPagePoint).rot(-shape.rotation)\n\n\t\tconst crop = props.crop ?? this.getDefaultCrop()\n\t\tconst newCrop = deepCopy(crop)\n\n\t\tconst newPoint = new Vec2d(shape.x, shape.y)\n\t\tconst pointDelta = new Vec2d(0, 0)\n\n\t\t// original (uncropped) width and height of shape\n\t\tconst w = (1 / (crop.bottomRight.x - crop.topLeft.x)) * props.w\n\t\tconst h = (1 / (crop.bottomRight.y - crop.topLeft.y)) * props.h\n\n\t\tlet hasCropChanged = false\n\n\t\t// Set y dimension\n\t\tswitch (this.info.handle) {\n\t\t\tcase 'top':\n\t\t\tcase 'top_left':\n\t\t\tcase 'top_right': {\n\t\t\t\tif (h < MIN_CROP_SIZE) break\n\t\t\t\thasCropChanged = true\n\t\t\t\t// top\n\t\t\t\tnewCrop.topLeft.y = newCrop.topLeft.y + change.y / h\n\t\t\t\tconst heightAfterCrop = h * (newCrop.bottomRight.y - newCrop.topLeft.y)\n\n\t\t\t\tif (heightAfterCrop < MIN_CROP_SIZE) {\n\t\t\t\t\tnewCrop.topLeft.y = newCrop.bottomRight.y - MIN_CROP_SIZE / h\n\t\t\t\t\tpointDelta.y = (newCrop.topLeft.y - crop.topLeft.y) * h\n\t\t\t\t} else {\n\t\t\t\t\tif (newCrop.topLeft.y <= 0) {\n\t\t\t\t\t\tnewCrop.topLeft.y = 0\n\t\t\t\t\t\tpointDelta.y = (newCrop.topLeft.y - crop.topLeft.y) * h\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpointDelta.y = change.y\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom':\n\t\t\tcase 'bottom_left':\n\t\t\tcase 'bottom_right': {\n\t\t\t\tif (h < MIN_CROP_SIZE) break\n\t\t\t\thasCropChanged = true\n\t\t\t\t// bottom\n\t\t\t\tnewCrop.bottomRight.y = Math.min(1, newCrop.bottomRight.y + change.y / h)\n\t\t\t\tconst heightAfterCrop = h * (newCrop.bottomRight.y - newCrop.topLeft.y)\n\n\t\t\t\tif (heightAfterCrop < MIN_CROP_SIZE) {\n\t\t\t\t\tnewCrop.bottomRight.y = newCrop.topLeft.y + MIN_CROP_SIZE / h\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// Set x dimension\n\t\tswitch (this.info.handle) {\n\t\t\tcase 'left':\n\t\t\tcase 'top_left':\n\t\t\tcase 'bottom_left': {\n\t\t\t\tif (w < MIN_CROP_SIZE) break\n\t\t\t\thasCropChanged = true\n\t\t\t\t// left\n\t\t\t\tnewCrop.topLeft.x = newCrop.topLeft.x + change.x / w\n\t\t\t\tconst widthAfterCrop = w * (newCrop.bottomRight.x - newCrop.topLeft.x)\n\n\t\t\t\tif (widthAfterCrop < MIN_CROP_SIZE) {\n\t\t\t\t\tnewCrop.topLeft.x = newCrop.bottomRight.x - MIN_CROP_SIZE / w\n\t\t\t\t\tpointDelta.x = (newCrop.topLeft.x - crop.topLeft.x) * w\n\t\t\t\t} else {\n\t\t\t\t\tif (newCrop.topLeft.x <= 0) {\n\t\t\t\t\t\tnewCrop.topLeft.x = 0\n\t\t\t\t\t\tpointDelta.x = (newCrop.topLeft.x - crop.topLeft.x) * w\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpointDelta.x = change.x\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'right':\n\t\t\tcase 'top_right':\n\t\t\tcase 'bottom_right': {\n\t\t\t\tif (w < MIN_CROP_SIZE) break\n\t\t\t\thasCropChanged = true\n\t\t\t\t// right\n\t\t\t\tnewCrop.bottomRight.x = Math.min(1, newCrop.bottomRight.x + change.x / w)\n\t\t\t\tconst widthAfterCrop = w * (newCrop.bottomRight.x - newCrop.topLeft.x)\n\n\t\t\t\tif (widthAfterCrop < MIN_CROP_SIZE) {\n\t\t\t\t\tnewCrop.bottomRight.x = newCrop.topLeft.x + MIN_CROP_SIZE / w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif (!hasCropChanged) return\n\n\t\tnewPoint.add(pointDelta.rot(shape.rotation))\n\n\t\tconst partial: TLShapePartial<\n\t\t\tTLBaseShape\n\t\t> = {\n\t\t\tid: shape.id,\n\t\t\ttype: shape.type,\n\t\t\tx: newPoint.x,\n\t\t\ty: newPoint.y,\n\t\t\tprops: {\n\t\t\t\tcrop: newCrop,\n\t\t\t\tw: (newCrop.bottomRight.x - newCrop.topLeft.x) * w,\n\t\t\t\th: (newCrop.bottomRight.y - newCrop.topLeft.y) * h,\n\t\t\t},\n\t\t}\n\n\t\tthis.editor.updateShapes([partial], { squashing: true })\n\t\tthis.updateCursor()\n\t}\n\n\tprivate complete() {\n\t\tif (this.info.onInteractionEnd) {\n\t\t\tthis.editor.setCurrentTool(this.info.onInteractionEnd, this.info)\n\t\t} else {\n\t\t\tthis.editor.setCroppingShape(null)\n\t\t\tthis.parent.transition('idle', {})\n\t\t}\n\t}\n\n\tprivate cancel() {\n\t\tthis.editor.bailToMark(this.markId)\n\t\tif (this.info.onInteractionEnd) {\n\t\t\tthis.editor.setCurrentTool(this.info.onInteractionEnd, this.info)\n\t\t} else {\n\t\t\tthis.editor.setCroppingShape(null)\n\t\t\tthis.parent.transition('idle', {})\n\t\t}\n\t}\n\n\tprivate createSnapshot() {\n\t\tconst {\n\t\t\tselectionRotation,\n\t\t\tinputs: { originPagePoint },\n\t\t} = this.editor\n\n\t\tconst shape = this.editor.onlySelectedShape as TLImageShape\n\n\t\tconst selectionBounds = this.editor.selectionRotatedPageBounds!\n\n\t\tconst dragHandlePoint = Vec2d.RotWith(\n\t\t\tselectionBounds.getHandlePoint(this.info.handle!),\n\t\t\tselectionBounds.point,\n\t\t\tselectionRotation\n\t\t)\n\n\t\tconst cursorHandleOffset = Vec2d.Sub(originPagePoint, dragHandlePoint)\n\n\t\treturn {\n\t\t\tshape,\n\t\t\tcursorHandleOffset,\n\t\t}\n\t}\n}\n"], "mappings": "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", "names": [] }