@kekonic/diagrams-routing 1.0.0-rc.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kekonic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # @kekonic/diagrams-routing
2
+
3
+ Post-layout edge finishing for KDiagram: route-style refinement, crossing treatment, endpoint trim, and label placement types.
4
+
5
+ ## Scope
6
+
7
+ - Route styles: `metro` / `rounded` / `bezier` refine the laid-out corridor into
8
+ organic cubics (port ease + curved avoidance); `orthogonal` keeps sharp corners;
9
+ `straight` shortcuts a clear corridor
10
+ - Crossing modes: `none` / `gaps` / `jumps` / `smart`
11
+ - Arrowhead / crow's-foot endpoint insets
12
+ - Shared `RoutedEdge` / `TreatedEdge` / `EdgeLabelPlacement` types
13
+
14
+ Orthogonal corridors normally come from ELK (or region-arrange stubs). This package does **not** search a new route grid; it shortens or smooths the corridor it was given.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pnpm add @kekonic/diagrams-routing
20
+ ```
21
+
22
+ Prefer the meta package `@kekonic/diagrams` for the full pipeline.
23
+
24
+ ## Related
25
+
26
+ - Layout: `@kekonic/diagrams-layout`
27
+ - Pipeline boundaries: [`docs/architecture/pipeline.md`](../../docs/architecture/pipeline.md)
@@ -0,0 +1,162 @@
1
+ import { PerimeterAttachInput, attachPointOnPerimeter } from "@kekonic/diagrams-geometry";
2
+ import { CrossingMode, Diagnostic, EdgeArrows, EdgeKind, Point, Rect, RouteMode } from "@kekonic/diagrams-core";
3
+ //#region src/routing/path-style.d.ts
4
+ type CubicBezier = {
5
+ from: Point;
6
+ c1: Point;
7
+ c2: Point;
8
+ to: Point;
9
+ };
10
+ type RouteStyleEdge = {
11
+ edgeId: string;
12
+ fromId: string;
13
+ toId: string;
14
+ points: Point[];
15
+ };
16
+ type RouteStyleObstacle = {
17
+ id: string;
18
+ bounds: Rect;
19
+ };
20
+ type RefinedRoute = {
21
+ edgeId: string;
22
+ points: Point[];
23
+ cubics?: CubicBezier[];
24
+ };
25
+ type OrganicRouteOptions = {
26
+ mode?: "metro" | "rounded" | "bezier";
27
+ t0?: Point;
28
+ t1?: Point;
29
+ cornerRadius?: number;
30
+ };
31
+ export declare function collapseColinear(points: Point[], eps?: number): Point[];
32
+ /**
33
+ * True when the open segment stabs the open interior of `box`.
34
+ * Grazing a face does not count — attach points sit on silhouettes.
35
+ */
36
+ export declare function segmentHitsAabb(a: Point, b: Point, box: Rect): boolean;
37
+ /**
38
+ * Keep original waypoints, skipping any that the chord can see around.
39
+ * Clear line of sight → `[start, end]`. Otherwise a minimal dogleg from the
40
+ * existing corridor — never a silent punch through a third-party node.
41
+ */
42
+ export declare function shortcutStraight(points: Point[], obstacles: Rect[]): Point[];
43
+ export declare function sampleCubics(cubics: CubicBezier[], steps?: number): Point[];
44
+ /**
45
+ * Outward unit normal of the silhouette face `point` sits on.
46
+ * Corner ties prefer `fallback` (usually the corridor stub).
47
+ */
48
+ export declare function silhouetteNormal(point: Point, box: Rect, fallback: Point): Point;
49
+ /**
50
+ * Obstacle-aware cubic spline along an orthogonal channel.
51
+ *
52
+ * Clear line of sight → one cubic with port-normal handles (ease out of the
53
+ * source, ease into the target). Otherwise each corridor elbow becomes its own
54
+ * curved section — not a sharp Manhattan stair.
55
+ */
56
+ export declare function fitOrganicRoute(points: Point[], obstacles: Rect[], options?: OrganicRouteOptions): CubicBezier[];
57
+ /** Smart-bezier: organic cubics with the bezier handle profile. */
58
+ export declare function fitSmartBezier(points: Point[], obstacles: Rect[], ports?: {
59
+ t0?: Point;
60
+ t1?: Point;
61
+ }): CubicBezier[];
62
+ export declare function cubicsToPath(cubics: CubicBezier[]): string;
63
+ /**
64
+ * Refine laid-out orthogonal polylines for the requested route mode.
65
+ * `orthogonal` stays a sharp polyline. Metro / rounded / bezier become organic
66
+ * cubics (port ease + curved avoidance). Straight still shortcuts the corridor.
67
+ */
68
+ export declare function refineRouteStyle(edges: RouteStyleEdge[], obstacles: RouteStyleObstacle[], mode: RouteMode | undefined, parallel?: "separate" | "shared", cornerRadius?: number): RefinedRoute[];
69
+ //#endregion
70
+ //#region src/routing/types.d.ts
71
+ type RoutedEdge = {
72
+ edgeId: string;
73
+ points: Point[];
74
+ segments: Array<{
75
+ from: Point;
76
+ to: Point;
77
+ }>;
78
+ /** Organic cubics for metro / rounded / bezier. Crossing treatment may flatten these. */
79
+ cubics?: CubicBezier[];
80
+ };
81
+ /** Post-ELK edge geometry after label placement and endpoint trim. */
82
+ type RoutingResult = {
83
+ edges: RoutedEdge[];
84
+ algorithmVersion: string;
85
+ routeMs: number;
86
+ diagnostics: Diagnostic[];
87
+ };
88
+ //#endregion
89
+ //#region src/crossings/treat.d.ts
90
+ /** Tip extends past the path end (toward the node) by this much. */
91
+ export declare const ARROW_MARKER_TIP_OVERHANG: number;
92
+ /** Target trim: tip lands on the outer node stroke; dash/solid stop at the arrow base. */
93
+ export declare const ARROW_ENDPOINT_INSET: number;
94
+ type FlowArrowEnds = {
95
+ start: boolean;
96
+ end: boolean;
97
+ };
98
+ /** Whether an edge paints flow arrowheads at the path start and/or end. */
99
+ export declare function flowArrowEnds(edge: {
100
+ kind: EdgeKind;
101
+ arrows?: EdgeArrows;
102
+ } | undefined, showArrowheads: boolean): FlowArrowEnds;
103
+ /**
104
+ * Crow's-foot tip sits on the path endpoint (marker refX), unlike arrows whose tip
105
+ * overhangs past refX. Keep only a hairline gap so the tip kisses the table stroke.
106
+ */
107
+ export declare const CARDINALITY_ENDPOINT_INSET: number;
108
+ /** Small inset for edges without arrowheads — clears node stroke at connection. */
109
+ export declare const EDGE_ENDPOINT_INSET = 1;
110
+ type RenderedEdgeSegment = {
111
+ type: "line";
112
+ from: Point;
113
+ to: Point;
114
+ } | {
115
+ type: "cubic";
116
+ from: Point;
117
+ c1: Point;
118
+ c2: Point;
119
+ to: Point;
120
+ } | {
121
+ type: "gap";
122
+ from: Point;
123
+ to: Point;
124
+ } | {
125
+ type: "jump";
126
+ from: Point;
127
+ to: Point;
128
+ radius: number;
129
+ };
130
+ type TreatedEdge = {
131
+ edgeId: string;
132
+ segments: RenderedEdgeSegment[];
133
+ };
134
+ export declare function applyCrossingTreatment(edges: RoutedEdge[], mode: CrossingMode): TreatedEdge[];
135
+ /** Crossing points between distinct edge segments (for label scoring). */
136
+ export declare function detectCrossingPoints(edges: RoutedEdge[]): Point[];
137
+ type TrimEdgeEndpointsOptions = {
138
+ /** Uniform source inset, or per-edge via callback. */
139
+ sourceInset?: number | ((edgeId: string) => number);
140
+ /** Uniform target inset, or per-edge via callback. */
141
+ targetInset?: number | ((edgeId: string) => number);
142
+ };
143
+ /** Shorten first/last strokes so arrowheads stop on the outer node stroke. */
144
+ export declare function trimEdgeEndpoints(edges: TreatedEdge[], options?: TrimEdgeEndpointsOptions): TreatedEdge[];
145
+ //#endregion
146
+ //#region src/labels/types.d.ts
147
+ /** Edge label bounds produced by ELK and painted by the SVG renderer. */
148
+ type EdgeLabelPlacement = {
149
+ edgeId: string;
150
+ text: string;
151
+ bounds: Rect;
152
+ anchor: Point;
153
+ };
154
+ /** Icon size inside an edge-label pill (logical units). Keep in sync with SVG paint. */
155
+ export declare const EDGE_LABEL_ICON = 12;
156
+ /** Gap between edge-label icon and text. */
157
+ export declare const EDGE_LABEL_ICON_GAP = 4;
158
+ /** Horizontal padding inside the edge-label pill. */
159
+ export declare const EDGE_LABEL_PAD_X = 8;
160
+ //#endregion
161
+ export { type CubicBezier, type EdgeLabelPlacement, type FlowArrowEnds, type OrganicRouteOptions, type PerimeterAttachInput, type RefinedRoute, type RenderedEdgeSegment, type RouteStyleEdge, type RouteStyleObstacle, type RoutedEdge, type RoutingResult, type TreatedEdge, attachPointOnPerimeter };
162
+ //# sourceMappingURL=index.d.mts.map