@knowvah/dot-engine 1.2.7 → 1.4.0
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/dist/api/geometry.d.ts +54 -1
- package/dist/api/geometry.d.ts.map +1 -1
- package/dist/api.js +21 -0
- package/dist/api.js.map +2 -2
- package/dist/index.js +21 -0
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/src/api/geometry.ts +91 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knowvah/dot-engine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Faithful TypeScript port of Graphviz (dot, neato, fdp, sfdp, circo, twopi, osage, patchwork) — no C: no native binary, no WASM. Oracle-verified against the C implementation, runs in the browser.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graphviz",
|
package/src/api/geometry.ts
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
import type { Graph } from '../model/graph.js';
|
|
34
34
|
import type { Node } from '../model/node.js';
|
|
35
35
|
import type { Edge } from '../model/edge.js';
|
|
36
|
+
import type { TextlabelT } from '../common/types.js';
|
|
36
37
|
import { RenderError } from '../errors.js';
|
|
37
38
|
|
|
38
39
|
// ---------------------------------------------------------------------------
|
|
@@ -98,15 +99,56 @@ export interface NodeGeometry {
|
|
|
98
99
|
* in order. An edge with no routed spline produces an empty `points` array.
|
|
99
100
|
* `label` is present only when the edge carries a centre label.
|
|
100
101
|
*
|
|
101
|
-
*
|
|
102
|
+
* `tailLabel`/`headLabel` are the `taillabel`/`headlabel` port labels. They
|
|
103
|
+
* are present only once the layout has actually *placed* them (C `lp->set`),
|
|
104
|
+
* which is the same gate `render()` applies before emitting the `<text>`:
|
|
105
|
+
* a declared port label that place_portlabel skipped (no spline, IGNORED edge
|
|
106
|
+
* type) still holds calloc-zero coordinates, so it is reported as absent
|
|
107
|
+
* rather than as a label at the origin.
|
|
108
|
+
*
|
|
109
|
+
* `sp`/`ep` are the arrow attachment points. When an end carries an arrow the
|
|
110
|
+
* spline is shortened to leave room for it, and the arrow spans from the
|
|
111
|
+
* terminal control point out to this point — so a consumer drawing its own
|
|
112
|
+
* arrowheads reads the tip here instead of extrapolating one. Each is present
|
|
113
|
+
* only when that end actually has an arrow (C `sflag`/`eflag`); with no arrow
|
|
114
|
+
* the field holds the calloc-zero point, which is not geometry.
|
|
115
|
+
*
|
|
116
|
+
* These are the *attachment* points on the node boundary, verbatim from the
|
|
117
|
+
* bezier — with `arrowhead=none` the spline simply ends there. Graphviz's own
|
|
118
|
+
* renderer insets the arrow polygon it draws by a penwidth-dependent amount
|
|
119
|
+
* (measured: ~1.5pt at `penwidth=1`, ~6.2pt at `penwidth=5`), so `ep` is the
|
|
120
|
+
* point to draw an arrow *to*, not a copy of the rendered polygon's tip.
|
|
121
|
+
*
|
|
122
|
+
* @see lib/common/types.h:ED_spl, ED_label, ED_tail_label, ED_head_label
|
|
123
|
+
* @see lib/common/types.h:bezier (sflag/eflag, sp/ep)
|
|
102
124
|
*/
|
|
103
125
|
export interface EdgeGeometry {
|
|
104
126
|
tail: string;
|
|
105
127
|
head: string;
|
|
106
128
|
/** Bezier control points for the edge spline, in points. */
|
|
107
129
|
points: { x: number; y: number }[];
|
|
130
|
+
/**
|
|
131
|
+
* Arrow attachment point at the tail end, if that end carries an arrow.
|
|
132
|
+
* @see lib/common/types.h:bezier.sp
|
|
133
|
+
*/
|
|
134
|
+
sp?: { x: number; y: number };
|
|
135
|
+
/**
|
|
136
|
+
* Arrow attachment point at the head end, if that end carries an arrow.
|
|
137
|
+
* @see lib/common/types.h:bezier.ep
|
|
138
|
+
*/
|
|
139
|
+
ep?: { x: number; y: number };
|
|
108
140
|
/** Centre edge label position, if present. @see lib/common/types.h:ED_label */
|
|
109
141
|
label?: { x: number; y: number };
|
|
142
|
+
/**
|
|
143
|
+
* `taillabel` position, if placed.
|
|
144
|
+
* @see lib/common/types.h:ED_tail_label
|
|
145
|
+
*/
|
|
146
|
+
tailLabel?: { x: number; y: number };
|
|
147
|
+
/**
|
|
148
|
+
* `headlabel` position, if placed.
|
|
149
|
+
* @see lib/common/types.h:ED_head_label
|
|
150
|
+
*/
|
|
151
|
+
headLabel?: { x: number; y: number };
|
|
110
152
|
}
|
|
111
153
|
|
|
112
154
|
/**
|
|
@@ -203,9 +245,49 @@ function collectEdgePoints(
|
|
|
203
245
|
return pts;
|
|
204
246
|
}
|
|
205
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Position of a port label that layout actually placed, else undefined.
|
|
250
|
+
* `set` is C's own "this label has coordinates" flag, and the gate
|
|
251
|
+
* emit_edge_label uses before drawing; an unplaced label still holds the
|
|
252
|
+
* calloc-zero pos and must not be published as geometry.
|
|
253
|
+
* @see lib/common/splines.c:place_portlabel (l->set = TRUE)
|
|
254
|
+
* @see lib/common/emit.c:emit_edge_label (lbl == NULL || !lbl->set)
|
|
255
|
+
*/
|
|
256
|
+
function placedLabelPos(
|
|
257
|
+
lbl: TextlabelT | undefined,
|
|
258
|
+
flipY: (y: number) => number,
|
|
259
|
+
): { x: number; y: number } | undefined {
|
|
260
|
+
if (lbl === undefined || !lbl.set) return undefined;
|
|
261
|
+
return { x: lbl.pos.x, y: flipY(lbl.pos.y) };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Arrow attachment points, one per end that actually carries an arrow.
|
|
266
|
+
* C keeps `sp`/`ep` beside the control points and gates them on
|
|
267
|
+
* `sflag`/`eflag`; with no arrow at that end the flag is 0 and the point is
|
|
268
|
+
* still calloc-zero, so an ungated read would publish (0, 0) as geometry.
|
|
269
|
+
* Indexes the bezier array by `spl.size` (not `list.length`), matching C.
|
|
270
|
+
* @see lib/common/types.h:bezier
|
|
271
|
+
* @see lib/common/postproc.c:endPoints
|
|
272
|
+
*/
|
|
273
|
+
function arrowAttachPoints(
|
|
274
|
+
edge: Edge,
|
|
275
|
+
flipY: (y: number) => number,
|
|
276
|
+
): { sp?: { x: number; y: number }; ep?: { x: number; y: number } } {
|
|
277
|
+
const spl = edge.info.spl;
|
|
278
|
+
if (spl === undefined || spl.size === 0) return {};
|
|
279
|
+
const out: { sp?: { x: number; y: number }; ep?: { x: number; y: number } } = {};
|
|
280
|
+
const first = spl.list[0];
|
|
281
|
+
if (first.sflag !== 0) out.sp = { x: first.sp.x, y: flipY(first.sp.y) };
|
|
282
|
+
const last = spl.list[spl.size - 1];
|
|
283
|
+
if (last.eflag !== 0) out.ep = { x: last.ep.x, y: flipY(last.ep.y) };
|
|
284
|
+
return out;
|
|
285
|
+
}
|
|
286
|
+
|
|
206
287
|
/**
|
|
207
288
|
* Snapshot one edge's geometry.
|
|
208
|
-
* @see lib/common/types.h:ED_spl, ED_label
|
|
289
|
+
* @see lib/common/types.h:ED_spl, ED_label, ED_tail_label, ED_head_label
|
|
290
|
+
* (textlabel_t.pos), bezier.sp/ep
|
|
209
291
|
*/
|
|
210
292
|
function snapshotEdge(edge: Edge, flipY: (y: number) => number): EdgeGeometry {
|
|
211
293
|
const geom: EdgeGeometry = {
|
|
@@ -217,6 +299,13 @@ function snapshotEdge(edge: Edge, flipY: (y: number) => number): EdgeGeometry {
|
|
|
217
299
|
if (lbl !== undefined) {
|
|
218
300
|
geom.label = { x: lbl.pos.x, y: flipY(lbl.pos.y) };
|
|
219
301
|
}
|
|
302
|
+
const tailLabel = placedLabelPos(edge.info.tail_label, flipY);
|
|
303
|
+
if (tailLabel !== undefined) geom.tailLabel = tailLabel;
|
|
304
|
+
const headLabel = placedLabelPos(edge.info.head_label, flipY);
|
|
305
|
+
if (headLabel !== undefined) geom.headLabel = headLabel;
|
|
306
|
+
const { sp, ep } = arrowAttachPoints(edge, flipY);
|
|
307
|
+
if (sp !== undefined) geom.sp = sp;
|
|
308
|
+
if (ep !== undefined) geom.ep = ep;
|
|
220
309
|
return geom;
|
|
221
310
|
}
|
|
222
311
|
|