@kgdiff/layout 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +46 -2
- package/dist/components.d.ts +11 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +56 -0
- package/dist/components.js.map +1 -0
- package/dist/engine.d.ts +20 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +336 -0
- package/dist/engine.js.map +1 -0
- package/dist/extend.d.ts +7 -0
- package/dist/extend.d.ts.map +1 -0
- package/dist/extend.js +68 -0
- package/dist/extend.js.map +1 -0
- package/dist/forces/collide-rect.d.ts +50 -0
- package/dist/forces/collide-rect.d.ts.map +1 -0
- package/dist/forces/collide-rect.js +310 -0
- package/dist/forces/collide-rect.js.map +1 -0
- package/dist/forces/free-spot.d.ts +40 -0
- package/dist/forces/free-spot.d.ts.map +1 -0
- package/dist/forces/free-spot.js +189 -0
- package/dist/forces/free-spot.js.map +1 -0
- package/dist/forces/params.d.ts +38 -0
- package/dist/forces/params.d.ts.map +1 -0
- package/dist/forces/params.js +55 -0
- package/dist/forces/params.js.map +1 -0
- package/dist/forces/springs.d.ts +20 -0
- package/dist/forces/springs.d.ts.map +1 -0
- package/dist/forces/springs.js +34 -0
- package/dist/forces/springs.js.map +1 -0
- package/dist/geometry.d.ts +21 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +39 -0
- package/dist/geometry.js.map +1 -0
- package/dist/graph.d.ts +38 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +82 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +162 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +28 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +196 -0
- package/dist/init.js.map +1 -0
- package/dist/json.d.ts +4 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +112 -0
- package/dist/json.js.map +1 -0
- package/dist/layout.d.ts +7 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +70 -0
- package/dist/layout.js.map +1 -0
- package/dist/math.d.ts +29 -0
- package/dist/math.d.ts.map +1 -0
- package/dist/math.js +91 -0
- package/dist/math.js.map +1 -0
- package/dist/options.d.ts +43 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +76 -0
- package/dist/options.js.map +1 -0
- package/dist/pack.d.ts +43 -0
- package/dist/pack.d.ts.map +1 -0
- package/dist/pack.js +168 -0
- package/dist/pack.js.map +1 -0
- package/dist/prng.d.ts +20 -0
- package/dist/prng.d.ts.map +1 -0
- package/dist/prng.js +53 -0
- package/dist/prng.js.map +1 -0
- package/dist/result.d.ts +20 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +40 -0
- package/dist/result.js.map +1 -0
- package/dist/scope.d.ts +25 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +71 -0
- package/dist/scope.js.map +1 -0
- package/dist/simulate.d.ts +64 -0
- package/dist/simulate.d.ts.map +1 -0
- package/dist/simulate.js +247 -0
- package/dist/simulate.js.map +1 -0
- package/dist/text-metrics.d.ts +32 -0
- package/dist/text-metrics.d.ts.map +1 -0
- package/dist/text-metrics.js +153 -0
- package/dist/text-metrics.js.map +1 -0
- package/dist/union.d.ts +32 -0
- package/dist/union.d.ts.map +1 -0
- package/dist/union.js +106 -0
- package/dist/union.js.map +1 -0
- package/package.json +52 -3
- package/src/components.ts +56 -0
- package/src/engine.ts +444 -0
- package/src/extend.ts +75 -0
- package/src/forces/collide-rect.ts +385 -0
- package/src/forces/free-spot.ts +243 -0
- package/src/forces/params.ts +88 -0
- package/src/forces/springs.ts +50 -0
- package/src/geometry.ts +66 -0
- package/src/graph.ts +120 -0
- package/src/index.ts +193 -0
- package/src/init.ts +246 -0
- package/src/json.ts +131 -0
- package/src/layout.ts +87 -0
- package/src/math.ts +91 -0
- package/src/options.ts +153 -0
- package/src/pack.ts +228 -0
- package/src/prng.ts +59 -0
- package/src/result.ts +63 -0
- package/src/scope.ts +86 -0
- package/src/simulate.ts +328 -0
- package/src/text-metrics.ts +157 -0
- package/src/union.ts +127 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The force simulation. d3-force supplies the link and many-body (Barnes–Hut) forces; the tick
|
|
3
|
+
* loop is our own so that it is synchronous and timer-free (no d3-timer, safe in workers and
|
|
4
|
+
* Node), runs a fixed number of ticks (no time-based termination) and can change forces between
|
|
5
|
+
* phases:
|
|
6
|
+
*
|
|
7
|
+
* 1. structure (first ~35% of ticks): links + charge + node-only collision. The graph unfolds
|
|
8
|
+
* without label boxes jamming it.
|
|
9
|
+
* 2. orientation (union layouts): the component is rotated onto its principal axis (wide
|
|
10
|
+
* layouts suit screens and horizontal labels) and mirrored to a canonical handedness; if its
|
|
11
|
+
* label boxes could not fit in its current extent, it is scaled up once (`makeRoom`).
|
|
12
|
+
* 3. labels: label boxes are inflated from 50% to 100% over ~25% of the ticks, then held.
|
|
13
|
+
* Collision is not scaled by alpha: it keeps working while the other forces cool down.
|
|
14
|
+
* 4. a position-level pass removes any overlap that is left, and merge / split partners that
|
|
15
|
+
* ended up far apart are docked next to each other.
|
|
16
|
+
*/
|
|
17
|
+
import { type SimulationLinkDatum, type SimulationNodeDatum } from 'd3-force';
|
|
18
|
+
import { type CollisionBoxes } from './forces/collide-rect.js';
|
|
19
|
+
import { type Spring } from './forces/springs.js';
|
|
20
|
+
import type { Random } from './prng.js';
|
|
21
|
+
export interface SimNode extends SimulationNodeDatum {
|
|
22
|
+
index: number;
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
vx: number;
|
|
26
|
+
vy: number;
|
|
27
|
+
}
|
|
28
|
+
export interface SimLink extends SimulationLinkDatum<SimNode> {
|
|
29
|
+
source: SimNode;
|
|
30
|
+
target: SimNode;
|
|
31
|
+
distance: number;
|
|
32
|
+
strength: number;
|
|
33
|
+
}
|
|
34
|
+
export interface SimulationSpec {
|
|
35
|
+
/** Initial positions; fixed nodes carry `fx` / `fy`. Indices must be 0..n−1. */
|
|
36
|
+
readonly nodes: SimNode[];
|
|
37
|
+
readonly links: SimLink[];
|
|
38
|
+
readonly springs: readonly Spring[];
|
|
39
|
+
/** Many-body strength per node (negative = repulsion). */
|
|
40
|
+
readonly charge: Float64Array;
|
|
41
|
+
/** Node-only boxes (structure phase). */
|
|
42
|
+
readonly nodeBoxes: CollisionBoxes;
|
|
43
|
+
/** Full node + label boxes (label phase and final overlap removal). */
|
|
44
|
+
readonly labelBoxes: CollisionBoxes;
|
|
45
|
+
readonly ticks: number;
|
|
46
|
+
/** Starting alpha (1 for a fresh layout, lower to refine around fixed nodes). */
|
|
47
|
+
readonly alpha: number;
|
|
48
|
+
/** Pull towards the origin; 0 disables it (anchored layouts). */
|
|
49
|
+
readonly gravity: number;
|
|
50
|
+
/** Rotate / mirror into canonical orientation after the structure phase. */
|
|
51
|
+
readonly orient: boolean;
|
|
52
|
+
readonly springStrength: number;
|
|
53
|
+
readonly springLength: number;
|
|
54
|
+
/** Partners farther apart than this are docked next to each other at the end (0 = never). */
|
|
55
|
+
readonly dockDistance: number;
|
|
56
|
+
/** Many-body cut-off (docs/algorithms.md: 900; shorter when refining around fixed nodes). */
|
|
57
|
+
readonly chargeRange: number;
|
|
58
|
+
/** Gap kept between boxes. */
|
|
59
|
+
readonly padding: number;
|
|
60
|
+
readonly random: Random;
|
|
61
|
+
}
|
|
62
|
+
/** Run the simulation in place. Returns the number of overlap-removal passes used. */
|
|
63
|
+
export declare function simulate(spec: SimulationSpec): number;
|
|
64
|
+
//# sourceMappingURL=simulate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simulate.d.ts","sourceRoot":"","sources":["../src/simulate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACzB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,KAAK,cAAc,EAIpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAA8B,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,WAAW,OAAQ,SAAQ,mBAAmB;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,OAAQ,SAAQ,mBAAmB,CAAC,OAAO,CAAC;IAC3D,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,6FAA6F;IAC7F,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,6FAA6F;IAC7F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAcD,sFAAsF;AACtF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAuGrD"}
|
package/dist/simulate.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The force simulation. d3-force supplies the link and many-body (Barnes–Hut) forces; the tick
|
|
3
|
+
* loop is our own so that it is synchronous and timer-free (no d3-timer, safe in workers and
|
|
4
|
+
* Node), runs a fixed number of ticks (no time-based termination) and can change forces between
|
|
5
|
+
* phases:
|
|
6
|
+
*
|
|
7
|
+
* 1. structure (first ~35% of ticks): links + charge + node-only collision. The graph unfolds
|
|
8
|
+
* without label boxes jamming it.
|
|
9
|
+
* 2. orientation (union layouts): the component is rotated onto its principal axis (wide
|
|
10
|
+
* layouts suit screens and horizontal labels) and mirrored to a canonical handedness; if its
|
|
11
|
+
* label boxes could not fit in its current extent, it is scaled up once (`makeRoom`).
|
|
12
|
+
* 3. labels: label boxes are inflated from 50% to 100% over ~25% of the ticks, then held.
|
|
13
|
+
* Collision is not scaled by alpha: it keeps working while the other forces cool down.
|
|
14
|
+
* 4. a position-level pass removes any overlap that is left, and merge / split partners that
|
|
15
|
+
* ended up far apart are docked next to each other.
|
|
16
|
+
*/
|
|
17
|
+
import { forceLink, forceManyBody, } from 'd3-force';
|
|
18
|
+
import { collideVelocities, collisionScratch, removeOverlaps, } from './forces/collide-rect.js';
|
|
19
|
+
import { dockPartners } from './forces/free-spot.js';
|
|
20
|
+
import { applyGravity, applySprings } from './forces/springs.js';
|
|
21
|
+
import { coolingFactor } from './math.js';
|
|
22
|
+
const ALPHA_MIN = 0.001;
|
|
23
|
+
/** d3's default: velocities keep 60% per tick. */
|
|
24
|
+
const VELOCITY_RETAIN = 0.6;
|
|
25
|
+
const STRUCTURE_SHARE = 0.35;
|
|
26
|
+
const RAMP_SHARE = 0.25;
|
|
27
|
+
/** Label boxes start the label phase at this fraction of their size. */
|
|
28
|
+
const RAMP_FROM = 0.5;
|
|
29
|
+
const COLLIDE_STRENGTH = 0.7;
|
|
30
|
+
/** Label boxes may cover at most this share of the nodes' bounding box after the structure phase. */
|
|
31
|
+
const ROOM_DENSITY = 0.4;
|
|
32
|
+
const MAX_OVERLAP_PASSES = 150;
|
|
33
|
+
/** Run the simulation in place. Returns the number of overlap-removal passes used. */
|
|
34
|
+
export function simulate(spec) {
|
|
35
|
+
const { nodes, ticks } = spec;
|
|
36
|
+
const n = nodes.length;
|
|
37
|
+
if (n === 0)
|
|
38
|
+
return 0;
|
|
39
|
+
if (ticks > 0) {
|
|
40
|
+
const link = forceLink(spec.links)
|
|
41
|
+
.distance((l) => l.distance)
|
|
42
|
+
.strength((l) => l.strength);
|
|
43
|
+
link.initialize(nodes, spec.random);
|
|
44
|
+
const charge = forceManyBody()
|
|
45
|
+
.strength((d) => spec.charge[d.index] ?? 0)
|
|
46
|
+
.theta(0.9)
|
|
47
|
+
.distanceMax(spec.chargeRange);
|
|
48
|
+
charge.initialize(nodes, spec.random);
|
|
49
|
+
const decay = coolingFactor(ALPHA_MIN / spec.alpha, ticks);
|
|
50
|
+
const structureEnd = Math.round(ticks * STRUCTURE_SHARE);
|
|
51
|
+
const rampTicks = Math.max(1, Math.round(ticks * RAMP_SHARE));
|
|
52
|
+
const ramp = scratchBoxes(spec.nodeBoxes);
|
|
53
|
+
const scratch = collisionScratch(n);
|
|
54
|
+
let alpha = spec.alpha;
|
|
55
|
+
for (let tick = 0; tick < ticks; tick++) {
|
|
56
|
+
alpha *= decay;
|
|
57
|
+
link(alpha);
|
|
58
|
+
charge(alpha);
|
|
59
|
+
if (spec.springs.length > 0) {
|
|
60
|
+
applySprings(nodes, spec.springs, alpha, spec.springStrength, spec.springLength);
|
|
61
|
+
}
|
|
62
|
+
if (spec.gravity > 0)
|
|
63
|
+
applyGravity(nodes, alpha, spec.gravity);
|
|
64
|
+
let boxes = spec.nodeBoxes;
|
|
65
|
+
if (tick >= structureEnd) {
|
|
66
|
+
const t = Math.min(1, (tick - structureEnd + 1) / rampTicks);
|
|
67
|
+
boxes =
|
|
68
|
+
t >= 1
|
|
69
|
+
? spec.labelBoxes
|
|
70
|
+
: blendBoxes(spec.nodeBoxes, spec.labelBoxes, RAMP_FROM + (1 - RAMP_FROM) * t, ramp);
|
|
71
|
+
}
|
|
72
|
+
if (boxes !== undefined)
|
|
73
|
+
collideVelocities(nodes, boxes, spec.padding, COLLIDE_STRENGTH, scratch);
|
|
74
|
+
for (const node of nodes) {
|
|
75
|
+
if (node.fx == null) {
|
|
76
|
+
node.vx *= VELOCITY_RETAIN;
|
|
77
|
+
node.x += node.vx;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
node.x = node.fx;
|
|
81
|
+
node.vx = 0;
|
|
82
|
+
}
|
|
83
|
+
if (node.fy == null) {
|
|
84
|
+
node.vy *= VELOCITY_RETAIN;
|
|
85
|
+
node.y += node.vy;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
node.y = node.fy;
|
|
89
|
+
node.vy = 0;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (tick + 1 === structureEnd) {
|
|
93
|
+
if (spec.orient)
|
|
94
|
+
orient(nodes);
|
|
95
|
+
makeRoom(nodes, spec.labelBoxes, spec.padding, ROOM_DENSITY);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const cleared = removeOverlaps(nodes, spec.labelBoxes, spec.padding, MAX_OVERLAP_PASSES);
|
|
100
|
+
let passes = cleared.passes;
|
|
101
|
+
if (spec.springs.length > 0 && spec.dockDistance > 0) {
|
|
102
|
+
const pinned = dockPartners(nodes, spec.springs, spec.labelBoxes, spec.padding, spec.dockDistance);
|
|
103
|
+
if (pinned.length > 0) {
|
|
104
|
+
// Make room around docked pairs: they hold still, their new neighbours step aside. Only
|
|
105
|
+
// the docked nodes (and whatever was left over) need to be looked at.
|
|
106
|
+
const invMass = Float64Array.from(spec.labelBoxes.invMass);
|
|
107
|
+
const active = Uint8Array.from(cleared.unresolved);
|
|
108
|
+
for (const k of pinned) {
|
|
109
|
+
invMass[k] = 0;
|
|
110
|
+
active[k] = 1;
|
|
111
|
+
}
|
|
112
|
+
const boxes = { ...spec.labelBoxes, invMass };
|
|
113
|
+
const room = removeOverlaps(nodes, boxes, spec.padding, MAX_OVERLAP_PASSES, active);
|
|
114
|
+
// Whatever the pinned pass could not clear (a pinned pair in a tight spot) is cleared with
|
|
115
|
+
// everyone movable again.
|
|
116
|
+
const rest = Uint8Array.from(room.unresolved);
|
|
117
|
+
for (const k of pinned)
|
|
118
|
+
rest[k] = 1;
|
|
119
|
+
passes += room.passes;
|
|
120
|
+
passes += removeOverlaps(nodes, spec.labelBoxes, spec.padding, MAX_OVERLAP_PASSES, rest).passes;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return passes;
|
|
124
|
+
}
|
|
125
|
+
function scratchBoxes(like) {
|
|
126
|
+
const n = like.halfWidth.length;
|
|
127
|
+
return {
|
|
128
|
+
halfWidth: new Float64Array(n),
|
|
129
|
+
halfHeight: new Float64Array(n),
|
|
130
|
+
offsetY: new Float64Array(n),
|
|
131
|
+
invMass: like.invMass,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** Boxes with the label part scaled by `s` (node part kept), written into `out`. */
|
|
135
|
+
function blendBoxes(node, full, s, out) {
|
|
136
|
+
const n = node.halfWidth.length;
|
|
137
|
+
for (let i = 0; i < n; i++) {
|
|
138
|
+
const top = node.offsetY[i] - node.halfHeight[i];
|
|
139
|
+
const bottom = node.offsetY[i] + node.halfHeight[i];
|
|
140
|
+
const fullBottom = full.offsetY[i] + full.halfHeight[i];
|
|
141
|
+
const b = bottom + (fullBottom - bottom) * s;
|
|
142
|
+
out.halfWidth[i] = node.halfWidth[i] + (full.halfWidth[i] - node.halfWidth[i]) * s;
|
|
143
|
+
out.halfHeight[i] = (b - top) / 2;
|
|
144
|
+
out.offsetY[i] = (b + top) / 2;
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Rotate the (free) layout so its principal axis is horizontal, then mirror so the heavier tail
|
|
150
|
+
* points right / down. Only exact operations: the eigenvector of the 2×2 covariance matrix gives
|
|
151
|
+
* cos / sin directly.
|
|
152
|
+
*/
|
|
153
|
+
function orient(nodes) {
|
|
154
|
+
let cx = 0;
|
|
155
|
+
let cy = 0;
|
|
156
|
+
for (const d of nodes) {
|
|
157
|
+
cx += d.x;
|
|
158
|
+
cy += d.y;
|
|
159
|
+
}
|
|
160
|
+
cx /= nodes.length;
|
|
161
|
+
cy /= nodes.length;
|
|
162
|
+
let sxx = 0;
|
|
163
|
+
let syy = 0;
|
|
164
|
+
let sxy = 0;
|
|
165
|
+
for (const d of nodes) {
|
|
166
|
+
const dx = d.x - cx;
|
|
167
|
+
const dy = d.y - cy;
|
|
168
|
+
sxx += dx * dx;
|
|
169
|
+
syy += dy * dy;
|
|
170
|
+
sxy += dx * dy;
|
|
171
|
+
}
|
|
172
|
+
const half = (sxx - syy) / 2;
|
|
173
|
+
const lambda = (sxx + syy) / 2 + Math.sqrt(half * half + sxy * sxy);
|
|
174
|
+
let ux = sxy;
|
|
175
|
+
let uy = lambda - sxx;
|
|
176
|
+
if (Math.abs(ux) + Math.abs(uy) < 1e-12 * (sxx + syy + 1)) {
|
|
177
|
+
ux = lambda - syy;
|
|
178
|
+
uy = sxy;
|
|
179
|
+
}
|
|
180
|
+
const len = Math.sqrt(ux * ux + uy * uy);
|
|
181
|
+
const c = len > 0 ? ux / len : 1;
|
|
182
|
+
const s = len > 0 ? uy / len : 0;
|
|
183
|
+
let m3x = 0;
|
|
184
|
+
let m3y = 0;
|
|
185
|
+
for (const d of nodes) {
|
|
186
|
+
const dx = d.x - cx;
|
|
187
|
+
const dy = d.y - cy;
|
|
188
|
+
const rx = c * dx + s * dy;
|
|
189
|
+
const ry = -s * dx + c * dy;
|
|
190
|
+
d.x = rx;
|
|
191
|
+
d.y = ry;
|
|
192
|
+
const vx = c * d.vx + s * d.vy;
|
|
193
|
+
d.vy = -s * d.vx + c * d.vy;
|
|
194
|
+
d.vx = vx;
|
|
195
|
+
m3x += rx * rx * rx;
|
|
196
|
+
m3y += ry * ry * ry;
|
|
197
|
+
}
|
|
198
|
+
const fx = m3x < 0 ? -1 : 1;
|
|
199
|
+
const fy = m3y < 0 ? -1 : 1;
|
|
200
|
+
if (fx === 1 && fy === 1)
|
|
201
|
+
return;
|
|
202
|
+
for (const d of nodes) {
|
|
203
|
+
d.x *= fx;
|
|
204
|
+
d.vx *= fx;
|
|
205
|
+
d.y *= fy;
|
|
206
|
+
d.vy *= fy;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Scale the (free) layout up about its centroid when its label boxes could not possibly fit:
|
|
211
|
+
* when their total area exceeds `density` × the area of the nodes' bounding box. A dense graph
|
|
212
|
+
* pulls itself together tighter than its labels allow, and pushing boxes apart one pair at a time
|
|
213
|
+
* through such a jam takes many passes; a uniform scale keeps the picture and makes the room in
|
|
214
|
+
* one step. Fixed nodes, if any, rule this out.
|
|
215
|
+
*/
|
|
216
|
+
function makeRoom(nodes, boxes, padding, density) {
|
|
217
|
+
if (nodes.length < 3 || boxes.invMass.some((m) => m === 0))
|
|
218
|
+
return;
|
|
219
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
220
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
221
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
222
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
223
|
+
let area = 0;
|
|
224
|
+
let cx = 0;
|
|
225
|
+
let cy = 0;
|
|
226
|
+
for (const d of nodes) {
|
|
227
|
+
minX = Math.min(minX, d.x);
|
|
228
|
+
maxX = Math.max(maxX, d.x);
|
|
229
|
+
minY = Math.min(minY, d.y);
|
|
230
|
+
maxY = Math.max(maxY, d.y);
|
|
231
|
+
cx += d.x;
|
|
232
|
+
cy += d.y;
|
|
233
|
+
area += (2 * boxes.halfWidth[d.index] + padding) * (2 * boxes.halfHeight[d.index] + padding);
|
|
234
|
+
}
|
|
235
|
+
const span = Math.max(1, maxX - minX) * Math.max(1, maxY - minY);
|
|
236
|
+
const ratio = area / (density * span);
|
|
237
|
+
if (ratio <= 1)
|
|
238
|
+
return;
|
|
239
|
+
const scale = Math.sqrt(ratio);
|
|
240
|
+
cx /= nodes.length;
|
|
241
|
+
cy /= nodes.length;
|
|
242
|
+
for (const d of nodes) {
|
|
243
|
+
d.x = cx + (d.x - cx) * scale;
|
|
244
|
+
d.y = cy + (d.y - cy) * scale;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=simulate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simulate.js","sourceRoot":"","sources":["../src/simulate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM-free text metrics: label widths are estimated from per-character advances so the layout
|
|
3
|
+
* is identical in Node and in every browser (docs/algorithms.md §12 `estimateLabelWidth`).
|
|
4
|
+
*/
|
|
5
|
+
/** Advance of one code point, in em. */
|
|
6
|
+
export declare function charAdvance(char: string): number;
|
|
7
|
+
/** Sum of per-character advances × font size. See the public `estimateLabelWidth`. */
|
|
8
|
+
export declare function labelWidth(text: string, fontSize: number): number;
|
|
9
|
+
/** Gap between the node circle and the top of its label (world units, visual-language §Typography). */
|
|
10
|
+
export declare const LABEL_GAP = 5;
|
|
11
|
+
/** Height of one label line in em (12 px text + its 3 px halo). */
|
|
12
|
+
export declare const LINE_HEIGHT_EM = 1.25;
|
|
13
|
+
/** Renamed nodes show the old name 14 px (at 12 px text) below the new one, at 11/12 size. */
|
|
14
|
+
export declare const SECONDARY_OFFSET_EM: number;
|
|
15
|
+
export declare const SECONDARY_SIZE_RATIO: number;
|
|
16
|
+
/**
|
|
17
|
+
* Reserved label width is capped so a pathological label (a 300-character IRI) cannot blow up
|
|
18
|
+
* the layout; renderers truncate long labels anyway. 32 em ≈ 55 Latin characters.
|
|
19
|
+
*/
|
|
20
|
+
export declare const MAX_LABEL_EM = 32;
|
|
21
|
+
export interface LabelBox {
|
|
22
|
+
/** Full width of the label block (world units). */
|
|
23
|
+
readonly width: number;
|
|
24
|
+
/** Full height of the label block, all lines. */
|
|
25
|
+
readonly height: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The block of text drawn centered below a node: its label and, for renamed nodes, the struck
|
|
29
|
+
* old label on a second, slightly smaller line.
|
|
30
|
+
*/
|
|
31
|
+
export declare function labelBox(label: string, labelBefore: string | undefined, fontSize: number): LabelBox;
|
|
32
|
+
//# sourceMappingURL=text-metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-metrics.d.ts","sourceRoot":"","sources":["../src/text-metrics.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkFH,wCAAwC;AACxC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAcjE;AAID,uGAAuG;AACvG,eAAO,MAAM,SAAS,IAAI,CAAC;AAC3B,mEAAmE;AACnE,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC,8FAA8F;AAC9F,eAAO,MAAM,mBAAmB,QAAU,CAAC;AAC3C,eAAO,MAAM,oBAAoB,QAAU,CAAC;AAC5C;;;GAGG;AACH,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B,MAAM,WAAW,QAAQ;IACvB,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GACf,QAAQ,CAUV"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM-free text metrics: label widths are estimated from per-character advances so the layout
|
|
3
|
+
* is identical in Node and in every browser (docs/algorithms.md §12 `estimateLabelWidth`).
|
|
4
|
+
*/
|
|
5
|
+
/** Advance widths in em. */
|
|
6
|
+
const EM_WIDE = 1;
|
|
7
|
+
const EM_DIGIT = 0.6;
|
|
8
|
+
const EM_UPPER = 0.68;
|
|
9
|
+
const EM_OTHER = 0.56;
|
|
10
|
+
const EM_SPACE = 0.3;
|
|
11
|
+
/** One regional indicator is half of a flag emoji (a flag is a pair). */
|
|
12
|
+
const EM_REGIONAL = 0.5;
|
|
13
|
+
/**
|
|
14
|
+
* Code point ranges rendered full-width: East Asian Wide / Fullwidth blocks (CJK, kana, Hangul,
|
|
15
|
+
* full-width forms) and emoji. Sorted, inclusive, non-overlapping (binary searched).
|
|
16
|
+
*/
|
|
17
|
+
const WIDE_RANGES = [
|
|
18
|
+
[0x1100, 0x115f], // Hangul Jamo initials
|
|
19
|
+
[0x231a, 0x231b],
|
|
20
|
+
[0x2329, 0x232a],
|
|
21
|
+
[0x23e9, 0x23ec],
|
|
22
|
+
[0x23f0, 0x23f0],
|
|
23
|
+
[0x23f3, 0x23f3],
|
|
24
|
+
[0x25fd, 0x25fe],
|
|
25
|
+
[0x2600, 0x27bf], // misc symbols, dingbats (mostly emoji presentation)
|
|
26
|
+
[0x2b1b, 0x2b1c],
|
|
27
|
+
[0x2b50, 0x2b50],
|
|
28
|
+
[0x2b55, 0x2b55],
|
|
29
|
+
[0x2e80, 0x303e], // CJK radicals, Kangxi, ideographic description, CJK symbols & punctuation
|
|
30
|
+
[0x3041, 0x33ff], // kana, Bopomofo, Hangul compatibility, Kanbun, enclosed CJK, CJK compat
|
|
31
|
+
[0x3400, 0x4dbf], // CJK Ext. A
|
|
32
|
+
[0x4e00, 0x9fff], // CJK Unified Ideographs
|
|
33
|
+
[0xa000, 0xa4cf], // Yi
|
|
34
|
+
[0xa960, 0xa97f], // Hangul Jamo Ext. A
|
|
35
|
+
[0xac00, 0xd7a3], // Hangul syllables
|
|
36
|
+
[0xf900, 0xfaff], // CJK compatibility ideographs
|
|
37
|
+
[0xfe10, 0xfe19], // vertical forms
|
|
38
|
+
[0xfe30, 0xfe6f], // CJK compatibility forms, small forms
|
|
39
|
+
[0xff00, 0xff60], // full-width forms
|
|
40
|
+
[0xffe0, 0xffe6],
|
|
41
|
+
[0x16fe0, 0x18aff], // Tangut, Khitan…
|
|
42
|
+
[0x1b000, 0x1b2ff], // kana supplements
|
|
43
|
+
[0x1f004, 0x1f004],
|
|
44
|
+
[0x1f0cf, 0x1f0cf],
|
|
45
|
+
[0x1f18e, 0x1f18e],
|
|
46
|
+
[0x1f191, 0x1f19a],
|
|
47
|
+
[0x1f200, 0x1f2ff], // enclosed ideographic supplement
|
|
48
|
+
[0x1f300, 0x1f64f], // pictographs, emoticons
|
|
49
|
+
[0x1f680, 0x1f6ff], // transport & map
|
|
50
|
+
[0x1f7e0, 0x1f7eb],
|
|
51
|
+
[0x1f900, 0x1f9ff], // supplemental symbols & pictographs
|
|
52
|
+
[0x1fa70, 0x1faff],
|
|
53
|
+
[0x20000, 0x2fffd], // CJK Ext. B–F, compatibility supplement
|
|
54
|
+
[0x30000, 0x3fffd], // CJK Ext. G+
|
|
55
|
+
];
|
|
56
|
+
const ZERO_WIDTH = /[\p{Mn}\p{Me}\p{Cf}\p{Cc}]/u;
|
|
57
|
+
const SPACE = /\s/u;
|
|
58
|
+
const DIGIT = /\p{Nd}/u;
|
|
59
|
+
const UPPER = /\p{Lu}/u;
|
|
60
|
+
function inRanges(cp, ranges) {
|
|
61
|
+
let lo = 0;
|
|
62
|
+
let hi = ranges.length - 1;
|
|
63
|
+
while (lo <= hi) {
|
|
64
|
+
const mid = (lo + hi) >>> 1;
|
|
65
|
+
const range = ranges[mid];
|
|
66
|
+
if (range === undefined)
|
|
67
|
+
return false;
|
|
68
|
+
if (cp < range[0])
|
|
69
|
+
hi = mid - 1;
|
|
70
|
+
else if (cp > range[1])
|
|
71
|
+
lo = mid + 1;
|
|
72
|
+
else
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
function asciiAdvance(cp) {
|
|
78
|
+
if (cp === 0x20 || cp === 0x09)
|
|
79
|
+
return EM_SPACE;
|
|
80
|
+
if (cp < 0x20 || cp === 0x7f)
|
|
81
|
+
return 0;
|
|
82
|
+
if (cp >= 0x30 && cp <= 0x39)
|
|
83
|
+
return EM_DIGIT;
|
|
84
|
+
if (cp >= 0x41 && cp <= 0x5a)
|
|
85
|
+
return EM_UPPER;
|
|
86
|
+
return EM_OTHER;
|
|
87
|
+
}
|
|
88
|
+
/** Advance of one code point, in em. */
|
|
89
|
+
export function charAdvance(char) {
|
|
90
|
+
const cp = char.codePointAt(0) ?? 0;
|
|
91
|
+
if (cp < 0x80)
|
|
92
|
+
return asciiAdvance(cp);
|
|
93
|
+
// Combining marks, joiners, variation selectors, emoji skin-tone modifiers draw no advance.
|
|
94
|
+
if (ZERO_WIDTH.test(char) || (cp >= 0x1f3fb && cp <= 0x1f3ff))
|
|
95
|
+
return 0;
|
|
96
|
+
if (cp >= 0x1f1e6 && cp <= 0x1f1ff)
|
|
97
|
+
return EM_REGIONAL;
|
|
98
|
+
if (inRanges(cp, WIDE_RANGES))
|
|
99
|
+
return EM_WIDE;
|
|
100
|
+
if (SPACE.test(char))
|
|
101
|
+
return EM_SPACE;
|
|
102
|
+
if (DIGIT.test(char))
|
|
103
|
+
return EM_DIGIT;
|
|
104
|
+
if (UPPER.test(char))
|
|
105
|
+
return EM_UPPER;
|
|
106
|
+
return EM_OTHER;
|
|
107
|
+
}
|
|
108
|
+
/** Sum of per-character advances × font size. See the public `estimateLabelWidth`. */
|
|
109
|
+
export function labelWidth(text, fontSize) {
|
|
110
|
+
let em = 0;
|
|
111
|
+
for (let i = 0; i < text.length; i++) {
|
|
112
|
+
const unit = text.charCodeAt(i);
|
|
113
|
+
if (unit < 0x80) {
|
|
114
|
+
em += asciiAdvance(unit);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const cp = text.codePointAt(i) ?? unit;
|
|
118
|
+
const char = String.fromCodePoint(cp);
|
|
119
|
+
if (cp > 0xffff)
|
|
120
|
+
i++;
|
|
121
|
+
em += charAdvance(char);
|
|
122
|
+
}
|
|
123
|
+
return em * fontSize;
|
|
124
|
+
}
|
|
125
|
+
// ─── Label geometry (shared with bounds and collision) ───────────────────────
|
|
126
|
+
/** Gap between the node circle and the top of its label (world units, visual-language §Typography). */
|
|
127
|
+
export const LABEL_GAP = 5;
|
|
128
|
+
/** Height of one label line in em (12 px text + its 3 px halo). */
|
|
129
|
+
export const LINE_HEIGHT_EM = 1.25;
|
|
130
|
+
/** Renamed nodes show the old name 14 px (at 12 px text) below the new one, at 11/12 size. */
|
|
131
|
+
export const SECONDARY_OFFSET_EM = 14 / 12;
|
|
132
|
+
export const SECONDARY_SIZE_RATIO = 11 / 12;
|
|
133
|
+
/**
|
|
134
|
+
* Reserved label width is capped so a pathological label (a 300-character IRI) cannot blow up
|
|
135
|
+
* the layout; renderers truncate long labels anyway. 32 em ≈ 55 Latin characters.
|
|
136
|
+
*/
|
|
137
|
+
export const MAX_LABEL_EM = 32;
|
|
138
|
+
/**
|
|
139
|
+
* The block of text drawn centered below a node: its label and, for renamed nodes, the struck
|
|
140
|
+
* old label on a second, slightly smaller line.
|
|
141
|
+
*/
|
|
142
|
+
export function labelBox(label, labelBefore, fontSize) {
|
|
143
|
+
const max = MAX_LABEL_EM * fontSize;
|
|
144
|
+
let width = Math.min(max, labelWidth(label, fontSize));
|
|
145
|
+
let height = LINE_HEIGHT_EM * fontSize;
|
|
146
|
+
if (labelBefore !== undefined && labelBefore !== label) {
|
|
147
|
+
const secondary = fontSize * SECONDARY_SIZE_RATIO;
|
|
148
|
+
width = Math.max(width, Math.min(max, labelWidth(labelBefore, secondary)));
|
|
149
|
+
height += SECONDARY_OFFSET_EM * fontSize;
|
|
150
|
+
}
|
|
151
|
+
return { width, height };
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=text-metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-metrics.js","sourceRoot":"","sources":["../src/text-metrics.ts"],"names":[],"mappings":"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"}
|
package/dist/union.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The union graph as the layout sees it: nodes in id order, undirected neighbour pairs drawn
|
|
3
|
+
* from BOTH versions of every edge (so neither version is favoured), and merge / split partner
|
|
4
|
+
* pairs. Built once per call in O(N + E).
|
|
5
|
+
*/
|
|
6
|
+
import type { DiffResult, UnionId, UnionNode } from '@kgdiff/core';
|
|
7
|
+
export interface Partner {
|
|
8
|
+
/** The node that should travel little during replay (merge source / split target). */
|
|
9
|
+
readonly mover: number;
|
|
10
|
+
/** Where it travels to / from (merge target / split source). */
|
|
11
|
+
readonly anchor: number;
|
|
12
|
+
}
|
|
13
|
+
export interface UnionGraph {
|
|
14
|
+
/** Union nodes sorted by id (UTF-16 code unit order). */
|
|
15
|
+
readonly nodes: readonly UnionNode[];
|
|
16
|
+
readonly indexOf: ReadonlyMap<UnionId, number>;
|
|
17
|
+
/** Distinct undirected neighbour pairs [a, b] with a < b, in first-seen edge order. */
|
|
18
|
+
readonly pairs: Int32Array;
|
|
19
|
+
/** CSR adjacency over `pairs`: neighbours of i are `adjacency[offsets[i] .. offsets[i + 1])`, ascending. */
|
|
20
|
+
readonly offsets: Int32Array;
|
|
21
|
+
readonly adjacency: Int32Array;
|
|
22
|
+
readonly partners: readonly Partner[];
|
|
23
|
+
/** 1 for changed nodes and for endpoints (either version) of changed edges. */
|
|
24
|
+
readonly changed: Uint8Array;
|
|
25
|
+
}
|
|
26
|
+
/** Build CSR adjacency (ascending neighbour lists) from flat undirected pairs. */
|
|
27
|
+
export declare function buildAdjacency(n: number, pairs: Int32Array): {
|
|
28
|
+
offsets: Int32Array;
|
|
29
|
+
adjacency: Int32Array;
|
|
30
|
+
};
|
|
31
|
+
export declare function buildUnionGraph(diff: DiffResult): UnionGraph;
|
|
32
|
+
//# sourceMappingURL=union.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"union.d.ts","sourceRoot":"","sources":["../src/union.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,WAAW,OAAO;IACtB,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,uFAAuF;IACvF,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,4GAA4G;IAC5G,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;CAC9B;AAeD,kFAAkF;AAClF,wBAAgB,cAAc,CAC5B,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,UAAU,GAChB;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,UAAU,CAAA;CAAE,CAchD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAiE5D"}
|