@knowvah/dot-engine 2.6.11 → 2.7.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/README.md +1 -1
- package/dist/api.js +18 -4
- package/dist/api.js.map +3 -3
- package/dist/async/render-async.d.ts.map +1 -1
- package/dist/common/agerr.d.ts +37 -0
- package/dist/common/agerr.d.ts.map +1 -0
- package/dist/common/arrows-shapes-poly.d.ts.map +1 -1
- package/dist/common/color.d.ts.map +1 -1
- package/dist/common/crand.d.ts +0 -20
- package/dist/common/crand.d.ts.map +1 -1
- package/dist/common/emit-once.d.ts +6 -0
- package/dist/common/emit-once.d.ts.map +1 -0
- package/dist/common/graph-init.d.ts.map +1 -1
- package/dist/common/htmltable-attr-warn.d.ts.map +1 -1
- package/dist/common/htmltable-emit-fill.d.ts +29 -2
- package/dist/common/htmltable-emit-fill.d.ts.map +1 -1
- package/dist/common/htmltable-emit-rules.d.ts.map +1 -1
- package/dist/common/htmltable-emit.d.ts.map +1 -1
- package/dist/common/htmltable-lex-expat.d.ts +1 -6
- package/dist/common/htmltable-lex-expat.d.ts.map +1 -1
- package/dist/common/htmltable-pos-runs.d.ts +7 -4
- package/dist/common/htmltable-pos-runs.d.ts.map +1 -1
- package/dist/common/htmltable.d.ts +1 -7
- package/dist/common/htmltable.d.ts.map +1 -1
- package/dist/common/libm-trig.d.ts +5 -0
- package/dist/common/libm-trig.d.ts.map +1 -0
- package/dist/common/multicolor.d.ts +21 -13
- package/dist/common/multicolor.d.ts.map +1 -1
- package/dist/common/poly-gencode.d.ts +1 -2
- package/dist/common/poly-gencode.d.ts.map +1 -1
- package/dist/common/poly-init.d.ts.map +1 -1
- package/dist/common/postproc.d.ts.map +1 -1
- package/dist/common/random.d.ts.map +1 -1
- package/dist/common/render-state.d.ts +8 -0
- package/dist/common/render-state.d.ts.map +1 -0
- package/dist/common/splines-clip.d.ts +7 -0
- package/dist/common/splines-clip.d.ts.map +1 -1
- package/dist/common/splines-geom.d.ts +8 -0
- package/dist/common/splines-geom.d.ts.map +1 -1
- package/dist/common/splines-routespl.d.ts.map +1 -1
- package/dist/common/textmeasure-lookup.d.ts.map +1 -1
- package/dist/common/textmeasure.d.ts.map +1 -1
- package/dist/gvc/anchor.d.ts.map +1 -1
- package/dist/gvc/context.d.ts +6 -0
- package/dist/gvc/context.d.ts.map +1 -1
- package/dist/gvc/device-cluster.d.ts +15 -0
- package/dist/gvc/device-cluster.d.ts.map +1 -1
- package/dist/gvc/device-labels.d.ts +14 -0
- package/dist/gvc/device-labels.d.ts.map +1 -1
- package/dist/gvc/device.d.ts.map +1 -1
- package/dist/gvc/first-layer.d.ts +9 -0
- package/dist/gvc/first-layer.d.ts.map +1 -0
- package/dist/gvc/gvrender-set-style.d.ts +28 -0
- package/dist/gvc/gvrender-set-style.d.ts.map +1 -0
- package/dist/gvc/usershape.d.ts +18 -0
- package/dist/gvc/usershape.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3169 -1296
- package/dist/index.js.map +4 -4
- package/dist/layout/dot/cluster.d.ts.map +1 -1
- package/dist/layout/dot/compound.d.ts.map +1 -1
- package/dist/layout/dot/conc.d.ts.map +1 -1
- package/dist/layout/dot/decomp.d.ts.map +1 -1
- package/dist/layout/dot/edge-route-clip.d.ts +32 -14
- package/dist/layout/dot/edge-route-clip.d.ts.map +1 -1
- package/dist/layout/dot/edge-route-routing.d.ts.map +1 -1
- package/dist/layout/dot/mincross-build.d.ts.map +1 -1
- package/dist/layout/dot/mincross-cross.d.ts.map +1 -1
- package/dist/layout/dot/rank.d.ts.map +1 -1
- package/dist/layout/dot/splines.d.ts.map +1 -1
- package/dist/layout/fdp/index.d.ts.map +1 -1
- package/dist/layout/fdp/tlayout-parms.d.ts.map +1 -1
- package/dist/layout/fdp/xlayout.d.ts.map +1 -1
- package/dist/layout/neato/__fixtures__/dijkstra-f.d.ts +11 -0
- package/dist/layout/neato/__fixtures__/dijkstra-f.d.ts.map +1 -0
- package/dist/layout/neato/__fixtures__/hier-imds.d.ts +36 -0
- package/dist/layout/neato/__fixtures__/hier-imds.d.ts.map +1 -0
- package/dist/layout/neato/__fixtures__/hier-majorization.d.ts +32 -0
- package/dist/layout/neato/__fixtures__/hier-majorization.d.ts.map +1 -0
- package/dist/layout/neato/cdt-surface.d.ts.map +1 -1
- package/dist/layout/neato/compute-hierarchy.d.ts +24 -0
- package/dist/layout/neato/compute-hierarchy.d.ts.map +1 -0
- package/dist/layout/neato/conjgrad-mkernel.d.ts +20 -0
- package/dist/layout/neato/conjgrad-mkernel.d.ts.map +1 -0
- package/dist/layout/neato/conjgrad.d.ts +19 -0
- package/dist/layout/neato/conjgrad.d.ts.map +1 -1
- package/dist/layout/neato/constrained-majorization.d.ts +26 -0
- package/dist/layout/neato/constrained-majorization.d.ts.map +1 -0
- package/dist/layout/neato/dijkstra.d.ts +33 -16
- package/dist/layout/neato/dijkstra.d.ts.map +1 -1
- package/dist/layout/neato/edge-len.d.ts.map +1 -1
- package/dist/layout/neato/fdp-adjust.d.ts.map +1 -1
- package/dist/layout/neato/gts-triangle.d.ts +14 -0
- package/dist/layout/neato/gts-triangle.d.ts.map +1 -0
- package/dist/layout/neato/init.d.ts +6 -22
- package/dist/layout/neato/init.d.ts.map +1 -1
- package/dist/layout/neato/kk.d.ts.map +1 -1
- package/dist/layout/neato/kkutils.d.ts +20 -0
- package/dist/layout/neato/kkutils.d.ts.map +1 -0
- package/dist/layout/neato/make-graph-data.d.ts +43 -0
- package/dist/layout/neato/make-graph-data.d.ts.map +1 -0
- package/dist/layout/neato/matrix-ops.d.ts +46 -0
- package/dist/layout/neato/matrix-ops.d.ts.map +1 -1
- package/dist/layout/neato/multispline-router.d.ts.map +1 -1
- package/dist/layout/neato/multispline.d.ts.map +1 -1
- package/dist/layout/neato/opt-arrangement.d.ts +20 -0
- package/dist/layout/neato/opt-arrangement.d.ts.map +1 -0
- package/dist/layout/neato/poly.d.ts.map +1 -1
- package/dist/layout/neato/quad-prog-solve.d.ts +44 -0
- package/dist/layout/neato/quad-prog-solve.d.ts.map +1 -0
- package/dist/layout/neato/sgd.d.ts.map +1 -1
- package/dist/layout/neato/smart-ini-x.d.ts +9 -0
- package/dist/layout/neato/smart-ini-x.d.ts.map +1 -0
- package/dist/layout/neato/splines.d.ts +1 -1
- package/dist/layout/neato/splines.d.ts.map +1 -1
- package/dist/layout/neato/start.d.ts +4 -1
- package/dist/layout/neato/start.d.ts.map +1 -1
- package/dist/layout/neato/stress.d.ts +8 -0
- package/dist/layout/neato/stress.d.ts.map +1 -1
- package/dist/model/edge.d.ts +1 -1
- package/dist/model/edge.d.ts.map +1 -1
- package/dist/model/lazy-attrs.d.ts +10 -0
- package/dist/model/lazy-attrs.d.ts.map +1 -0
- package/dist/model/node.d.ts +1 -1
- package/dist/model/node.d.ts.map +1 -1
- package/dist/ortho/index.d.ts.map +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/render/color-resolve.d.ts +49 -1
- package/dist/render/color-resolve.d.ts.map +1 -1
- package/dist/render/dot/edge-draw.d.ts +1 -1
- package/dist/render/dot/edge-draw.d.ts.map +1 -1
- package/dist/render/public.d.ts.map +1 -1
- package/dist/render/svg-edge-split.d.ts +2 -0
- package/dist/render/svg-edge-split.d.ts.map +1 -1
- package/dist/render/svg-multicolor.d.ts +2 -2
- package/dist/render/svg-multicolor.d.ts.map +1 -1
- package/dist/render/xdot-public.d.ts.map +1 -1
- package/dist/render.js +2799 -927
- package/dist/render.js.map +4 -4
- package/package.json +1 -1
- package/src/async/render-async.ts +6 -0
- package/src/common/agerr.ts +96 -0
- package/src/common/arrows-shapes-poly.ts +19 -5
- package/src/common/color.ts +38 -10
- package/src/common/crand.ts +8 -2
- package/src/common/emit-once.ts +27 -0
- package/src/common/graph-init.ts +2 -1
- package/src/common/htmltable-attr-warn.ts +3 -4
- package/src/common/htmltable-emit-fill.ts +104 -11
- package/src/common/htmltable-emit-rules.ts +2 -0
- package/src/common/htmltable-emit.ts +4 -3
- package/src/common/htmltable-lex-expat.ts +96 -23
- package/src/common/htmltable-pos-runs.ts +11 -6
- package/src/common/htmltable.ts +28 -117
- package/src/common/libm-trig.ts +43 -0
- package/src/common/multicolor.ts +88 -24
- package/src/common/poly-gencode.ts +30 -10
- package/src/common/poly-init.ts +20 -1
- package/src/common/postproc.ts +4 -1
- package/src/common/random.ts +11 -1
- package/src/common/render-state.ts +36 -0
- package/src/common/splines-clip.ts +15 -12
- package/src/common/splines-geom.ts +8 -4
- package/src/common/splines-routespl.ts +2 -1
- package/src/common/textmeasure-lookup.ts +9 -2
- package/src/common/textmeasure.ts +45 -2
- package/src/gvc/anchor.ts +1 -12
- package/src/gvc/context.ts +8 -0
- package/src/gvc/device-cluster.ts +93 -10
- package/src/gvc/device-labels.ts +27 -0
- package/src/gvc/device.ts +34 -8
- package/src/gvc/first-layer.ts +26 -0
- package/src/gvc/gvrender-set-style.ts +114 -0
- package/src/gvc/usershape.ts +26 -0
- package/src/index.ts +3 -0
- package/src/layout/dot/cluster.ts +2 -1
- package/src/layout/dot/compound.ts +3 -4
- package/src/layout/dot/conc.ts +6 -5
- package/src/layout/dot/decomp.ts +3 -0
- package/src/layout/dot/edge-route-clip.ts +46 -28
- package/src/layout/dot/edge-route-routing.ts +11 -3
- package/src/layout/dot/fastgr.ts +2 -2
- package/src/layout/dot/mincross-build.ts +2 -0
- package/src/layout/dot/mincross-cross.ts +2 -0
- package/src/layout/dot/rank.ts +2 -0
- package/src/layout/dot/splines.ts +2 -1
- package/src/layout/fdp/index.ts +2 -1
- package/src/layout/fdp/tlayout-parms.ts +9 -2
- package/src/layout/fdp/xlayout.ts +10 -2
- package/src/layout/neato/__fixtures__/dijkstra-f.ts +17 -0
- package/src/layout/neato/__fixtures__/hier/c1554.gv +33 -0
- package/src/layout/neato/__fixtures__/hier/c1554.plain +26 -0
- package/src/layout/neato/__fixtures__/hier/c1554.xdot +161 -0
- package/src/layout/neato/__fixtures__/hier/cases/cycle.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/cycle.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/cycle.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/dirnone.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/dirnone.plain +11 -0
- package/src/layout/neato/__fixtures__/hier/cases/dirnone.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/epsilon.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/epsilon.plain +13 -0
- package/src/layout/neato/__fixtures__/hier/cases/epsilon.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/levelsgap.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/levelsgap.plain +8 -0
- package/src/layout/neato/__fixtures__/hier/cases/levelsgap.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/mds.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/mds.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/mds.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/multiedge.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/multiedge.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/multiedge.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.plain +8 -0
- package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/startrandom.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/startrandom.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/startrandom.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/startregular.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/startregular.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/startregular.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/tdist.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/tdist.plain +13 -0
- package/src/layout/neato/__fixtures__/hier/cases/tdist.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/undirected.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/undirected.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/undirected.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/hier-probe.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/hier-probe.plain +16 -0
- package/src/layout/neato/__fixtures__/hier/hier-probe.xdot +62 -0
- package/src/layout/neato/__fixtures__/hier-imds.ts +151 -0
- package/src/layout/neato/__fixtures__/hier-majorization.ts +145 -0
- package/src/layout/neato/cdt-surface.ts +12 -22
- package/src/layout/neato/compute-hierarchy.ts +90 -0
- package/src/layout/neato/conjgrad-mkernel.ts +141 -0
- package/src/layout/neato/conjgrad.ts +208 -0
- package/src/layout/neato/constrained-majorization.ts +479 -0
- package/src/layout/neato/dijkstra.ts +218 -92
- package/src/layout/neato/edge-len.ts +2 -1
- package/src/layout/neato/fdp-adjust.ts +3 -2
- package/src/layout/neato/gts-triangle.ts +42 -0
- package/src/layout/neato/init.ts +68 -68
- package/src/layout/neato/kk.ts +2 -1
- package/src/layout/neato/kkutils.ts +96 -0
- package/src/layout/neato/make-graph-data.ts +166 -0
- package/src/layout/neato/matrix-ops.ts +138 -0
- package/src/layout/neato/multispline-router.ts +3 -3
- package/src/layout/neato/multispline.ts +3 -2
- package/src/layout/neato/opt-arrangement.ts +86 -0
- package/src/layout/neato/poly.ts +3 -2
- package/src/layout/neato/quad-prog-solve.ts +489 -0
- package/src/layout/neato/sgd.ts +5 -2
- package/src/layout/neato/smart-ini-x.ts +503 -0
- package/src/layout/neato/splines.ts +4 -4
- package/src/layout/neato/start.ts +19 -14
- package/src/layout/neato/stress.ts +28 -0
- package/src/model/edge.ts +3 -2
- package/src/model/lazy-attrs.ts +36 -0
- package/src/model/node.ts +3 -2
- package/src/ortho/index.ts +2 -1
- package/src/parser/dot.js +4 -1
- package/src/parser/dot.pegjs +5 -1
- package/src/parser/index.ts +4 -3
- package/src/render/color-resolve.ts +193 -4
- package/src/render/dot/edge-draw.ts +6 -3
- package/src/render/dot.ts +1 -1
- package/src/render/public.ts +2 -0
- package/src/render/svg-edge-split.ts +6 -4
- package/src/render/svg-multicolor.ts +4 -3
- package/src/render/svg-parallel-edge.ts +2 -2
- package/src/render/xdot-public.ts +2 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EPL-2.0
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared empty attribute map for dot virtual nodes/edges (AD-12).
|
|
5
|
+
*
|
|
6
|
+
* C virtual nodes/edges carry no attribute record; allocating an empty `Map`
|
|
7
|
+
* per object cost ~372 B per virtual pair. Virtual objects start with this
|
|
8
|
+
* single shared map instead; reads see an empty map, and the first write goes
|
|
9
|
+
* through {@link ownAttrs}, which materialises a private `Map`. A direct
|
|
10
|
+
* mutation of the shared map throws rather than leaking into every virtual.
|
|
11
|
+
* @see lib/dotgen/fastgr.c:virtual_node
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
class SharedEmptyAttrs extends Map<string, string> {
|
|
15
|
+
override set(key: string, _value: string): never {
|
|
16
|
+
throw new Error(`attrs.set("${key}") on a shared empty map; use ownAttrs()`);
|
|
17
|
+
}
|
|
18
|
+
override delete(key: string): never {
|
|
19
|
+
throw new Error(`attrs.delete("${key}") on a shared empty map; use ownAttrs()`);
|
|
20
|
+
}
|
|
21
|
+
override clear(): never {
|
|
22
|
+
throw new Error('attrs.clear() on a shared empty map; use ownAttrs()');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The one shared empty attribute map (read-only by construction). */
|
|
27
|
+
export const EMPTY_ATTRS: Map<string, string> = new SharedEmptyAttrs();
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Return the object's private attribute map, materialising it on first write
|
|
31
|
+
* when the object still holds {@link EMPTY_ATTRS}.
|
|
32
|
+
*/
|
|
33
|
+
export function ownAttrs(o: { attrs: Map<string, string> }): Map<string, string> {
|
|
34
|
+
if (o.attrs === EMPTY_ATTRS) o.attrs = new Map();
|
|
35
|
+
return o.attrs;
|
|
36
|
+
}
|
package/src/model/node.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Edge } from './edge.js';
|
|
10
10
|
import type { Graph } from './graph.js';
|
|
11
|
+
import { EMPTY_ATTRS } from './lazy-attrs.js';
|
|
11
12
|
import { type NodeInfo, makeNodeInfo } from './nodeInfo.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -64,10 +65,10 @@ export class Node {
|
|
|
64
65
|
nodeDefaultsSnapshot?: Map<string, string>;
|
|
65
66
|
|
|
66
67
|
/** @see lib/cgraph/node.c:agnode */
|
|
67
|
-
constructor(id: number, name: string, root: Graph) {
|
|
68
|
+
constructor(id: number, name: string, root: Graph, lazyAttrs = false) {
|
|
68
69
|
this.id = id;
|
|
69
70
|
this.name = name;
|
|
70
|
-
this.attrs = new Map();
|
|
71
|
+
this.attrs = lazyAttrs ? EMPTY_ATTRS : new Map();
|
|
71
72
|
this.info = makeNodeInfo();
|
|
72
73
|
this.root = root;
|
|
73
74
|
}
|
package/src/ortho/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "./sgraph.js";
|
|
21
21
|
import { convertSPtoRoute, assignSegs, assignTracks, vtrack, htrack } from "./ortho-route.js";
|
|
22
22
|
import { gvQsort } from "../util/bsd-qsort.js";
|
|
23
|
+
import { agwarningf } from '../common/agerr.js';
|
|
23
24
|
|
|
24
25
|
export type { OrthoGraph, OrthoEdge, OrthoNode, OrthoPoint, ClipAndInstallFn };
|
|
25
26
|
export { SEED } from "./partition.js";
|
|
@@ -144,7 +145,7 @@ export function orthoEdges(
|
|
|
144
145
|
clipAndInstall?: ClipAndInstallFn,
|
|
145
146
|
): number {
|
|
146
147
|
if (useLbls) {
|
|
147
|
-
|
|
148
|
+
agwarningf(
|
|
148
149
|
"Orthogonal edges do not currently handle edge labels. Try using xlabels.\n",
|
|
149
150
|
);
|
|
150
151
|
useLbls = false; // eslint-disable-line no-param-reassign
|
package/src/parser/dot.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// https://peggyjs.org/
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
import { agwarningf } from "../common/agerr.js";
|
|
8
|
+
|
|
6
9
|
class peg$SyntaxError extends SyntaxError {
|
|
7
10
|
constructor(message, expected, found, location) {
|
|
8
11
|
super(message);
|
|
@@ -286,7 +289,7 @@ function peg$parse(input, options) {
|
|
|
286
289
|
function peg$f13(t, m, attrs) {
|
|
287
290
|
// grammar.y:attrstmt calls nomacros() when a macro name is present;
|
|
288
291
|
// the attributes are still applied unchanged.
|
|
289
|
-
if (m)
|
|
292
|
+
if (m) agwarningf("attribute macros not implemented");
|
|
290
293
|
return { type: "attr", target: t, attrs: attrs };
|
|
291
294
|
}
|
|
292
295
|
function peg$f14(a) { return { type: "assign", key: a.key, value: a.value }; }
|
package/src/parser/dot.pegjs
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
// Architecture decision AD-11: this file is the canonical faithfulness
|
|
9
9
|
// artifact; every production cites its Bison rule or Flex token.
|
|
10
10
|
|
|
11
|
+
{{
|
|
12
|
+
import { agwarningf } from "../common/agerr.js";
|
|
13
|
+
}}
|
|
14
|
+
|
|
11
15
|
// ── Top-level rule ───────────────────────────────────────────────────────────
|
|
12
16
|
// grammar.y: graph : hdr body | error | /* empty */
|
|
13
17
|
// `end` is the offset just past the graph's closing brace: the last input the
|
|
@@ -71,7 +75,7 @@ AttrStmt
|
|
|
71
75
|
{
|
|
72
76
|
// grammar.y:attrstmt calls nomacros() when a macro name is present;
|
|
73
77
|
// the attributes are still applied unchanged.
|
|
74
|
-
if (m)
|
|
78
|
+
if (m) agwarningf("attribute macros not implemented");
|
|
75
79
|
return { type: "attr", target: t, attrs: attrs };
|
|
76
80
|
}
|
|
77
81
|
/ a:AttrAssignment
|
package/src/parser/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { syntaxErrorMessage } from './scan-token.js';
|
|
|
18
18
|
import type { ParsedGraph } from './ast.js';
|
|
19
19
|
import type { GvErrorCode, GvExpectation } from '../errors.js';
|
|
20
20
|
import { DotEngineError, friendlyMessageFor, invalidArgType } from '../errors.js';
|
|
21
|
+
import { agerrFinished } from '../common/agerr.js';
|
|
21
22
|
|
|
22
23
|
// ── ParseError ────────────────────────────────────────────────────────────────
|
|
23
24
|
|
|
@@ -233,7 +234,7 @@ export function isPeggyError(err: unknown): err is {
|
|
|
233
234
|
function warnNumberAmbiguities(src: string, upTo: number): void {
|
|
234
235
|
for (const a of scanNumberAmbiguities(src, Stripper.strip(src))) {
|
|
235
236
|
if (a.offset > upTo) break;
|
|
236
|
-
|
|
237
|
+
agerrFinished(numberAmbiguityMessage(a));
|
|
237
238
|
}
|
|
238
239
|
}
|
|
239
240
|
|
|
@@ -250,7 +251,7 @@ export function parse(src: string): Graph {
|
|
|
250
251
|
if (isPeggyError(err)) {
|
|
251
252
|
const start = err.location.start;
|
|
252
253
|
warnNumberAmbiguities(src, start.offset);
|
|
253
|
-
|
|
254
|
+
agerrFinished(syntaxErrorMessage(src, start.offset));
|
|
254
255
|
const code: GvErrorCode =
|
|
255
256
|
err.found === null ? 'SYNTAX_UNEXPECTED_EOF' : 'SYNTAX_ERROR';
|
|
256
257
|
throw new ParseError(
|
|
@@ -282,7 +283,7 @@ export function parse(src: string): Graph {
|
|
|
282
283
|
const offset = err instanceof ParseError ? err.location.offset : undefined;
|
|
283
284
|
if (offset !== undefined) {
|
|
284
285
|
warnNumberAmbiguities(src, offset);
|
|
285
|
-
|
|
286
|
+
agerrFinished(syntaxErrorMessage(src, offset));
|
|
286
287
|
}
|
|
287
288
|
throw err;
|
|
288
289
|
}
|
|
@@ -18,10 +18,17 @@
|
|
|
18
18
|
|
|
19
19
|
import {
|
|
20
20
|
colorxlate,
|
|
21
|
+
ColorxlateResult,
|
|
21
22
|
getColorScheme,
|
|
22
23
|
setColorScheme,
|
|
23
24
|
type GVColor,
|
|
24
25
|
} from '../common/color.js';
|
|
26
|
+
import type { Edge } from '../model/edge.js';
|
|
27
|
+
import { registerRenderState } from '../common/render-state.js';
|
|
28
|
+
import { agerrorf, agwarningf } from '../common/agerr.js';
|
|
29
|
+
import { parseSegsSilent } from '../common/multicolor.js';
|
|
30
|
+
import { findStopColor, styleTokens } from '../common/style-resolve.js';
|
|
31
|
+
import { emitOnce } from '../common/emit-once.js';
|
|
25
32
|
|
|
26
33
|
/**
|
|
27
34
|
* The SVG renderer's known color names, ported verbatim from
|
|
@@ -78,19 +85,70 @@ const SVG_KNOWN_COLORS: readonly string[] = [
|
|
|
78
85
|
/** Lower-cased lookup set for the SVG known colors (case-insensitive, as C). */
|
|
79
86
|
export const KNOWN_COLORS: ReadonlySet<string> = new Set(SVG_KNOWN_COLORS);
|
|
80
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Whether the active renderer has the SVG known-colors list (svg). Only then
|
|
90
|
+
* does a known name skip colorxlate; every other renderer runs colorxlate on
|
|
91
|
+
* every name, which under a colorscheme can reject a name the list accepts.
|
|
92
|
+
* Per render (AD-4); a render that sets nothing is svg.
|
|
93
|
+
* @see lib/gvc/gvrender.c:195-199 gvrender_resolve_color (knowncolors)
|
|
94
|
+
*/
|
|
95
|
+
const rendererColors = { hasKnownList: true };
|
|
96
|
+
registerRenderState(() => {
|
|
97
|
+
rendererColors.hasKnownList = true;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/** Select the active renderer's known-colors behaviour; svg is the only list. */
|
|
101
|
+
export function setRendererKnownColors(hasList: boolean): void {
|
|
102
|
+
rendererColors.hasKnownList = hasList;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The first color of a `c1:c2` list: gvrender_set_pencolor cuts the name at the
|
|
107
|
+
* first ':' before resolving it.
|
|
108
|
+
* @see lib/gvc/gvrender.c:gvrender_set_pencolor
|
|
109
|
+
*/
|
|
110
|
+
export function firstColor(name: string): string {
|
|
111
|
+
const i = name.indexOf(':');
|
|
112
|
+
return i < 0 ? name : name.slice(0, i);
|
|
113
|
+
}
|
|
114
|
+
|
|
81
115
|
/**
|
|
82
116
|
* Resolve a raw color string to a canonical {@link GVColor} for rendering.
|
|
83
117
|
*
|
|
118
|
+
* `report` false resolves without the unknown-color warning, for a caller that
|
|
119
|
+
* resolves earlier than C does (the warning belongs to C's own call order).
|
|
120
|
+
*
|
|
84
121
|
* @see lib/gvc/gvrender.c:188-213 gvrender_resolve_color
|
|
85
122
|
*/
|
|
86
|
-
export function resolveRenderColor(raw: string): GVColor {
|
|
123
|
+
export function resolveRenderColor(raw: string, report = true): GVColor {
|
|
87
124
|
if (raw === '' || raw === 'none') return { type: 'none' };
|
|
88
125
|
// C keeps a known name verbatim (case preserved); only the compare is
|
|
89
126
|
// case-insensitive (bsearch over a lowercase table).
|
|
90
|
-
|
|
127
|
+
const known = KNOWN_COLORS.has(raw.toLowerCase());
|
|
128
|
+
if (known && (rendererColors.hasKnownList || !report)) return { type: 'string', s: raw };
|
|
91
129
|
const color: GVColor = { type: 'rgba', r: 0, g: 0, b: 0, a: 0 };
|
|
92
|
-
colorxlate(raw, color, 'rgba');
|
|
93
|
-
|
|
130
|
+
const rc = colorxlate(raw, color, 'rgba');
|
|
131
|
+
if (report) reportColorxlate(raw, rc);
|
|
132
|
+
return known ? { type: 'string', s: raw } : color;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The non-OK branch of gvrender_resolve_color: an unknown name warns once per
|
|
137
|
+
* render (emit_once "color <name>"), any other failure is an error.
|
|
138
|
+
*
|
|
139
|
+
* The result is renderer independent: every renderer's known-colors list is
|
|
140
|
+
* either absent (dot, xdot, json, cmapx, ...) or the SVG list, whose names all
|
|
141
|
+
* colorxlate to COLOR_OK, so only the xlate result decides whether C warns.
|
|
142
|
+
*
|
|
143
|
+
* @see lib/gvc/gvrender.c:201-209 gvrender_resolve_color
|
|
144
|
+
*/
|
|
145
|
+
function reportColorxlate(name: string, rc: ColorxlateResult): void {
|
|
146
|
+
if (rc === ColorxlateResult.ColorOk) return;
|
|
147
|
+
if (rc === ColorxlateResult.ColorUnknown) {
|
|
148
|
+
if (emitOnce(`color ${name}`)) agwarningf(`${name} is not a known color.`);
|
|
149
|
+
} else {
|
|
150
|
+
agerrorf('error in colorxlate()');
|
|
151
|
+
}
|
|
94
152
|
}
|
|
95
153
|
|
|
96
154
|
/**
|
|
@@ -169,3 +227,134 @@ export function textFillAttrs(fontColor: string | null): string {
|
|
|
169
227
|
if (byte < 255) out += ' fill-opacity="' + (byte / 255).toFixed(6) + '"';
|
|
170
228
|
return out;
|
|
171
229
|
}
|
|
230
|
+
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
// Unknown-color reporting in C's call order
|
|
233
|
+
//
|
|
234
|
+
// Which names C hands to gvrender_resolve_color, and in what order, is fixed by
|
|
235
|
+
// the emit code (emit_edge_graphics, emit_background, emit_label, ...), not by
|
|
236
|
+
// the renderer. The port's renderers resolve in their own order and not at all
|
|
237
|
+
// for the non-drawing ones (plain, imap, cmapx), so each pass below lists the
|
|
238
|
+
// names in C's order and resolves them once, before any renderer code runs;
|
|
239
|
+
// emit_once then makes every later resolve of the same name silent.
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
/** @see lib/common/const.h DEFAULT_COLOR */
|
|
243
|
+
const DEFAULT_COLOR = 'black';
|
|
244
|
+
/** @see lib/common/emit.c:452 AEQ0 (EPS) */
|
|
245
|
+
const SEG_EPS = 1e-5;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Resolve each name as gvrender_set_pencolor/_fillcolor/_gradient_vals would
|
|
249
|
+
* (cut at the first ':'), reporting unknown colors.
|
|
250
|
+
*/
|
|
251
|
+
export function reportColorNames(names: readonly string[]): void {
|
|
252
|
+
for (const name of names) resolveRenderColor(firstColor(name));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** The per-bezier arrow flags emit_edge_graphics consults. */
|
|
256
|
+
export interface EdgeArrowFlags {
|
|
257
|
+
sflag: boolean;
|
|
258
|
+
eflag: boolean;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** The inputs of emit_edge_graphics' colour decisions. */
|
|
262
|
+
export interface EdgeColorSpec {
|
|
263
|
+
/** late_string(e, E_color, ""). */
|
|
264
|
+
color: string;
|
|
265
|
+
/** E_fillcolor when set and non-empty, else "". */
|
|
266
|
+
fillcolor: string;
|
|
267
|
+
tapered: boolean;
|
|
268
|
+
arrows: readonly EdgeArrowFlags[];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Count occurrences of one character. */
|
|
272
|
+
function countChar(s: string, ch: string): number {
|
|
273
|
+
return s.split(ch).length - 1;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* The colours C's multicolor() sets, or null when the colour spec is rejected
|
|
278
|
+
* (parseSegs rv 1 or 2) and emit_edge_graphics falls back to DEFAULT_COLOR.
|
|
279
|
+
* @see lib/common/emit.c:1975 multicolor
|
|
280
|
+
*/
|
|
281
|
+
function multicolorNames(
|
|
282
|
+
color: string,
|
|
283
|
+
arrows: readonly EdgeArrowFlags[],
|
|
284
|
+
): string[] | null {
|
|
285
|
+
const { segs, error } = parseSegsSilent(color);
|
|
286
|
+
if (error === 1 || error === 2) return null;
|
|
287
|
+
const out: string[] = [];
|
|
288
|
+
const front = segs[0]?.color ?? null;
|
|
289
|
+
for (const bz of arrows) {
|
|
290
|
+
let endcolor: string | null = null;
|
|
291
|
+
for (const seg of segs) {
|
|
292
|
+
if (seg.color === null) break;
|
|
293
|
+
if (Math.abs(seg.t) < SEG_EPS) continue;
|
|
294
|
+
out.push(seg.color);
|
|
295
|
+
endcolor = seg.color;
|
|
296
|
+
}
|
|
297
|
+
if (bz.sflag && front !== null) out.push(front);
|
|
298
|
+
if (bz.eflag && endcolor !== null) out.push(endcolor);
|
|
299
|
+
}
|
|
300
|
+
return out;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** The tapered branch: transparent pen, colour as fill, then pen and fill. */
|
|
304
|
+
function taperedNames(color: string, fillcolor: string, hasFill: boolean): string[] {
|
|
305
|
+
const pen = color === '' ? DEFAULT_COLOR : color;
|
|
306
|
+
return hasFill ? [pen, fillcolor === '' ? DEFAULT_COLOR : fillcolor] : [pen];
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* The names emit_edge_graphics resolves for an edge with a spline, in order.
|
|
311
|
+
* @see lib/common/emit.c:2350 emit_edge_graphics
|
|
312
|
+
*/
|
|
313
|
+
export function edgeGraphicsColors(spec: EdgeColorSpec): string[] {
|
|
314
|
+
const numc = countChar(spec.color, ':');
|
|
315
|
+
let color = spec.color;
|
|
316
|
+
if (countChar(color, ';') > 0 && numc > 0) {
|
|
317
|
+
const multi = multicolorNames(color, spec.arrows);
|
|
318
|
+
if (multi !== null) return multi;
|
|
319
|
+
color = DEFAULT_COLOR;
|
|
320
|
+
}
|
|
321
|
+
const hasFill = spec.fillcolor !== '';
|
|
322
|
+
const early = hasFill ? [spec.fillcolor] : [];
|
|
323
|
+
if (spec.tapered) return [...early, ...taperedNames(color, spec.fillcolor, hasFill)];
|
|
324
|
+
if (numc > 0) return [...early, ...color.split(':').filter((c) => c !== '')];
|
|
325
|
+
const fill = hasFill ? spec.fillcolor : color;
|
|
326
|
+
if (color !== '') return [...early, color, fill];
|
|
327
|
+
return [...early, DEFAULT_COLOR, fill !== '' ? fill : DEFAULT_COLOR];
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Report the unknown colours of an edge's graphics in C's order.
|
|
332
|
+
* @see lib/common/emit.c:2350 emit_edge_graphics
|
|
333
|
+
*/
|
|
334
|
+
export function reportEdgeColors(e: Edge): void {
|
|
335
|
+
const spl = e.info.spl;
|
|
336
|
+
if (!spl) return;
|
|
337
|
+
const color = e.attrs.get('color') ?? '';
|
|
338
|
+
reportColorNames(edgeGraphicsColors({
|
|
339
|
+
color,
|
|
340
|
+
fillcolor: e.attrs.get('fillcolor') ?? '',
|
|
341
|
+
tapered: styleTokens(e.attrs.get('style')).includes('tapered'),
|
|
342
|
+
arrows: spl.list.map((bz) => ({ sflag: bz.sflag !== 0, eflag: bz.eflag !== 0 })),
|
|
343
|
+
}));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* The names emit_background resolves: the fill (a gradient's first colour, the
|
|
348
|
+
* transparent pen, then the stop). Only a truecolor device (svg) keeps a
|
|
349
|
+
* transparent background unpainted; elsewhere it becomes white.
|
|
350
|
+
* @see lib/common/emit.c:1476 emit_background
|
|
351
|
+
*/
|
|
352
|
+
export function backgroundColors(bgcolor: string | undefined, truecolor: boolean): string[] {
|
|
353
|
+
let str = bgcolor !== undefined && bgcolor !== '' ? bgcolor : 'white';
|
|
354
|
+
if (str === 'transparent') {
|
|
355
|
+
if (truecolor) return [];
|
|
356
|
+
str = 'white';
|
|
357
|
+
}
|
|
358
|
+
const stop = findStopColor(str);
|
|
359
|
+
return stop === null ? [str, 'transparent'] : [stop.fillColor, 'transparent', stop.stopColor];
|
|
360
|
+
}
|
|
@@ -23,11 +23,12 @@ import { resolveRenderColor } from '../color-resolve.js';
|
|
|
23
23
|
import { taper, taperfun } from '../../common/taper.js';
|
|
24
24
|
import { orthoRoundedRadius } from '../svg-helpers.js';
|
|
25
25
|
import { orthoRoundedPolylines } from '../svg-edge-ortho-radius.js';
|
|
26
|
-
import { parseSegs } from '../../common/multicolor.js';
|
|
26
|
+
import { edgeSegsContext, parseSegs, parseSegsSilent } from '../../common/multicolor.js';
|
|
27
27
|
import { splitSplineByColor } from '../svg-edge-split.js';
|
|
28
28
|
import { buildOffsetLists, advanceTmpList } from '../../common/edge-offset.js';
|
|
29
29
|
import { xdotFillColor, xdotNum, xdotPenColor, xdotPoint, xdotPoints, xdotStrOp, trimFixed3 } from './xdot-ops.js';
|
|
30
30
|
import { DotWriterBase } from './agwrite.js';
|
|
31
|
+
import { gvrenderSetStyle } from '../../gvc/gvrender-set-style.js';
|
|
31
32
|
|
|
32
33
|
/** Pen colour when a colour-list entry is empty. @see lib/common/emit.c:2485 */
|
|
33
34
|
const DEFAULT_COLOR = 'black';
|
|
@@ -81,6 +82,7 @@ export abstract class EdgeDrawBase extends DotWriterBase {
|
|
|
81
82
|
*/
|
|
82
83
|
attachmentPolyline(pts: Point[], pencolor: string, job: RenderJob): void {
|
|
83
84
|
const obj = job.obj;
|
|
85
|
+
gvrenderSetStyle(DEFAULT_LINE_STYLE);
|
|
84
86
|
if (obj !== null) {
|
|
85
87
|
obj.rawStyle = [...DEFAULT_LINE_STYLE];
|
|
86
88
|
obj.pen = PenType.Solid;
|
|
@@ -147,11 +149,12 @@ export abstract class EdgeDrawBase extends DotWriterBase {
|
|
|
147
149
|
*/
|
|
148
150
|
protected emitSplitSpline(
|
|
149
151
|
bzList: (Bezier | undefined)[],
|
|
152
|
+
e: Edge,
|
|
150
153
|
colorAttr: string,
|
|
151
154
|
edraw: string[],
|
|
152
155
|
job: RenderJob,
|
|
153
156
|
): { firstColor: string; endColor: string } {
|
|
154
|
-
const segs = parseSegs(colorAttr).segs;
|
|
157
|
+
const segs = parseSegs(colorAttr, edgeSegsContext(e)).segs;
|
|
155
158
|
const firstColor = segs[0]?.color ?? DEFAULT_COLOR;
|
|
156
159
|
let endColor = firstColor;
|
|
157
160
|
for (const bz of bzList) {
|
|
@@ -183,7 +186,7 @@ export abstract class EdgeDrawBase extends DotWriterBase {
|
|
|
183
186
|
? buildOffsetLists(bz.list, (2 + numc) / 2)
|
|
184
187
|
: { offlist: [] as Point[], tmplist: [] as Point[] },
|
|
185
188
|
);
|
|
186
|
-
const colors =
|
|
189
|
+
const colors = parseSegsSilent(colorAttr).segs.map((s) => s.color ?? DEFAULT_COLOR);
|
|
187
190
|
for (const color of colors) {
|
|
188
191
|
const pen = xdotPenColor(resolveRenderColor(color));
|
|
189
192
|
for (const sd of segData) {
|
package/src/render/dot.ts
CHANGED
|
@@ -215,7 +215,7 @@ export class XdotRenderer extends EdgeDrawBase implements RendererPlugin {
|
|
|
215
215
|
// color segment, split along the spline's arc length. Takes precedence
|
|
216
216
|
// over tapered / `:` parallel, matching C's `if (numsemi && numc)` order.
|
|
217
217
|
// @see lib/common/emit.c:2389 multicolor
|
|
218
|
-
const c = this.emitSplitSpline(spl.list as (Bezier | undefined)[], colorAttr, edraw, job);
|
|
218
|
+
const c = this.emitSplitSpline(spl.list as (Bezier | undefined)[], e, colorAttr, edraw, job);
|
|
219
219
|
tailArrowColor = c.firstColor;
|
|
220
220
|
headArrowColor = c.endColor;
|
|
221
221
|
} else if (edgeIsTapered(e)) {
|
package/src/render/public.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { Graph } from '../model/graph.js';
|
|
|
14
14
|
import { createDefaultContext } from '../gvc/default-context.js';
|
|
15
15
|
import { render as deviceRender } from '../gvc/device.js';
|
|
16
16
|
import { invalidArgType, rethrowAtBoundary } from '../errors.js';
|
|
17
|
+
import { resetRenderState } from '../common/render-state.js';
|
|
17
18
|
import type { EngineName } from '../gvc/context.js';
|
|
18
19
|
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
@@ -118,6 +119,7 @@ export function render(
|
|
|
118
119
|
opts?: RenderOptions,
|
|
119
120
|
): string {
|
|
120
121
|
checkRenderArgs(g, format, opts);
|
|
122
|
+
resetRenderState(); // AD-4: one render = one native process
|
|
121
123
|
const engine: EngineName = opts?.engine ?? 'dot';
|
|
122
124
|
const inlineImages = opts?.inlineImages ?? false;
|
|
123
125
|
const ctx = createDefaultContext();
|
|
@@ -20,7 +20,8 @@ import type { Edge } from '../model/edge.js';
|
|
|
20
20
|
import type { RenderJob } from '../gvc/job.js';
|
|
21
21
|
import type { Point, Bezier } from '../model/geom.js';
|
|
22
22
|
import { bezier } from '../common/bezier.js';
|
|
23
|
-
import {
|
|
23
|
+
import { dist2 } from '../common/spline-midpoint.js';
|
|
24
|
+
import { edgeSegsContext, parseSegs } from '../common/multicolor.js';
|
|
24
25
|
import { transformPoint } from '../gvc/device.js';
|
|
25
26
|
import { emitBezierPath, emitDash, emitPenWidth } from './svg-helpers.js';
|
|
26
27
|
import { resolveRenderColor, colorPaint } from './color-resolve.js';
|
|
@@ -31,12 +32,13 @@ const PENWIDTH_THRESHOLD = 0.005;
|
|
|
31
32
|
/** AEQ0 tolerance for fraction comparisons. */
|
|
32
33
|
const EPS = 1e-5;
|
|
33
34
|
|
|
35
|
+
/** DIST: sqrt of the fused DIST2 (libgvc splitBSpline: fmla + fsqrt). @see lib/common/geom.h:DIST */
|
|
34
36
|
function dist(a: Point, b: Point): number {
|
|
35
|
-
return Math.
|
|
37
|
+
return Math.sqrt(dist2(a, b));
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
/** Chord length of one cubic (control points at off..off+3). @see emit.c:1908 */
|
|
39
|
-
function approxLen(list: Point[], off: number): number {
|
|
41
|
+
export function approxLen(list: Point[], off: number): number {
|
|
40
42
|
return dist(list[off]!, list[off + 1]!) +
|
|
41
43
|
dist(list[off + 1]!, list[off + 2]!) +
|
|
42
44
|
dist(list[off + 2]!, list[off + 3]!);
|
|
@@ -158,7 +160,7 @@ export function emitSplitEdgePaths(
|
|
|
158
160
|
job: RenderJob,
|
|
159
161
|
colorList: string,
|
|
160
162
|
): { firstColor: string; endColor: string } {
|
|
161
|
-
const segs = parseSegs(colorList).segs;
|
|
163
|
+
const segs = parseSegs(colorList, edgeSegsContext(e)).segs;
|
|
162
164
|
const firstColor = segs[0]?.color ?? DEFAULT_COLOR;
|
|
163
165
|
const spl = e.info.spl;
|
|
164
166
|
let endColor = firstColor;
|
|
@@ -231,8 +231,9 @@ function drawWedge(seg: WedgeSeg, e: EllipseParams, ctx: RenderCtx): number {
|
|
|
231
231
|
*/
|
|
232
232
|
export function wedgedEllipse(
|
|
233
233
|
job: RenderJob, pf: Point[], clrs: string, renderer: RendererPlugin,
|
|
234
|
+
context?: () => string,
|
|
234
235
|
): number {
|
|
235
|
-
const { segs, error } = parseSegs(clrs);
|
|
236
|
+
const { segs, error } = parseSegs(clrs, context);
|
|
236
237
|
if (error === 1 || error === 2) return error;
|
|
237
238
|
const ctrX = (pf[0]!.x + pf[1]!.x) / 2;
|
|
238
239
|
const ctrY = (pf[0]!.y + pf[1]!.y) / 2;
|
|
@@ -286,9 +287,9 @@ function drawBand(p: Point[], seg: BandSeg, ctx: RenderCtx): void {
|
|
|
286
287
|
*/
|
|
287
288
|
export function stripedBox(
|
|
288
289
|
job: RenderJob, pts: Point[], clrs: string,
|
|
289
|
-
rotate: boolean, renderer: RendererPlugin,
|
|
290
|
+
rotate: boolean, renderer: RendererPlugin, context?: () => string,
|
|
290
291
|
): number {
|
|
291
|
-
const { segs, error } = parseSegs(clrs);
|
|
292
|
+
const { segs, error } = parseSegs(clrs, context);
|
|
292
293
|
if (error === 1 || error === 2) return error;
|
|
293
294
|
// @see lib/common/emit.c:605-615 rotate swap
|
|
294
295
|
const p: Point[] = rotate
|
|
@@ -27,7 +27,7 @@ import { buildOffsetLists, advanceTmpList } from '../common/edge-offset.js';
|
|
|
27
27
|
import { transformPoint } from '../gvc/device.js';
|
|
28
28
|
import { emitBezierPath, emitDash, emitPenWidth } from './svg-helpers.js';
|
|
29
29
|
import { resolveRenderColor, colorPaint, colorOpacity } from './color-resolve.js';
|
|
30
|
-
import {
|
|
30
|
+
import { parseSegsSilent } from '../common/multicolor.js';
|
|
31
31
|
|
|
32
32
|
const PENWIDTH_NORMAL = 1.0;
|
|
33
33
|
const PENWIDTH_THRESHOLD = 0.005;
|
|
@@ -114,7 +114,7 @@ export function emitParallelEdgePaths(
|
|
|
114
114
|
// parseSegs strips any ';weight', so the semicolon syntax (which C routes
|
|
115
115
|
// to split-along-length multicolor — a follow-up) at least yields valid
|
|
116
116
|
// parallel colors instead of an invalid "red;0.5" stroke.
|
|
117
|
-
const colors =
|
|
117
|
+
const colors = parseSegsSilent(colorList).segs.map((s) => s.color ?? DEFAULT_COLOR);
|
|
118
118
|
emitColorPasses(segData, colors, job);
|
|
119
119
|
return {
|
|
120
120
|
headColor: colors[0] ?? DEFAULT_COLOR,
|
|
@@ -35,6 +35,7 @@ import { createDefaultContext } from '../gvc/default-context.js';
|
|
|
35
35
|
import { parseXDot } from '../xdot/index.js';
|
|
36
36
|
import type { EngineName } from '../gvc/context.js';
|
|
37
37
|
import { invalidArgType, rethrowAtBoundary } from '../errors.js';
|
|
38
|
+
import { resetRenderState } from '../common/render-state.js';
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* `Xdot` — the parsed result of one xdot attribute stream: `ops` (the
|
|
@@ -160,6 +161,7 @@ function layoutAndRenderXdot(g: Graph, engine: EngineName): string {
|
|
|
160
161
|
*/
|
|
161
162
|
export function getDrawOps(g: Graph, opts?: DrawOpsOptions): XdotOp[] {
|
|
162
163
|
checkDrawOpsArgs(g, opts);
|
|
164
|
+
resetRenderState(); // AD-4: one render = one native process
|
|
163
165
|
const engine = opts?.engine ?? DEFAULT_DRAW_ENGINE;
|
|
164
166
|
return collectGraphOps(parse(layoutAndRenderXdot(g, engine)));
|
|
165
167
|
}
|