{
  "version": 3,
  "sources": ["../../../src/lib/overlays/ArrowBindingHintOverlayUtil.ts"],
  "sourcesContent": ["import {\n\tgetPerfectDashProps,\n\tOverlayUtil,\n\tPI2,\n\tTLArrowShape,\n\tTLOverlay,\n\tTLShapeId,\n\tVec,\n} from '@tldraw/editor'\nimport { TLArrowInfo } from '../shapes/arrow/arrow-types'\nimport { getArrowInfo } from '../shapes/arrow/getArrowInfo'\nimport { getArrowBindings } from '../shapes/arrow/shared'\n\n/** @public */\nexport interface TLArrowBindingHintOverlay extends TLOverlay {\n\tprops: {\n\t\tarrowId: TLShapeId\n\t}\n}\n\n/**\n * Overlay util for the dashed binding hint shown on bound arrows. Draws stubs\n * along the arrow's handle path, from each bound endpoint's snapped body\n * position to the user's intended (handle) position, with a precision marker\n * at the handle.\n *\n * @public\n */\nexport class ArrowBindingHintOverlayUtil extends OverlayUtil<TLArrowBindingHintOverlay> {\n\tstatic override type = 'arrow_binding_hint'\n\toverride options = {\n\t\tzIndex: 150,\n\t\tstrokeWidth: 2,\n\t\topacity: 0.16,\n\t\tdashLengthRatio: 2.5,\n\t\tdotRadius: 4,\n\t\tcrossSize: 6,\n\t\tdashedMinZoom: 0.2,\n\t}\n\n\toverride isActive(): boolean {\n\t\tconst editor = this.editor\n\t\tif (editor.getIsReadonly()) return false\n\t\tconst id = editor.getOnlySelectedShapeId()\n\t\tif (!id) return false\n\t\tconst shape = editor.getShape(id)\n\t\tif (!shape || shape.type !== 'arrow') return false\n\t\tif (\n\t\t\t!editor.isInAny(\n\t\t\t\t'select.idle',\n\t\t\t\t'select.pointing_handle',\n\t\t\t\t'select.dragging_handle',\n\t\t\t\t'select.translating',\n\t\t\t\t'arrow.dragging'\n\t\t\t)\n\t\t) {\n\t\t\treturn false\n\t\t}\n\t\tconst bindings = getArrowBindings(editor, shape as TLArrowShape)\n\t\treturn Boolean(bindings.start || bindings.end)\n\t}\n\n\toverride getOverlays(): TLArrowBindingHintOverlay[] {\n\t\tconst id = this.editor.getOnlySelectedShapeId()\n\t\tif (!id) return []\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: 'arrow_binding_hint',\n\t\t\t\ttype: 'arrow_binding_hint',\n\t\t\t\tprops: { arrowId: id },\n\t\t\t},\n\t\t]\n\t}\n\n\toverride render(ctx: CanvasRenderingContext2D, overlays: TLArrowBindingHintOverlay[]): void {\n\t\tconst overlay = overlays[0]\n\t\tif (!overlay) return\n\n\t\tconst editor = this.editor\n\t\tconst shape = editor.getShape(overlay.props.arrowId) as TLArrowShape | undefined\n\t\tif (!shape) return\n\n\t\tconst info = getArrowInfo(editor, shape)\n\t\tif (!info?.isValid) return\n\n\t\tconst bindings = getArrowBindings(editor, shape)\n\t\tif (!bindings.start && !bindings.end) return\n\n\t\tconst pageTransform = editor.getShapePageTransform(shape)\n\t\tif (!pageTransform) return\n\n\t\tconst zoom = editor.getZoomLevel()\n\t\tconst colors = editor.getCurrentTheme().colors[editor.getColorMode()]\n\t\tconst strokeWidth = this.options.strokeWidth / zoom\n\n\t\tctx.save()\n\t\tctx.transform(\n\t\t\tpageTransform.a,\n\t\t\tpageTransform.b,\n\t\t\tpageTransform.c,\n\t\t\tpageTransform.d,\n\t\t\tpageTransform.e,\n\t\t\tpageTransform.f\n\t\t)\n\n\t\tctx.strokeStyle = colors.text\n\t\tctx.fillStyle = colors.text\n\t\tctx.lineWidth = strokeWidth\n\t\tctx.lineCap = 'round'\n\t\tctx.lineJoin = 'round'\n\t\tctx.globalAlpha = this.options.opacity\n\n\t\tif (bindings.start) {\n\t\t\tthis.drawEndpoint(\n\t\t\t\tctx,\n\t\t\t\tinfo,\n\t\t\t\t'start',\n\t\t\t\tbindings.start.props.isExact,\n\t\t\t\tbindings.start.props.isPrecise,\n\t\t\t\tstrokeWidth,\n\t\t\t\tzoom\n\t\t\t)\n\t\t}\n\t\tif (bindings.end) {\n\t\t\tthis.drawEndpoint(\n\t\t\t\tctx,\n\t\t\t\tinfo,\n\t\t\t\t'end',\n\t\t\t\tbindings.end.props.isExact,\n\t\t\t\tbindings.end.props.isPrecise,\n\t\t\t\tstrokeWidth,\n\t\t\t\tzoom\n\t\t\t)\n\t\t}\n\n\t\tctx.restore()\n\t}\n\n\tprivate drawEndpoint(\n\t\tctx: CanvasRenderingContext2D,\n\t\tinfo: TLArrowInfo,\n\t\tside: 'start' | 'end',\n\t\tisExact: boolean,\n\t\tisPrecise: boolean,\n\t\tstrokeWidth: number,\n\t\tzoom: number\n\t) {\n\t\tconst handle = info[side].handle\n\t\tconst point = info[side].point\n\t\tconst dist = Vec.Dist(handle, point)\n\n\t\t// Stop the dashed stub at the marker's outer edge so it doesn't pass\n\t\t// through the dot/cross. The cross's corners (leg endpoints) sit at\n\t\t// half the diagonal of its bounding square, not half its side.\n\t\tconst markerRadius =\n\t\t\t(isPrecise ? (this.options.crossSize / 2) * Math.SQRT2 : this.options.dotRadius) / zoom\n\n\t\tif (dist > markerRadius + 0.5) {\n\t\t\tctx.save()\n\t\t\tctx.beginPath()\n\n\t\t\tlet pathLength: number\n\n\t\t\tif (info.type === 'arc') {\n\t\t\t\t// Render along the body arc so the stub sits on the same circle as\n\t\t\t\t// the visible arrow body; project handle radially onto that circle.\n\t\t\t\tconst { center, radius, sweepFlag } = info.bodyArc\n\t\t\t\tconst pointAngle = Math.atan2(point.y - center.y, point.x - center.x)\n\t\t\t\tconst handleAngle = Math.atan2(handle.y - center.y, handle.x - center.x)\n\t\t\t\tconst anticlockwise = !sweepFlag\n\t\t\t\tconst sign = (sweepFlag ? 1 : -1) * (side === 'start' ? 1 : -1)\n\t\t\t\tconst trimmedHandleAngle = handleAngle + sign * (markerRadius / radius)\n\n\t\t\t\t// Handle and point are close points on the same circle, so the\n\t\t\t\t// stub follows the short arc between them. Use the shortest signed\n\t\t\t\t// angular distance to get the arc length, then trim the marker.\n\t\t\t\tlet handleToPointSweep = pointAngle - handleAngle\n\t\t\t\tif (handleToPointSweep > Math.PI) handleToPointSweep -= PI2\n\t\t\t\telse if (handleToPointSweep < -Math.PI) handleToPointSweep += PI2\n\t\t\t\tpathLength = Math.max(0, radius * Math.abs(handleToPointSweep) - markerRadius)\n\n\t\t\t\tif (side === 'start') {\n\t\t\t\t\tctx.arc(center.x, center.y, radius, trimmedHandleAngle, pointAngle, anticlockwise)\n\t\t\t\t} else {\n\t\t\t\t\tctx.arc(center.x, center.y, radius, pointAngle, trimmedHandleAngle, anticlockwise)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpathLength = dist - markerRadius\n\t\t\t\tconst t = markerRadius / dist\n\t\t\t\tconst trimmedHandle = {\n\t\t\t\t\tx: handle.x + (point.x - handle.x) * t,\n\t\t\t\t\ty: handle.y + (point.y - handle.y) * t,\n\t\t\t\t}\n\t\t\t\tctx.moveTo(trimmedHandle.x, trimmedHandle.y)\n\t\t\t\tctx.lineTo(point.x, point.y)\n\t\t\t}\n\n\t\t\t// Below the dash threshold the dashes get too small to read, so\n\t\t\t// fall back to a solid stub.\n\t\t\tif (zoom >= this.options.dashedMinZoom) {\n\t\t\t\tconst { strokeDasharray, strokeDashoffset } = getPerfectDashProps(pathLength, strokeWidth, {\n\t\t\t\t\tstyle: 'dashed',\n\t\t\t\t\tend: 'skip',\n\t\t\t\t\tstart: 'skip',\n\t\t\t\t})\n\n\t\t\t\tif (strokeDasharray !== 'none') {\n\t\t\t\t\tconst [dashLength, gapLength] = strokeDasharray.split(' ').map(Number)\n\t\t\t\t\tctx.setLineDash([dashLength, gapLength])\n\t\t\t\t\tctx.lineDashOffset = Number(strokeDashoffset)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tctx.stroke()\n\t\t\tctx.restore()\n\t\t}\n\n\t\tif (isExact) return\n\n\t\tconst markerAngle = dist > 0.5 ? this.getMarkerAngle(info, side, handle, point) : 0\n\n\t\tif (isPrecise) {\n\t\t\tconst half = this.options.crossSize / zoom / 2\n\t\t\tctx.save()\n\t\t\tctx.translate(handle.x, handle.y)\n\t\t\tctx.rotate(markerAngle)\n\t\t\tctx.beginPath()\n\t\t\tctx.moveTo(-half, -half)\n\t\t\tctx.lineTo(half, half)\n\t\t\tctx.moveTo(-half, half)\n\t\t\tctx.lineTo(half, -half)\n\t\t\tctx.stroke()\n\t\t\tctx.restore()\n\t\t} else {\n\t\t\tconst radius = this.options.dotRadius / zoom\n\t\t\tctx.beginPath()\n\t\t\tctx.arc(handle.x, handle.y, radius, 0, PI2)\n\t\t\tctx.stroke()\n\t\t}\n\t}\n\n\t/** Tangent direction at the handle, oriented toward the body. */\n\tprivate getMarkerAngle(\n\t\tinfo: TLArrowInfo,\n\t\tside: 'start' | 'end',\n\t\thandle: { x: number; y: number },\n\t\tpoint: { x: number; y: number }\n\t): number {\n\t\tif (info.type === 'arc') {\n\t\t\tconst { center, sweepFlag } = info.bodyArc\n\t\t\tconst radial = Math.atan2(handle.y - center.y, handle.x - center.x)\n\t\t\t// tangent perpendicular to radial; sign chosen to point toward the body\n\t\t\tconst sign = (sweepFlag ? 1 : -1) * (side === 'start' ? 1 : -1)\n\t\t\treturn radial + (sign * Math.PI) / 2\n\t\t}\n\t\treturn Math.atan2(point.y - handle.y, point.x - handle.x)\n\t}\n}\n"],
  "mappings": "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",
  "names": []
}
