tldraw
Version:
A tiny little drawing editor.
8 lines (7 loc) • 10.3 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../../../src/lib/shapes/arrow/elbow/definitions.ts"],
"sourcesContent": ["import { Box, ElbowArrowSnap, Geometry2d, TLShapeId, Vec, VecLike, VecModel } from '@tldraw/editor'\n\n/**\n * The side of a box that an elbow arrow could enter/exit from.\n * @public\n */\nexport type ElbowArrowSide = 'top' | 'right' | 'bottom' | 'left'\n\n/**\n * The reason a particular side of a shape was chosen for an elbow arrow to enter / exit. Used only\n * for debugging information.\n *\n * - `manual`: The side was chosen because the user indicated this was the desired side\n * - `auto`: The side was chosen automatically based on heuristics for nice-looking arrows\n * - `fallback`: We couldn't draw a route to the edge the user indicated, so fell back to our\n * heuristics\n *\n * @internal\n */\nexport type ElbowArrowSideReason = 'manual' | 'auto' | 'fallback'\n\n/**\n * A route for an elbow arrow.\n *\n * @public\n */\nexport interface ElbowArrowRoute {\n\t/**\n\t * The name of the route - this is used only for debugging.\n\t * @internal\n\t */\n\tname: string\n\t/** The vertices of the route. Draw a line through them to see the route. */\n\tpoints: Vec[]\n\t/** The total distance of the route, in arrow-space pixels. */\n\tdistance: number\n\t/**\n\t * Why did we pick edge A?\n\t * @internal\n\t */\n\taEdgePicking: ElbowArrowSideReason\n\t/**\n\t * Why did we pick edge B?\n\t * @internal\n\t */\n\tbEdgePicking: ElbowArrowSideReason\n\t/**\n\t * Some points on the line are there for more informative than display reasons - e.g. where the\n\t * midpoint handle is. If we draw these in our \"draw\" style, the line will look weird. We still\n\t * need them for some of the calculations we do, but we want to skip them specifically when\n\t * rendering the arrow.\n\t */\n\tskipPointsWhenDrawing: Set<Vec>\n\t/**\n\t * The midpoint handle of the route, if any.\n\t */\n\tmidpointHandle: ElbowArrowMidpointHandle | null\n}\n\n/**\n * Part of an {@link ElbowArrowRoute} that describes a handle for dragging the midpoint line, a line\n * roughly halfway between the two shapes.\n * @public\n */\nexport interface ElbowArrowMidpointHandle {\n\taxis: 'x' | 'y'\n\t/** The start point of the segment in the route that the handle is on. */\n\tsegmentStart: VecLike\n\t/** The end point of the segment in the route that the handle is on. */\n\tsegmentEnd: VecLike\n\t/** The position of the handle, in arrow-space. */\n\tpoint: VecLike\n}\n\nexport const ElbowArrowSides = ['right', 'bottom', 'left', 'top'] as const\n\n/**\n * Extracted from {@link ArrowShapeOptions}. Options for one specific arrow.\n * @public\n */\nexport interface ElbowArrowOptions {\n\texpandElbowLegLength: number\n\tminElbowLegLength: number\n\telbowMidpoint: number\n}\n\n/**\n * Vectors that point out of each side of a box.\n */\nexport const ElbowArrowSideDeltas = {\n\ttop: { x: 0, y: -1 },\n\tright: { x: 1, y: 0 },\n\tbottom: { x: 0, y: 1 },\n\tleft: { x: -1, y: 0 },\n} as const satisfies Record<ElbowArrowSide, VecModel>\n\n/**\n * The axis along when each side of a box lies.\n */\nexport const ElbowArrowSideAxes = {\n\tleft: 'x',\n\tright: 'x',\n\ttop: 'y',\n\tbottom: 'y',\n} as const satisfies Record<ElbowArrowSide, 'x' | 'y'>\n\n/**\n * The opposite of each side of a box.\n */\nexport const ElbowArrowSideOpposites = {\n\ttop: 'bottom',\n\tright: 'left',\n\tbottom: 'top',\n\tleft: 'right',\n} as const satisfies Record<ElbowArrowSide, ElbowArrowSide>\n\nexport const ElbowArrowAxes = {\n\tx: {\n\t\tv: (x: number, y: number) => new Vec(x, y),\n\t\tloEdge: 'left',\n\t\thiEdge: 'right',\n\t\tcrossMid: 'midY',\n\t\tgap: 'gapX',\n\t\tmidRange: 'midXRange',\n\t\tself: 'x',\n\t\tcross: 'y',\n\t\tsize: 'width',\n\t},\n\ty: {\n\t\tv: (y: number, x: number) => new Vec(x, y),\n\t\tloEdge: 'top',\n\t\thiEdge: 'bottom',\n\t\tcrossMid: 'midX',\n\t\tgap: 'gapY',\n\t\tmidRange: 'midYRange',\n\t\tself: 'y',\n\t\tcross: 'x',\n\t\tsize: 'height',\n\t},\n} as const\n\nexport type ElbowArrowAxis = (typeof ElbowArrowAxes)[keyof typeof ElbowArrowAxes]\n\nexport type ElbowArrowSideWithAxis = ElbowArrowSide | 'x' | 'y'\n\n/** @public */\nexport interface ElbowArrowBoxes {\n\t/** The starting bounding box */\n\tA: Box\n\t/** The ending bounding box */\n\tB: Box\n\t/** The common bounding box of A and B */\n\tcommon: Box\n}\n\n/** @public */\nexport interface ElbowArrowRange {\n\tmin: number\n\tmax: number\n}\n\n/**\n * An edge on a box.\n * @public\n */\nexport interface ElbowArrowEdge {\n\t/**\n\t * The co-ordinate of the edge. An x-coordinate if left/right, a y-coordinate if top/bottom.\n\t */\n\tvalue: number\n\t/**\n\t * The co-ordinate of the edge, expanded by {@link ArrowShapeOptions.expandElbowLegLength}. May\n\t * be null if the target is a point.\n\t */\n\texpanded: number | null\n\t/**\n\t * The usable range of the edge along its cross-axis. Y-coordinates if left/right, x-coordinated\n\t * if top/bottom.\n\t */\n\tcross: ElbowArrowRange\n\t/**\n\t * The point of the target along the edge, constrained to within {@link ElbowArrowEdge.cross}.\n\t */\n\tcrossTarget: number\n\t/**\n\t * Whether the cross-axis range is shrunk from the original range to make space for the other shape.\n\t */\n\tisPartial: boolean\n}\n\n/**\n * The usable range of the edges of a box. Each edge might be null if the edge is not usable for\n * entry/exit.\n * @public\n */\nexport interface ElbowArrowBoxEdges {\n\ttop: ElbowArrowEdge | null\n\tright: ElbowArrowEdge | null\n\tbottom: ElbowArrowEdge | null\n\tleft: ElbowArrowEdge | null\n}\n\n/**\n * @public\n */\nexport interface ElbowArrowBox {\n\t/** The original bounding box */\n\toriginal: Box\n\t/**\n\t * The bounding box, expanded by {@link ArrowShapeOptions.expandElbowLegLength}.\n\t */\n\texpanded: Box\n}\n\n/**\n * @public\n */\nexport interface ElbowArrowTargetBox extends ElbowArrowBox {\n\t/** What specific point in the box are we aiming for? */\n\ttarget: Vec\n\t/**\n\t * If true, the arrow should end at `target`. If false, the arrow should end at the edge of the\n\t * shape, pointing at `target`.\n\t */\n\tisExact: boolean\n\t/**\n\t * How far away from this box should the arrow terminate to leave space for the arrowhead?\n\t */\n\tarrowheadOffset: number\n\t/**\n\t * The minimum length of the segment of the arrow that actually reaches the target - and has the\n\t * arrowhead on it.\n\t */\n\tminEndSegmentLength: number\n\t/**\n\t * The usable edges of the box.\n\t */\n\tedges: ElbowArrowBoxEdges\n\t/**\n\t * The geometry of the bound shape, in arrow space.\n\t */\n\tgeometry: Geometry2d | null\n\t/**\n\t * Are we treating this target as a single point in space rather than a bounding box?\n\t */\n\tisPoint: boolean\n}\n\n/** @public */\nexport interface ElbowArrowInfoWithoutRoute {\n\t/**\n\t * The options used for this elbow arrow\n\t */\n\toptions: ElbowArrowOptions\n\n\t/**\n\t * If false, A is the start shape and B is the end shape. If true, A is the end shape and B is\n\t * the start shape.\n\t */\n\tswapOrder: boolean\n\n\t/**\n\t * One of the two shapes we're drawing an arrow between. Could be either the start or end\n\t * depending on `swapOrder`.\n\t */\n\tA: ElbowArrowTargetBox\n\t/**\n\t * The other shape we're drawing an arrow between. Could be either the start or end\n\t * depending on `swapOrder`.\n\t */\n\tB: ElbowArrowTargetBox\n\t/**\n\t * The common bounding box of A and B.\n\t */\n\tcommon: ElbowArrowBox\n\n\t/**\n\t * The gap between the right edge of A and the left edge of B.\n\t */\n\tgapX: number\n\t/**\n\t * The gap between the bottom edge of A and the top edge of B.\n\t */\n\tgapY: number\n\t/**\n\t * The X coordinate of the middle line between the two boxes. If the boxes are too close or\n\t * overlap, this may be null.\n\t */\n\tmidX: number | null\n\t/**\n\t * The Y coordinate of the middle line between the two boxes. If the boxes are too close or\n\t * overlap, this may be null.\n\t */\n\tmidY: number | null\n}\n\n/** @public */\nexport interface ElbowArrowInfo extends ElbowArrowInfoWithoutRoute {\n\t/**\n\t * The route of the arrow.\n\t */\n\troute: ElbowArrowRoute | null\n\n\tmidXRange: { lo: number; hi: number } | null\n\tmidYRange: { lo: number; hi: number } | null\n}\n\nexport interface ElbowArrowTerminal {\n\t/**\n\t * The id of the shape we're binding to, if any.\n\t */\n\ttargetShapeId: TLShapeId | null\n\t/**\n\t * The side of the box that the arrow should enter from.\n\t */\n\tside: ElbowArrowSideWithAxis | null\n\t/**\n\t * The bounding box of the shape. May have width/height of 0 if the shape is a point.\n\t */\n\tbounds: Box\n\t/**\n\t * The geometry of the we're binding to, if it exists.\n\t */\n\tgeometry: Geometry2d | null\n\t/**\n\t * The target point of the arrow.\n\t */\n\ttarget: Vec\n\t/**\n\t * How far away from the target should the arrow terminate to leave space for the arrowhead?\n\t */\n\tarrowheadOffset: number\n\t/**\n\t * The minimum length of the segment of the arrow that actually reaches the target - and has the\n\t * arrowhead on it.\n\t */\n\tminEndSegmentLength: number\n\t/**\n\t * Whether the target is an exact point. within a shape's geometry.\n\t */\n\tisExact: boolean\n\t/**\n\t * Whether the target is a point, rather than a bounding box\n\t */\n\tisPoint: boolean\n\t/**\n\t * How did this binding get snapped to the target shape?\n\t */\n\tsnap: ElbowArrowSnap\n}\n"],
"mappings": "AAAA,SAAqD,WAA8B;AA0E5E,MAAM,kBAAkB,CAAC,SAAS,UAAU,QAAQ,KAAK;AAezD,MAAM,uBAAuB;AAAA,EACnC,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG;AAAA,EACnB,OAAO,EAAE,GAAG,GAAG,GAAG,EAAE;AAAA,EACpB,QAAQ,EAAE,GAAG,GAAG,GAAG,EAAE;AAAA,EACrB,MAAM,EAAE,GAAG,IAAI,GAAG,EAAE;AACrB;AAKO,MAAM,qBAAqB;AAAA,EACjC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AAAA,EACL,QAAQ;AACT;AAKO,MAAM,0BAA0B;AAAA,EACtC,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AACP;AAEO,MAAM,iBAAiB;AAAA,EAC7B,GAAG;AAAA,IACF,GAAG,CAAC,GAAW,MAAc,IAAI,IAAI,GAAG,CAAC;AAAA,IACzC,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,KAAK;AAAA,IACL,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,EACP;AAAA,EACA,GAAG;AAAA,IACF,GAAG,CAAC,GAAW,MAAc,IAAI,IAAI,GAAG,CAAC;AAAA,IACzC,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,KAAK;AAAA,IACL,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,EACP;AACD;",
"names": []
}