@yurialvesbordin/graphium 0.0.0-stage → 2.0.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 +37 -2
- package/dist/Graphium.d.ts +156 -0
- package/dist/Graphium.d.ts.map +1 -0
- package/dist/Graphium.js +413 -0
- package/dist/Graphium.js.map +1 -0
- package/dist/core/FocusController.d.ts +16 -0
- package/dist/core/FocusController.d.ts.map +1 -0
- package/dist/core/FocusController.js +53 -0
- package/dist/core/FocusController.js.map +1 -0
- package/dist/core/GraphEditor.d.ts +61 -0
- package/dist/core/GraphEditor.d.ts.map +1 -0
- package/dist/core/GraphEditor.js +165 -0
- package/dist/core/GraphEditor.js.map +1 -0
- package/dist/core/GraphModel.d.ts +166 -0
- package/dist/core/GraphModel.d.ts.map +1 -0
- package/dist/core/GraphModel.js +730 -0
- package/dist/core/GraphModel.js.map +1 -0
- package/dist/core/SelectionController.d.ts +26 -0
- package/dist/core/SelectionController.d.ts.map +1 -0
- package/dist/core/SelectionController.js +78 -0
- package/dist/core/SelectionController.js.map +1 -0
- package/dist/core/colors.d.ts +27 -0
- package/dist/core/colors.d.ts.map +1 -0
- package/dist/core/colors.js +141 -0
- package/dist/core/colors.js.map +1 -0
- package/dist/core/events.d.ts +21 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +64 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/handles.d.ts +60 -0
- package/dist/core/handles.d.ts.map +1 -0
- package/dist/core/handles.js +116 -0
- package/dist/core/handles.js.map +1 -0
- package/dist/core/theme.d.ts +9 -0
- package/dist/core/theme.d.ts.map +1 -0
- package/dist/core/theme.js +167 -0
- package/dist/core/theme.js.map +1 -0
- package/dist/core/themes.d.ts +9 -0
- package/dist/core/themes.d.ts.map +1 -0
- package/dist/core/themes.js +103 -0
- package/dist/core/themes.js.map +1 -0
- package/dist/core/types.d.ts +287 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +7 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction/InteractionBinder.d.ts +43 -0
- package/dist/interaction/InteractionBinder.d.ts.map +1 -0
- package/dist/interaction/InteractionBinder.js +121 -0
- package/dist/interaction/InteractionBinder.js.map +1 -0
- package/dist/interaction/PointerController.d.ts +83 -0
- package/dist/interaction/PointerController.d.ts.map +1 -0
- package/dist/interaction/PointerController.js +294 -0
- package/dist/interaction/PointerController.js.map +1 -0
- package/dist/physics/PhysicsEngine.d.ts +82 -0
- package/dist/physics/PhysicsEngine.d.ts.map +1 -0
- package/dist/physics/PhysicsEngine.js +469 -0
- package/dist/physics/PhysicsEngine.js.map +1 -0
- package/dist/physics/SpatialHash.d.ts +36 -0
- package/dist/physics/SpatialHash.d.ts.map +1 -0
- package/dist/physics/SpatialHash.js +126 -0
- package/dist/physics/SpatialHash.js.map +1 -0
- package/dist/physics/presets.d.ts +14 -0
- package/dist/physics/presets.d.ts.map +1 -0
- package/dist/physics/presets.js +108 -0
- package/dist/physics/presets.js.map +1 -0
- package/dist/render/Camera.d.ts +55 -0
- package/dist/render/Camera.d.ts.map +1 -0
- package/dist/render/Camera.js +94 -0
- package/dist/render/Camera.js.map +1 -0
- package/dist/render/LabelLayer.d.ts +32 -0
- package/dist/render/LabelLayer.d.ts.map +1 -0
- package/dist/render/LabelLayer.js +142 -0
- package/dist/render/LabelLayer.js.map +1 -0
- package/dist/render/RenderLoop.d.ts +67 -0
- package/dist/render/RenderLoop.d.ts.map +1 -0
- package/dist/render/RenderLoop.js +126 -0
- package/dist/render/RenderLoop.js.map +1 -0
- package/dist/render/Renderer.d.ts +73 -0
- package/dist/render/Renderer.d.ts.map +1 -0
- package/dist/render/Renderer.js +512 -0
- package/dist/render/Renderer.js.map +1 -0
- package/dist/render/TextureAtlas.d.ts +51 -0
- package/dist/render/TextureAtlas.d.ts.map +1 -0
- package/dist/render/TextureAtlas.js +160 -0
- package/dist/render/TextureAtlas.js.map +1 -0
- package/dist/render/ViewportController.d.ts +34 -0
- package/dist/render/ViewportController.d.ts.map +1 -0
- package/dist/render/ViewportController.js +57 -0
- package/dist/render/ViewportController.js.map +1 -0
- package/dist/render/geometry.d.ts +19 -0
- package/dist/render/geometry.d.ts.map +1 -0
- package/dist/render/geometry.js +71 -0
- package/dist/render/geometry.js.map +1 -0
- package/dist/render/shaders.d.ts +13 -0
- package/dist/render/shaders.d.ts.map +1 -0
- package/dist/render/shaders.js +183 -0
- package/dist/render/shaders.js.map +1 -0
- package/package.json +73 -4
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implements a flat spatial hash grid with open addressing and intrusive
|
|
3
|
+
* linked lists stored in TypedArrays. Rebuild and query paths allocate
|
|
4
|
+
* nothing, which keeps the physics loop free of garbage collection pressure.
|
|
5
|
+
*/
|
|
6
|
+
export class SpatialHash {
|
|
7
|
+
constructor(nodeCapacity = 512, cellSize = 96) {
|
|
8
|
+
this.count = 0;
|
|
9
|
+
this.cellSize = Math.max(0.0001, cellSize);
|
|
10
|
+
this.invCellSize = 1 / this.cellSize;
|
|
11
|
+
this.nodeCapacity = Math.max(16, nodeCapacity);
|
|
12
|
+
this.tableCapacity = 16;
|
|
13
|
+
const requested = this.nodeCapacity * 4;
|
|
14
|
+
while (this.tableCapacity < requested) {
|
|
15
|
+
this.tableCapacity <<= 1;
|
|
16
|
+
}
|
|
17
|
+
this.mask = this.tableCapacity - 1;
|
|
18
|
+
this.keyX = new Int32Array(this.tableCapacity);
|
|
19
|
+
this.keyY = new Int32Array(this.tableCapacity);
|
|
20
|
+
this.head = new Int32Array(this.tableCapacity);
|
|
21
|
+
this.used = new Uint8Array(this.tableCapacity);
|
|
22
|
+
this.next = new Int32Array(this.nodeCapacity);
|
|
23
|
+
this.head.fill(-1);
|
|
24
|
+
this.next.fill(-1);
|
|
25
|
+
}
|
|
26
|
+
/** Changes the grid cell size and invalidates the current index. */
|
|
27
|
+
setCellSize(value) {
|
|
28
|
+
this.cellSize = Math.max(0.0001, value);
|
|
29
|
+
this.invCellSize = 1 / this.cellSize;
|
|
30
|
+
}
|
|
31
|
+
/** Grows the per node chain storage when the population increases. */
|
|
32
|
+
ensureCapacity(required) {
|
|
33
|
+
if (required <= this.nodeCapacity) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
let capacity = this.nodeCapacity;
|
|
37
|
+
while (capacity < required) {
|
|
38
|
+
capacity <<= 1;
|
|
39
|
+
}
|
|
40
|
+
const next = new Int32Array(capacity);
|
|
41
|
+
next.set(this.next);
|
|
42
|
+
next.fill(-1, this.nodeCapacity);
|
|
43
|
+
this.next = next;
|
|
44
|
+
this.nodeCapacity = capacity;
|
|
45
|
+
}
|
|
46
|
+
/** Clears every cell and prepares the grid for a new rebuild. */
|
|
47
|
+
clear() {
|
|
48
|
+
this.used.fill(0);
|
|
49
|
+
this.head.fill(-1);
|
|
50
|
+
this.next.fill(-1);
|
|
51
|
+
this.count = 0;
|
|
52
|
+
}
|
|
53
|
+
/** Computes the hash slot for a cell coordinate pair. */
|
|
54
|
+
hash(cx, cy) {
|
|
55
|
+
return (((cx * 73856093) ^ (cy * 19349663)) >>> 0) & this.mask;
|
|
56
|
+
}
|
|
57
|
+
/** Finds the slot holding a cell, or the first free slot after probing. */
|
|
58
|
+
slot(cx, cy) {
|
|
59
|
+
let slot = this.hash(cx, cy);
|
|
60
|
+
while (this.used[slot] && (this.keyX[slot] !== cx || this.keyY[slot] !== cy)) {
|
|
61
|
+
slot = (slot + 1) & this.mask;
|
|
62
|
+
}
|
|
63
|
+
return slot;
|
|
64
|
+
}
|
|
65
|
+
/** Rebuilds the grid over the first count positions, skipping nodes whose masked bits are set. */
|
|
66
|
+
rebuild(x, y, count, hidden, mask) {
|
|
67
|
+
this.ensureCapacity(count);
|
|
68
|
+
this.clear();
|
|
69
|
+
for (let index = 0; index < count; index++) {
|
|
70
|
+
if (hidden && (hidden[index] & (mask ?? 0xff)) !== 0) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const cx = Math.floor(x[index] * this.invCellSize);
|
|
74
|
+
const cy = Math.floor(y[index] * this.invCellSize);
|
|
75
|
+
const slot = this.slot(cx, cy);
|
|
76
|
+
if (!this.used[slot]) {
|
|
77
|
+
this.used[slot] = 1;
|
|
78
|
+
this.keyX[slot] = cx;
|
|
79
|
+
this.keyY[slot] = cy;
|
|
80
|
+
this.head[slot] = -1;
|
|
81
|
+
}
|
|
82
|
+
this.next[index] = this.head[slot];
|
|
83
|
+
this.head[slot] = index;
|
|
84
|
+
this.count++;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** Collects all indices inside the square radius window into the output. */
|
|
88
|
+
queryRadius(x, y, radius, output) {
|
|
89
|
+
const minX = Math.floor((x - radius) * this.invCellSize);
|
|
90
|
+
const maxX = Math.floor((x + radius) * this.invCellSize);
|
|
91
|
+
const minY = Math.floor((y - radius) * this.invCellSize);
|
|
92
|
+
const maxY = Math.floor((y + radius) * this.invCellSize);
|
|
93
|
+
let found = 0;
|
|
94
|
+
for (let cy = minY; cy <= maxY; cy++) {
|
|
95
|
+
for (let cx = minX; cx <= maxX; cx++) {
|
|
96
|
+
const slot = this.slot(cx, cy);
|
|
97
|
+
if (!this.used[slot] || this.keyX[slot] !== cx || this.keyY[slot] !== cy) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
for (let index = this.head[slot]; index >= 0 && found < output.length; index = this.next[index]) {
|
|
101
|
+
output[found++] = index;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return found;
|
|
106
|
+
}
|
|
107
|
+
/** Returns the node index whose disc contains the point, or -1. */
|
|
108
|
+
pick(x, y, posX, posY, radii, output) {
|
|
109
|
+
const found = this.queryRadius(x, y, 96, output);
|
|
110
|
+
let best = -1;
|
|
111
|
+
let bestDistance = Infinity;
|
|
112
|
+
for (let index = 0; index < found; index++) {
|
|
113
|
+
const candidate = output[index];
|
|
114
|
+
const dx = posX[candidate] - x;
|
|
115
|
+
const dy = posY[candidate] - y;
|
|
116
|
+
const distance = dx * dx + dy * dy;
|
|
117
|
+
const radius = radii[candidate];
|
|
118
|
+
if (distance <= radius * radius && distance < bestDistance) {
|
|
119
|
+
best = candidate;
|
|
120
|
+
bestDistance = distance;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return best;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=SpatialHash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpatialHash.js","sourceRoot":"","sources":["../../src/physics/SpatialHash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declares physics presets that translate one word into a full set of engine
|
|
3
|
+
* parameters. Presets only override what they express, so user supplied
|
|
4
|
+
* values always win over preset defaults.
|
|
5
|
+
*/
|
|
6
|
+
import type { PhysicsOptions, PhysicsPresetName } from '../core/types.js';
|
|
7
|
+
export interface PresetDefinition {
|
|
8
|
+
label: string;
|
|
9
|
+
values: PhysicsOptions;
|
|
10
|
+
}
|
|
11
|
+
export declare const PRESETS: Record<PhysicsPresetName, PresetDefinition>;
|
|
12
|
+
/** Returns the preset list in display order for user interfaces. */
|
|
13
|
+
export declare function presetNames(): PhysicsPresetName[];
|
|
14
|
+
//# sourceMappingURL=presets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/physics/presets.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,iBAAiB,EAAE,gBAAgB,CAiG/D,CAAC;AAEF,oEAAoE;AACpE,wBAAgB,WAAW,IAAI,iBAAiB,EAAE,CAEjD"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declares physics presets that translate one word into a full set of engine
|
|
3
|
+
* parameters. Presets only override what they express, so user supplied
|
|
4
|
+
* values always win over preset defaults.
|
|
5
|
+
*/
|
|
6
|
+
export const PRESETS = {
|
|
7
|
+
silk: {
|
|
8
|
+
label: 'Silk',
|
|
9
|
+
values: {
|
|
10
|
+
repulsion: 1100,
|
|
11
|
+
repulsionRadius: 200,
|
|
12
|
+
degreeFactor: 0.05,
|
|
13
|
+
degreeExponent: 0.75,
|
|
14
|
+
springStrength: 0.055,
|
|
15
|
+
gravity: 0.0022,
|
|
16
|
+
damping: 0.92,
|
|
17
|
+
maxSpeed: 900,
|
|
18
|
+
collisionStrength: 0.85,
|
|
19
|
+
positionIterations: 2,
|
|
20
|
+
temperature: 0.7,
|
|
21
|
+
cooling: 0.99,
|
|
22
|
+
minTemperature: 0.05,
|
|
23
|
+
sleepEnergy: 0.0004,
|
|
24
|
+
sleepFrames: 48,
|
|
25
|
+
maxNeighbors: 128,
|
|
26
|
+
dragSmooth: 0.42,
|
|
27
|
+
throwFactor: 1,
|
|
28
|
+
edgeSeparation: 0.45,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
bouncy: {
|
|
32
|
+
label: 'Bouncy',
|
|
33
|
+
values: {
|
|
34
|
+
repulsion: 1300,
|
|
35
|
+
repulsionRadius: 220,
|
|
36
|
+
degreeFactor: 0.06,
|
|
37
|
+
degreeExponent: 0.8,
|
|
38
|
+
springStrength: 0.11,
|
|
39
|
+
gravity: 0.0018,
|
|
40
|
+
damping: 0.84,
|
|
41
|
+
maxSpeed: 1400,
|
|
42
|
+
collisionStrength: 1.1,
|
|
43
|
+
positionIterations: 2,
|
|
44
|
+
temperature: 1,
|
|
45
|
+
cooling: 0.994,
|
|
46
|
+
minTemperature: 0.06,
|
|
47
|
+
sleepEnergy: 0.0006,
|
|
48
|
+
sleepFrames: 60,
|
|
49
|
+
maxNeighbors: 128,
|
|
50
|
+
dragSmooth: 0.3,
|
|
51
|
+
throwFactor: 1.25,
|
|
52
|
+
edgeSeparation: 0.3,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
crystal: {
|
|
56
|
+
label: 'Crystal',
|
|
57
|
+
values: {
|
|
58
|
+
repulsion: 900,
|
|
59
|
+
repulsionRadius: 160,
|
|
60
|
+
degreeFactor: 0.04,
|
|
61
|
+
degreeExponent: 0.7,
|
|
62
|
+
springStrength: 0.2,
|
|
63
|
+
gravity: 0.003,
|
|
64
|
+
damping: 0.78,
|
|
65
|
+
maxSpeed: 1100,
|
|
66
|
+
collisionStrength: 1.4,
|
|
67
|
+
positionIterations: 4,
|
|
68
|
+
temperature: 0.6,
|
|
69
|
+
cooling: 0.985,
|
|
70
|
+
minTemperature: 0.04,
|
|
71
|
+
sleepEnergy: 0.0003,
|
|
72
|
+
sleepFrames: 36,
|
|
73
|
+
maxNeighbors: 96,
|
|
74
|
+
dragSmooth: 0.6,
|
|
75
|
+
throwFactor: 0.7,
|
|
76
|
+
edgeSeparation: 0.6,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
liquid: {
|
|
80
|
+
label: 'Liquid',
|
|
81
|
+
values: {
|
|
82
|
+
repulsion: 800,
|
|
83
|
+
repulsionRadius: 240,
|
|
84
|
+
degreeFactor: 0.05,
|
|
85
|
+
degreeExponent: 0.75,
|
|
86
|
+
springStrength: 0.035,
|
|
87
|
+
gravity: 0.0045,
|
|
88
|
+
damping: 0.96,
|
|
89
|
+
maxSpeed: 620,
|
|
90
|
+
collisionStrength: 0.7,
|
|
91
|
+
positionIterations: 1,
|
|
92
|
+
temperature: 0.5,
|
|
93
|
+
cooling: 0.995,
|
|
94
|
+
minTemperature: 0.03,
|
|
95
|
+
sleepEnergy: 0.0002,
|
|
96
|
+
sleepFrames: 70,
|
|
97
|
+
maxNeighbors: 96,
|
|
98
|
+
dragSmooth: 0.22,
|
|
99
|
+
throwFactor: 0.9,
|
|
100
|
+
edgeSeparation: 0.2,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
/** Returns the preset list in display order for user interfaces. */
|
|
105
|
+
export function presetNames() {
|
|
106
|
+
return ['silk', 'bouncy', 'crystal', 'liquid'];
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/physics/presets.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,MAAM,CAAC,MAAM,OAAO,GAAgD;IAClE,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM;QACb,MAAM,EAAE;YACN,SAAS,EAAE,IAAI;YACf,eAAe,EAAE,GAAG;YACpB,YAAY,EAAE,IAAI;YAClB,cAAc,EAAE,IAAI;YACpB,cAAc,EAAE,KAAK;YACrB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,GAAG;YACb,iBAAiB,EAAE,IAAI;YACvB,kBAAkB,EAAE,CAAC;YACrB,WAAW,EAAE,GAAG;YAChB,OAAO,EAAE,IAAI;YACb,cAAc,EAAE,IAAI;YACpB,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,GAAG;YACjB,UAAU,EAAE,IAAI;YAChB,WAAW,EAAE,CAAC;YACd,cAAc,EAAE,IAAI;SACrB;KACF;IACD,MAAM,EAAE;QACN,KAAK,EAAE,QAAQ;QACf,MAAM,EAAE;YACN,SAAS,EAAE,IAAI;YACf,eAAe,EAAE,GAAG;YACpB,YAAY,EAAE,IAAI;YAClB,cAAc,EAAE,GAAG;YACnB,cAAc,EAAE,IAAI;YACpB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,iBAAiB,EAAE,GAAG;YACtB,kBAAkB,EAAE,CAAC;YACrB,WAAW,EAAE,CAAC;YACd,OAAO,EAAE,KAAK;YACd,cAAc,EAAE,IAAI;YACpB,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,GAAG;YACjB,UAAU,EAAE,GAAG;YACf,WAAW,EAAE,IAAI;YACjB,cAAc,EAAE,GAAG;SACpB;KACF;IACD,OAAO,EAAE;QACP,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE;YACN,SAAS,EAAE,GAAG;YACd,eAAe,EAAE,GAAG;YACpB,YAAY,EAAE,IAAI;YAClB,cAAc,EAAE,GAAG;YACnB,cAAc,EAAE,GAAG;YACnB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,iBAAiB,EAAE,GAAG;YACtB,kBAAkB,EAAE,CAAC;YACrB,WAAW,EAAE,GAAG;YAChB,OAAO,EAAE,KAAK;YACd,cAAc,EAAE,IAAI;YACpB,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,EAAE;YAChB,UAAU,EAAE,GAAG;YACf,WAAW,EAAE,GAAG;YAChB,cAAc,EAAE,GAAG;SACpB;KACF;IACD,MAAM,EAAE;QACN,KAAK,EAAE,QAAQ;QACf,MAAM,EAAE;YACN,SAAS,EAAE,GAAG;YACd,eAAe,EAAE,GAAG;YACpB,YAAY,EAAE,IAAI;YAClB,cAAc,EAAE,IAAI;YACpB,cAAc,EAAE,KAAK;YACrB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,GAAG;YACb,iBAAiB,EAAE,GAAG;YACtB,kBAAkB,EAAE,CAAC;YACrB,WAAW,EAAE,GAAG;YAChB,OAAO,EAAE,KAAK;YACd,cAAc,EAAE,IAAI;YACpB,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,EAAE;YAChB,UAAU,EAAE,IAAI;YAChB,WAAW,EAAE,GAAG;YAChB,cAAc,EAAE,GAAG;SACpB;KACF;CACF,CAAC;AAEF,oEAAoE;AACpE,MAAM,UAAU,WAAW;IACzB,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maintains the 2D view transform as a cached 3x3 matrix and provides
|
|
3
|
+
* coordinate conversion helpers for pointer math and label placement.
|
|
4
|
+
*/
|
|
5
|
+
export declare class Camera {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
zoom: number;
|
|
11
|
+
minZoom: number;
|
|
12
|
+
maxZoom: number;
|
|
13
|
+
revision: number;
|
|
14
|
+
readonly matrix: Float32Array;
|
|
15
|
+
constructor(options?: {
|
|
16
|
+
width?: number;
|
|
17
|
+
height?: number;
|
|
18
|
+
x?: number;
|
|
19
|
+
y?: number;
|
|
20
|
+
zoom?: number;
|
|
21
|
+
minZoom?: number;
|
|
22
|
+
maxZoom?: number;
|
|
23
|
+
});
|
|
24
|
+
/** Recomputes the cached view matrix after any transform change. */
|
|
25
|
+
private updateMatrix;
|
|
26
|
+
/** Resizes the viewport and refreshes the view matrix. */
|
|
27
|
+
setViewport(width: number, height: number): this;
|
|
28
|
+
/** Moves the camera center to a world position. */
|
|
29
|
+
setPosition(x: number, y: number): this;
|
|
30
|
+
/** Sets the zoom level clamped between the configured limits. */
|
|
31
|
+
setZoom(zoom: number): this;
|
|
32
|
+
/** Pans the view by a screen pixel delta. */
|
|
33
|
+
pan(dx: number, dy: number): this;
|
|
34
|
+
/** Zooms while keeping the supplied screen point visually anchored. */
|
|
35
|
+
zoomAt(factor: number, screenX: number, screenY: number): this;
|
|
36
|
+
/** Converts world coordinates into screen pixels. */
|
|
37
|
+
worldToScreen(worldX: number, worldY: number, out: {
|
|
38
|
+
x: number;
|
|
39
|
+
y: number;
|
|
40
|
+
}): {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
};
|
|
44
|
+
/** Converts screen pixels into world coordinates. */
|
|
45
|
+
screenToWorld(screenX: number, screenY: number, out: {
|
|
46
|
+
x: number;
|
|
47
|
+
y: number;
|
|
48
|
+
}): {
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
};
|
|
52
|
+
/** Positions and scales the camera so a world rectangle fits the view. */
|
|
53
|
+
fit(minX: number, minY: number, maxX: number, maxY: number, padding?: number): this;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=Camera.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Camera.d.ts","sourceRoot":"","sources":["../../src/render/Camera.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,MAAM;IACjB,KAAK,SAAK;IACV,MAAM,SAAK;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,SAAK;IACb,QAAQ,CAAC,MAAM,eAAuB;gBAE1B,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IASxI,oEAAoE;IACpE,OAAO,CAAC,YAAY;IAepB,0DAA0D;IAC1D,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAOhD,mDAAmD;IACnD,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAOvC,iEAAiE;IACjE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAM3B,6CAA6C;IAC7C,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAOjC,uEAAuE;IACvE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAU9D,qDAAqD;IACrD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;IAMtG,qDAAqD;IACrD,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;IAMxG,0EAA0E;IAC1E,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,IAAI;CAUhF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maintains the 2D view transform as a cached 3x3 matrix and provides
|
|
3
|
+
* coordinate conversion helpers for pointer math and label placement.
|
|
4
|
+
*/
|
|
5
|
+
export class Camera {
|
|
6
|
+
constructor(options = {}) {
|
|
7
|
+
this.width = 1;
|
|
8
|
+
this.height = 1;
|
|
9
|
+
this.revision = 0;
|
|
10
|
+
this.matrix = new Float32Array(9);
|
|
11
|
+
this.x = Number.isFinite(options.x) ? options.x : 0;
|
|
12
|
+
this.y = Number.isFinite(options.y) ? options.y : 0;
|
|
13
|
+
this.zoom = Number.isFinite(options.zoom) ? options.zoom : 1;
|
|
14
|
+
this.minZoom = options.minZoom ?? 0.02;
|
|
15
|
+
this.maxZoom = options.maxZoom ?? 80;
|
|
16
|
+
this.updateMatrix();
|
|
17
|
+
}
|
|
18
|
+
/** Recomputes the cached view matrix after any transform change. */
|
|
19
|
+
updateMatrix() {
|
|
20
|
+
const sx = (2 * this.zoom) / this.width;
|
|
21
|
+
const sy = (-2 * this.zoom) / this.height;
|
|
22
|
+
this.matrix[0] = sx;
|
|
23
|
+
this.matrix[1] = 0;
|
|
24
|
+
this.matrix[2] = 0;
|
|
25
|
+
this.matrix[3] = 0;
|
|
26
|
+
this.matrix[4] = sy;
|
|
27
|
+
this.matrix[5] = 0;
|
|
28
|
+
this.matrix[6] = -sx * this.x;
|
|
29
|
+
this.matrix[7] = -sy * this.y;
|
|
30
|
+
this.matrix[8] = 1;
|
|
31
|
+
this.revision++;
|
|
32
|
+
}
|
|
33
|
+
/** Resizes the viewport and refreshes the view matrix. */
|
|
34
|
+
setViewport(width, height) {
|
|
35
|
+
this.width = Math.max(1, width);
|
|
36
|
+
this.height = Math.max(1, height);
|
|
37
|
+
this.updateMatrix();
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
/** Moves the camera center to a world position. */
|
|
41
|
+
setPosition(x, y) {
|
|
42
|
+
this.x = x;
|
|
43
|
+
this.y = y;
|
|
44
|
+
this.updateMatrix();
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
/** Sets the zoom level clamped between the configured limits. */
|
|
48
|
+
setZoom(zoom) {
|
|
49
|
+
this.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, zoom));
|
|
50
|
+
this.updateMatrix();
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
/** Pans the view by a screen pixel delta. */
|
|
54
|
+
pan(dx, dy) {
|
|
55
|
+
this.x += dx / this.zoom;
|
|
56
|
+
this.y += dy / this.zoom;
|
|
57
|
+
this.updateMatrix();
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
/** Zooms while keeping the supplied screen point visually anchored. */
|
|
61
|
+
zoomAt(factor, screenX, screenY) {
|
|
62
|
+
const beforeX = this.x + (screenX - this.width * 0.5) / this.zoom;
|
|
63
|
+
const beforeY = this.y + (screenY - this.height * 0.5) / this.zoom;
|
|
64
|
+
this.setZoom(this.zoom * factor);
|
|
65
|
+
this.x = beforeX - (screenX - this.width * 0.5) / this.zoom;
|
|
66
|
+
this.y = beforeY - (screenY - this.height * 0.5) / this.zoom;
|
|
67
|
+
this.updateMatrix();
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
/** Converts world coordinates into screen pixels. */
|
|
71
|
+
worldToScreen(worldX, worldY, out) {
|
|
72
|
+
out.x = this.zoom * (worldX - this.x) + this.width * 0.5;
|
|
73
|
+
out.y = this.zoom * (worldY - this.y) + this.height * 0.5;
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
/** Converts screen pixels into world coordinates. */
|
|
77
|
+
screenToWorld(screenX, screenY, out) {
|
|
78
|
+
out.x = this.x + (screenX - this.width * 0.5) / this.zoom;
|
|
79
|
+
out.y = this.y + (screenY - this.height * 0.5) / this.zoom;
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
/** Positions and scales the camera so a world rectangle fits the view. */
|
|
83
|
+
fit(minX, minY, maxX, maxY, padding = 40) {
|
|
84
|
+
const width = Math.max(1, maxX - minX);
|
|
85
|
+
const height = Math.max(1, maxY - minY);
|
|
86
|
+
const availableWidth = Math.max(1, this.width - padding * 2);
|
|
87
|
+
const availableHeight = Math.max(1, this.height - padding * 2);
|
|
88
|
+
this.x = (minX + maxX) * 0.5;
|
|
89
|
+
this.y = (minY + maxY) * 0.5;
|
|
90
|
+
this.setZoom(Math.min(availableWidth / width, availableHeight / height));
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=Camera.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Camera.js","sourceRoot":"","sources":["../../src/render/Camera.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,OAAO,MAAM;IAWjB,YAAY,UAA0H,EAAE;QAVxI,UAAK,GAAG,CAAC,CAAC;QACV,WAAM,GAAG,CAAC,CAAC;QAMX,aAAQ,GAAG,CAAC,CAAC;QACJ,WAAM,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;QAGpC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,OAAO,CAAC,CAAY,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,OAAO,CAAC,CAAY,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,OAAO,CAAC,IAAe,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,oEAAoE;IAC5D,YAAY;QAClB,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;QACxC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAED,0DAA0D;IAC1D,WAAW,CAAC,KAAa,EAAE,MAAc;QACvC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mDAAmD;IACnD,WAAW,CAAC,CAAS,EAAE,CAAS;QAC9B,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACX,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACX,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iEAAiE;IACjE,OAAO,CAAC,IAAY;QAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACjE,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,6CAA6C;IAC7C,GAAG,CAAC,EAAU,EAAE,EAAU;QACxB,IAAI,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uEAAuE;IACvE,MAAM,CAAC,MAAc,EAAE,OAAe,EAAE,OAAe;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QAClE,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QACnE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QAC5D,IAAI,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QAC7D,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qDAAqD;IACrD,aAAa,CAAC,MAAc,EAAE,MAAc,EAAE,GAA6B;QACzE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;QACzD,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAC1D,OAAO,GAAG,CAAC;IACb,CAAC;IAED,qDAAqD;IACrD,aAAa,CAAC,OAAe,EAAE,OAAe,EAAE,GAA6B;QAC3E,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QAC1D,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QAC3D,OAAO,GAAG,CAAC;IACb,CAAC;IAED,0EAA0E;IAC1E,GAAG,CAAC,IAAY,EAAE,IAAY,EAAE,IAAY,EAAE,IAAY,EAAE,OAAO,GAAG,EAAE;QACtE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;QACxC,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC;QAC7D,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC;QAC/D,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC;QAC7B,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC;QAC7B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,GAAG,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,CAAC,CAAC;QACzE,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders node labels as a pooled set of DOM elements positioned over the
|
|
3
|
+
* canvas. The pool keeps at most a fixed number of elements alive, updates
|
|
4
|
+
* transforms without layout thrash and hides labels below a zoom threshold.
|
|
5
|
+
*/
|
|
6
|
+
import { GraphModel } from '../core/GraphModel.js';
|
|
7
|
+
import type { ThemeResolved } from '../core/types.js';
|
|
8
|
+
import { Camera } from './Camera.js';
|
|
9
|
+
export declare class LabelLayer {
|
|
10
|
+
container: HTMLDivElement;
|
|
11
|
+
theme: ThemeResolved;
|
|
12
|
+
minZoom: number;
|
|
13
|
+
private model;
|
|
14
|
+
private camera;
|
|
15
|
+
private pool;
|
|
16
|
+
private activeCount;
|
|
17
|
+
private screen;
|
|
18
|
+
constructor(parent: HTMLElement, theme: ThemeResolved);
|
|
19
|
+
/** Applies label styling from the theme to the pool and future nodes. */
|
|
20
|
+
applyTheme(): void;
|
|
21
|
+
/** Registers the model and camera the layer reads positions from. */
|
|
22
|
+
attach(model: GraphModel, camera: Camera): void;
|
|
23
|
+
/** Syncs pooled labels with visible nodes for the current frame. */
|
|
24
|
+
update(): void;
|
|
25
|
+
/** Returns a styled pool element, creating new ones only when needed. */
|
|
26
|
+
private acquire;
|
|
27
|
+
/** Hides every active label element. */
|
|
28
|
+
private hideAll;
|
|
29
|
+
/** Removes all DOM elements and detaches the layer. */
|
|
30
|
+
destroy(): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=LabelLayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LabelLayer.d.ts","sourceRoot":"","sources":["../../src/render/LabelLayer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAyB,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,qBAAa,UAAU;IACrB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,SAAO;IAEd,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,IAAI,CAAwB;IACpC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa;IAkBrD,yEAAyE;IACzE,UAAU,IAAI,IAAI;IAgBlB,qEAAqE;IACrE,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAK/C,oEAAoE;IACpE,MAAM,IAAI,IAAI;IA6Cd,yEAAyE;IACzE,OAAO,CAAC,OAAO;IAyBf,wCAAwC;IACxC,OAAO,CAAC,OAAO;IAOf,uDAAuD;IACvD,OAAO,IAAI,IAAI;CAQhB"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders node labels as a pooled set of DOM elements positioned over the
|
|
3
|
+
* canvas. The pool keeps at most a fixed number of elements alive, updates
|
|
4
|
+
* transforms without layout thrash and hides labels below a zoom threshold.
|
|
5
|
+
*/
|
|
6
|
+
import { NODE_DIM, NODE_HIDDEN } from '../core/GraphModel.js';
|
|
7
|
+
const MAX_LABELS = 400;
|
|
8
|
+
export class LabelLayer {
|
|
9
|
+
constructor(parent, theme) {
|
|
10
|
+
this.minZoom = 0.3;
|
|
11
|
+
this.model = null;
|
|
12
|
+
this.camera = null;
|
|
13
|
+
this.pool = [];
|
|
14
|
+
this.activeCount = 0;
|
|
15
|
+
this.screen = { x: 0, y: 0 };
|
|
16
|
+
this.theme = theme;
|
|
17
|
+
this.container = document.createElement('div');
|
|
18
|
+
Object.assign(this.container.style, {
|
|
19
|
+
position: 'absolute',
|
|
20
|
+
top: '0',
|
|
21
|
+
left: '0',
|
|
22
|
+
width: '100%',
|
|
23
|
+
height: '100%',
|
|
24
|
+
overflow: 'hidden',
|
|
25
|
+
pointerEvents: 'none',
|
|
26
|
+
userSelect: 'none',
|
|
27
|
+
zIndex: '1',
|
|
28
|
+
});
|
|
29
|
+
parent.appendChild(this.container);
|
|
30
|
+
this.applyTheme();
|
|
31
|
+
}
|
|
32
|
+
/** Applies label styling from the theme to the pool and future nodes. */
|
|
33
|
+
applyTheme() {
|
|
34
|
+
const label = this.theme;
|
|
35
|
+
for (const element of this.pool) {
|
|
36
|
+
element.style.font = `${label.labelWeight} ${label.labelSize}px ${label.labelFont}`;
|
|
37
|
+
element.style.color = label.labelColor;
|
|
38
|
+
if (label.labelBackground) {
|
|
39
|
+
element.style.background = label.labelBackground;
|
|
40
|
+
element.style.padding = `${label.labelPadding[1]}px ${label.labelPadding[0]}px`;
|
|
41
|
+
element.style.borderRadius = `${label.labelRadius}px`;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
element.style.background = 'none';
|
|
45
|
+
element.style.padding = '0';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Registers the model and camera the layer reads positions from. */
|
|
50
|
+
attach(model, camera) {
|
|
51
|
+
this.model = model;
|
|
52
|
+
this.camera = camera;
|
|
53
|
+
}
|
|
54
|
+
/** Syncs pooled labels with visible nodes for the current frame. */
|
|
55
|
+
update() {
|
|
56
|
+
const model = this.model;
|
|
57
|
+
const camera = this.camera;
|
|
58
|
+
if (!model || !camera) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const enabled = this.theme.labelEnabled;
|
|
62
|
+
if (!enabled || camera.zoom < this.minZoom) {
|
|
63
|
+
this.hideAll();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const margin = 40;
|
|
67
|
+
let used = 0;
|
|
68
|
+
const width = camera.width;
|
|
69
|
+
const height = camera.height;
|
|
70
|
+
for (let index = 0; index < model.nodeCount && used < MAX_LABELS; index++) {
|
|
71
|
+
const label = model.nodeLabel[index];
|
|
72
|
+
if (label === null || (model.flags[index] & (NODE_HIDDEN | NODE_DIM)) !== 0) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const screenX = camera.zoom * (model.x[index] - camera.x) + width * 0.5;
|
|
76
|
+
const screenY = camera.zoom * (model.y[index] - camera.y) + height * 0.5;
|
|
77
|
+
if (screenX < -margin || screenX > width + margin || screenY < -margin || screenY > height + margin) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const element = this.acquire(used++);
|
|
81
|
+
const offset = model.visualRadius[index] * camera.zoom;
|
|
82
|
+
let top = screenY;
|
|
83
|
+
if (this.theme.labelPosition === 'above') {
|
|
84
|
+
top -= offset + this.theme.labelOffset;
|
|
85
|
+
}
|
|
86
|
+
else if (this.theme.labelPosition === 'below') {
|
|
87
|
+
top += offset + this.theme.labelOffset;
|
|
88
|
+
}
|
|
89
|
+
if (element.textContent !== label) {
|
|
90
|
+
element.textContent = label;
|
|
91
|
+
}
|
|
92
|
+
element.style.display = '';
|
|
93
|
+
element.style.transform = `translate3d(${screenX.toFixed(1)}px, ${top.toFixed(1)}px, 0) translate(-50%, -50%)`;
|
|
94
|
+
}
|
|
95
|
+
for (let index = used; index < this.activeCount; index++) {
|
|
96
|
+
this.pool[index].style.display = 'none';
|
|
97
|
+
}
|
|
98
|
+
this.activeCount = used;
|
|
99
|
+
}
|
|
100
|
+
/** Returns a styled pool element, creating new ones only when needed. */
|
|
101
|
+
acquire(index) {
|
|
102
|
+
if (index < this.pool.length) {
|
|
103
|
+
return this.pool[index];
|
|
104
|
+
}
|
|
105
|
+
const element = document.createElement('div');
|
|
106
|
+
Object.assign(element.style, {
|
|
107
|
+
position: 'absolute',
|
|
108
|
+
top: '0',
|
|
109
|
+
left: '0',
|
|
110
|
+
whiteSpace: 'nowrap',
|
|
111
|
+
willChange: 'transform',
|
|
112
|
+
pointerEvents: 'none',
|
|
113
|
+
});
|
|
114
|
+
element.style.font = `${this.theme.labelWeight} ${this.theme.labelSize}px ${this.theme.labelFont}`;
|
|
115
|
+
element.style.color = this.theme.labelColor;
|
|
116
|
+
if (this.theme.labelBackground) {
|
|
117
|
+
element.style.background = this.theme.labelBackground;
|
|
118
|
+
element.style.padding = `${this.theme.labelPadding[1]}px ${this.theme.labelPadding[0]}px`;
|
|
119
|
+
element.style.borderRadius = `${this.theme.labelRadius}px`;
|
|
120
|
+
}
|
|
121
|
+
this.container.appendChild(element);
|
|
122
|
+
this.pool.push(element);
|
|
123
|
+
return element;
|
|
124
|
+
}
|
|
125
|
+
/** Hides every active label element. */
|
|
126
|
+
hideAll() {
|
|
127
|
+
for (let index = 0; index < this.activeCount; index++) {
|
|
128
|
+
this.pool[index].style.display = 'none';
|
|
129
|
+
}
|
|
130
|
+
this.activeCount = 0;
|
|
131
|
+
}
|
|
132
|
+
/** Removes all DOM elements and detaches the layer. */
|
|
133
|
+
destroy() {
|
|
134
|
+
for (const element of this.pool) {
|
|
135
|
+
element.remove();
|
|
136
|
+
}
|
|
137
|
+
this.pool.length = 0;
|
|
138
|
+
this.activeCount = 0;
|
|
139
|
+
this.container.remove();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=LabelLayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LabelLayer.js","sourceRoot":"","sources":["../../src/render/LabelLayer.ts"],"names":[],"mappings":"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"}
|