@painekillers/tree-builder-core 1.0.0 → 1.1.1
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/graph.js +76 -8
- package/package.json +2 -2
- package/world/bridge.js +2 -2
package/graph.js
CHANGED
|
@@ -79,8 +79,28 @@ export class LayoutNode {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/*
|
|
83
|
+
Recursion settings
|
|
84
|
+
Null: No recursion
|
|
85
|
+
False: Creates fake nodes when encountering recursion
|
|
86
|
+
True: Connects back to existing instance of a node when recursing
|
|
87
|
+
#: Real recursion to depths #
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/*
|
|
91
|
+
Strategies
|
|
92
|
+
- [X] Current BFS (First) — Layer by shortest distance from root; first discovery determines placement.
|
|
93
|
+
- [X] Undirected BFS (Undirected) — Shortest distance to root; layering is one directional.
|
|
94
|
+
- [X] Directed BFS, outward only (Outwards) — Follow prerequisite-to-dependent edges only.
|
|
95
|
+
- [X] Furthest-parent layering (Furthest) — Place each node one layer below its deepest prerequisite.
|
|
96
|
+
*/
|
|
97
|
+
|
|
82
98
|
export class LayoutGraph {
|
|
83
|
-
constructor(graph, root, recurse) {
|
|
99
|
+
constructor(graph, root, recurse, strategy = "First") {
|
|
100
|
+
if(strategy == "First" && typeof recurse == "number") {
|
|
101
|
+
throw new Error(`Cannot use strategy ${strategy} with numeric recursion setting`);
|
|
102
|
+
}
|
|
103
|
+
|
|
84
104
|
this.layers = new Map()
|
|
85
105
|
|
|
86
106
|
const rootNode = graph.nodeFromId(root)
|
|
@@ -96,13 +116,13 @@ export class LayoutGraph {
|
|
|
96
116
|
const visited = new Map()
|
|
97
117
|
const connections = new Set()
|
|
98
118
|
|
|
99
|
-
const addConnection = (ln, from) => {
|
|
119
|
+
const addConnection = (ln, from, lnPos) => {
|
|
100
120
|
const fromNode =
|
|
101
121
|
this.layers.get(from.layer)?.[from.ind]
|
|
102
122
|
|
|
103
123
|
if(!fromNode) return
|
|
104
124
|
|
|
105
|
-
const a = `${
|
|
125
|
+
const a = `${lnPos.layer}:${lnPos.ind}`
|
|
106
126
|
const b = `${from.layer}:${from.ind}`
|
|
107
127
|
|
|
108
128
|
const key = [a, b].sort().join("|")
|
|
@@ -145,13 +165,29 @@ export class LayoutGraph {
|
|
|
145
165
|
|
|
146
166
|
//holy crap i cannot think bruh
|
|
147
167
|
if(((recurse === false) || (recurse === null)) && pos.layer !== layer) {
|
|
148
|
-
if(
|
|
168
|
+
if (
|
|
169
|
+
recurse === null ||
|
|
170
|
+
strategy == "Outwards" &&
|
|
171
|
+
from !== null &&
|
|
172
|
+
Math.abs(layer) < Math.abs(from.layer)
|
|
173
|
+
) { continue }
|
|
174
|
+
|
|
175
|
+
if (
|
|
176
|
+
strategy == "Furthest" &&
|
|
177
|
+
(
|
|
178
|
+
(layer > 0 && !node.parents.every(val => visited.has(val.id)))
|
|
179
|
+
||
|
|
180
|
+
(layer < 0 && !node.children.every(val => visited.has(val.id)))
|
|
181
|
+
)
|
|
182
|
+
) { continue }
|
|
183
|
+
|
|
184
|
+
//this part makes the fake node btw
|
|
149
185
|
const fn = new LayoutNode(node, layer, this.layers.get(pos.layer)[pos.ind])
|
|
150
186
|
this.layers.get(layer).push(fn)
|
|
151
187
|
|
|
152
|
-
addConnection(fn, from)
|
|
188
|
+
addConnection(fn, from, pos)
|
|
153
189
|
} else {
|
|
154
|
-
addConnection(ln, from)
|
|
190
|
+
addConnection(ln, from, pos)
|
|
155
191
|
|
|
156
192
|
}
|
|
157
193
|
}
|
|
@@ -159,6 +195,37 @@ export class LayoutGraph {
|
|
|
159
195
|
continue
|
|
160
196
|
}
|
|
161
197
|
|
|
198
|
+
if (
|
|
199
|
+
strategy == "Outwards" &&
|
|
200
|
+
from !== null &&
|
|
201
|
+
Math.abs(layer) < Math.abs(from.layer)
|
|
202
|
+
) { continue }
|
|
203
|
+
|
|
204
|
+
if (strategy == "Furthest") {
|
|
205
|
+
if (layer > 0 && !node.parents.every(val => visited.has(val.id))) {
|
|
206
|
+
for (const parent of node.parents) {
|
|
207
|
+
queue.push({
|
|
208
|
+
node: parent,
|
|
209
|
+
layer: layer - 1,
|
|
210
|
+
from: null
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
continue
|
|
215
|
+
} else
|
|
216
|
+
if (layer < 0 && !node.children.every(val => visited.has(val.id))) {
|
|
217
|
+
for (const child of node.children) {
|
|
218
|
+
queue.push({
|
|
219
|
+
node: child,
|
|
220
|
+
layer: layer + 1,
|
|
221
|
+
from: null
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
continue
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
162
229
|
const ln = new LayoutNode(node, layer)
|
|
163
230
|
|
|
164
231
|
this.layers.get(layer).push(ln)
|
|
@@ -171,7 +238,7 @@ export class LayoutGraph {
|
|
|
171
238
|
visited.set(key, pos)
|
|
172
239
|
|
|
173
240
|
if(from) {
|
|
174
|
-
addConnection(ln, from)
|
|
241
|
+
addConnection(ln, from, pos)
|
|
175
242
|
}
|
|
176
243
|
|
|
177
244
|
for (const child of node.children) {
|
|
@@ -185,10 +252,11 @@ export class LayoutGraph {
|
|
|
185
252
|
for (const parent of node.parents) {
|
|
186
253
|
queue.push({
|
|
187
254
|
node: parent,
|
|
188
|
-
layer: layer - 1,
|
|
255
|
+
layer: strategy !== "Undirected" ? layer - 1: layer + 1,
|
|
189
256
|
from: pos
|
|
190
257
|
})
|
|
191
258
|
}
|
|
259
|
+
|
|
192
260
|
}
|
|
193
261
|
}
|
|
194
262
|
}
|
package/package.json
CHANGED
package/world/bridge.js
CHANGED
|
@@ -25,8 +25,8 @@ export default class Bridge {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
calculateLayout(root, recurse){ // Real maxdepth, since we cant actually make it infinite
|
|
29
|
-
this.layout = new LayoutGraph(this.graph, root, recurse)
|
|
28
|
+
calculateLayout(root, recurse, strategy = "First"){ // Real maxdepth, since we cant actually make it infinite
|
|
29
|
+
this.layout = new LayoutGraph(this.graph, root, recurse, strategy)
|
|
30
30
|
// Since JS is goofy like this ill just have recurse be a number when we want recursive
|
|
31
31
|
this.root = this.graph.nodes.get(root)
|
|
32
32
|
|