@knowvah/dot-engine 1.4.0 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knowvah/dot-engine",
3
- "version": "1.4.0",
3
+ "version": "1.6.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",
@@ -106,6 +106,12 @@ export interface NodeGeometry {
106
106
  * type) still holds calloc-zero coordinates, so it is reported as absent
107
107
  * rather than as a label at the origin.
108
108
  *
109
+ * `xlabel` is the `xlabel` external label, positioned by the force-placement
110
+ * search rather than by spline midpoint arithmetic, so it is not derivable
111
+ * from `label` or `points`. It carries the same `lp->set` gate: a declared
112
+ * xlabel the search could not fit is reported as absent, exactly as
113
+ * `render()` declines to draw it.
114
+ *
109
115
  * `sp`/`ep` are the arrow attachment points. When an end carries an arrow the
110
116
  * spline is shortened to leave room for it, and the arrow spans from the
111
117
  * terminal control point out to this point — so a consumer drawing its own
@@ -119,7 +125,8 @@ export interface NodeGeometry {
119
125
  * (measured: ~1.5pt at `penwidth=1`, ~6.2pt at `penwidth=5`), so `ep` is the
120
126
  * point to draw an arrow *to*, not a copy of the rendered polygon's tip.
121
127
  *
122
- * @see lib/common/types.h:ED_spl, ED_label, ED_tail_label, ED_head_label
128
+ * @see lib/common/types.h:ED_spl, ED_label, ED_tail_label, ED_head_label,
129
+ * ED_xlabel
123
130
  * @see lib/common/types.h:bezier (sflag/eflag, sp/ep)
124
131
  */
125
132
  export interface EdgeGeometry {
@@ -149,6 +156,11 @@ export interface EdgeGeometry {
149
156
  * @see lib/common/types.h:ED_head_label
150
157
  */
151
158
  headLabel?: { x: number; y: number };
159
+ /**
160
+ * `xlabel` (external label) position, if placed.
161
+ * @see lib/common/types.h:ED_xlabel
162
+ */
163
+ xlabel?: { x: number; y: number };
152
164
  }
153
165
 
154
166
  /**
@@ -164,7 +176,15 @@ export interface EdgeGeometry {
164
176
  * `class="cluster"` polygon, so a consumer quantizing to SVG precision gets
165
177
  * byte-conformant geometry.
166
178
  *
179
+ * `label` is the cluster title's placed position and measured size, present
180
+ * only when the cluster declares a label. Unlike the edge port labels, it is
181
+ * *not* gated on the label's `set` flag: C draws a cluster label on existence
182
+ * alone (emit.c:3920 has no `->set` test, unlike emit_edge_label:2891), so an
183
+ * unplaced one still renders at whatever pos it holds. Gating here would hide
184
+ * geometry `render()` acts on.
185
+ *
167
186
  * @see lib/common/types.h:GD_bb (of a cluster subgraph)
187
+ * @see lib/common/types.h:GD_label (textlabel_t.pos / .dimen)
168
188
  */
169
189
  export interface ClusterGeometry {
170
190
  /** Cluster subgraph name (e.g. `cluster6`); encodes nesting. */
@@ -173,6 +193,13 @@ export interface ClusterGeometry {
173
193
  y: number;
174
194
  width: number;
175
195
  height: number;
196
+ /**
197
+ * Cluster label placement, if the cluster has one. `x`/`y` are the **centre**
198
+ * of the label space (matching `EdgeGeometry.label`, not the box corner
199
+ * `x`/`y` above); `width`/`height` are its measured size.
200
+ * @see lib/common/postproc.c:place_graph_label
201
+ */
202
+ label?: { x: number; y: number; width: number; height: number };
176
203
  }
177
204
 
178
205
  /**
@@ -286,8 +313,8 @@ function arrowAttachPoints(
286
313
 
287
314
  /**
288
315
  * Snapshot one edge's geometry.
289
- * @see lib/common/types.h:ED_spl, ED_label, ED_tail_label, ED_head_label
290
- * (textlabel_t.pos), bezier.sp/ep
316
+ * @see lib/common/types.h:ED_spl, ED_label, ED_tail_label, ED_head_label,
317
+ * ED_xlabel (textlabel_t.pos), bezier.sp/ep
291
318
  */
292
319
  function snapshotEdge(edge: Edge, flipY: (y: number) => number): EdgeGeometry {
293
320
  const geom: EdgeGeometry = {
@@ -303,6 +330,8 @@ function snapshotEdge(edge: Edge, flipY: (y: number) => number): EdgeGeometry {
303
330
  if (tailLabel !== undefined) geom.tailLabel = tailLabel;
304
331
  const headLabel = placedLabelPos(edge.info.head_label, flipY);
305
332
  if (headLabel !== undefined) geom.headLabel = headLabel;
333
+ const xlabel = placedLabelPos(edge.info.xlabel, flipY);
334
+ if (xlabel !== undefined) geom.xlabel = xlabel;
306
335
  const { sp, ep } = arrowAttachPoints(edge, flipY);
307
336
  if (sp !== undefined) geom.sp = sp;
308
337
  if (ep !== undefined) geom.ep = ep;
@@ -316,13 +345,18 @@ function snapshotEdge(edge: Edge, flipY: (y: number) => number): EdgeGeometry {
316
345
  * native lower-left corner (ll); `yAxis:'down'` returns the top-left corner
317
346
  * (ll.x, flipped ur.y). `width`/`height` are frame-independent (ur - ll).
318
347
  *
348
+ * The label rides in the same call because place_graph_label runs on the same
349
+ * layout pass that fills GD_bb; `pos` is the centre of the label space, so it
350
+ * flips like any other coordinate rather than like the box corner.
351
+ *
319
352
  * @see lib/common/types.h:GD_bb (cluster subgraph)
353
+ * @see lib/common/postproc.c:place_graph_label
320
354
  */
321
355
  function snapshotCluster(
322
356
  sg: Graph, yAxis: YAxis, flipY: (y: number) => number,
323
357
  ): ClusterGeometry {
324
358
  const bb = sg.info.bb;
325
- return {
359
+ const geom: ClusterGeometry = {
326
360
  name: sg.name,
327
361
  x: bb.ll.x,
328
362
  // 'up' keeps the lower-left y; 'down' flips the upper-right y to the
@@ -331,6 +365,16 @@ function snapshotCluster(
331
365
  width: bb.ur.x - bb.ll.x,
332
366
  height: bb.ur.y - bb.ll.y,
333
367
  };
368
+ const lab = sg.info.label as TextlabelT | undefined;
369
+ if (lab !== undefined) {
370
+ geom.label = {
371
+ x: lab.pos.x,
372
+ y: flipY(lab.pos.y),
373
+ width: lab.dimen.x,
374
+ height: lab.dimen.y,
375
+ };
376
+ }
377
+ return geom;
334
378
  }
335
379
 
336
380
  /**