@@ -66,10 +66,12 @@ const _computeCenter2Layout = (
66
66
depth = 0 ,
67
67
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
68
68
offsets : number [ ] ,
69
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
70
+ tracer : { maxX : number } ,
69
71
) : DeepWriteable < TreeWithLayout > => {
70
72
const children = tree . children ?. map ( ( child ) => ( {
71
73
edgeData : child . edgeData ,
72
- node : _computeCenter2Layout ( child . node , depth + 1 , offsets ) ,
74
+ node : _computeCenter2Layout ( child . node , depth + 1 , offsets , tracer ) ,
73
75
} ) )
74
76
75
77
let x : number
@@ -89,6 +91,7 @@ const _computeCenter2Layout = (
89
91
x = Math . max ( offsets [ depth ] ?? 0 , c )
90
92
m = x - c
91
93
}
94
+ tracer . maxX = Math . max ( tracer . maxX , x )
92
95
offsets [ depth ] = 1 + x
93
96
94
97
return {
@@ -103,15 +106,144 @@ const _computeCenter2Layout = (
103
106
} satisfies Readonly < TreeWithLayout > as DeepWriteable < TreeWithLayout >
104
107
}
105
108
106
- export const computeCenter2Layout = (
109
+ const _inPlaceEvenSpacingUpdate = (
110
+ numChildren : number ,
111
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
112
+ tree : DeepWriteable < TreeWithLayout > ,
113
+ shift : number ,
114
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
115
+ offsets : number [ ] ,
116
+ depth : number ,
117
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
118
+ tracer : { maxX : number } ,
119
+ ) : void => {
120
+ if ( numChildren === 0 ) {
121
+ tree . meta . pos . x += shift
122
+ tree . meta . m = 0
123
+ } else if ( numChildren === 1 ) {
124
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
125
+ tree . meta . pos . x = tree . children ! [ 0 ] ! . node . meta . pos . x
126
+ tree . meta . m = 0
127
+ } else {
128
+ const c = // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
129
+ ( tree . children ! [ 0 ] ! . node . meta . pos . x +
130
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
131
+ tree . children ! [ numChildren - 1 ] ! . node . meta . pos . x ) *
132
+ 0.5
133
+ tree . meta . pos . x = Math . max ( offsets [ depth ] ?? 0 , c )
134
+ }
135
+ tracer . maxX = Math . max ( tracer . maxX , tree . meta . pos . x )
136
+ offsets [ depth ] = 1 + tree . meta . pos . x
137
+ }
138
+
139
+ const _siblingsEvenSpacing = (
140
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
141
+ tree : DeepWriteable < TreeWithLayout > ,
142
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
143
+ offsets : number [ ] ,
144
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
145
+ tracer : { maxX : number } ,
146
+ depth = 0 ,
147
+ shift = 0 ,
148
+ // eslint-disable-next-line sonarjs/cognitive-complexity
149
+ ) : void => {
150
+ const numChildren = tree . children ?. length ?? 0
151
+ let lastFixedIdx : number | undefined
152
+ let maxSpacing = 1
153
+ for ( const [ idx , child ] of ( tree . children ?? [ ] ) . entries ( ) ) {
154
+ const isFixed = ( child . node . children ?. length ?? 0 ) > 0
155
+ if ( isFixed ) {
156
+ if ( lastFixedIdx !== undefined ) {
157
+ const spacing =
158
+ ( child . node . meta . pos . x -
159
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
160
+ tree . children ! [ lastFixedIdx ] ! . node . meta . pos . x ) /
161
+ ( idx - lastFixedIdx )
162
+ maxSpacing = Math . max ( maxSpacing , spacing )
163
+ }
164
+ lastFixedIdx = idx
165
+ }
166
+ }
167
+
168
+ let accShift = shift
169
+ for ( const [ idx , child ] of ( tree . children ?? [ ] ) . entries ( ) ) {
170
+ if ( idx === 0 ) {
171
+ if ( numChildren > 1 ) {
172
+ accShift = Math . max (
173
+ 0 ,
174
+ shift +
175
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
176
+ tree . children ! [ 1 ] ! . node . meta . pos . x -
177
+ maxSpacing -
178
+ child . node . meta . pos . x ,
179
+ )
180
+ }
181
+ } else {
182
+ accShift =
183
+ shift +
184
+ Math . max (
185
+ 0 ,
186
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
187
+ tree . children ! [ idx - 1 ] ! . node . meta . pos . x +
188
+ maxSpacing -
189
+ child . node . meta . pos . x ,
190
+ )
191
+ }
192
+ _siblingsEvenSpacing ( child . node , offsets , tracer , depth + 1 , accShift )
193
+ }
194
+
195
+ _inPlaceEvenSpacingUpdate ( numChildren , tree , shift , offsets , depth , tracer )
196
+ }
197
+
198
+ const _cousinsEvenSpacing = (
199
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
200
+ tree : DeepWriteable < TreeWithLayout > ,
201
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
202
+ offsets : number [ ] ,
203
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
204
+ tracer : { maxX : number } ,
205
+ depth = 0 ,
206
+ shift = 0 ,
207
+ ) : void => {
208
+ const numChildren = tree . children ?. length ?? 0
209
+
210
+ const nextOffset = offsets [ depth + 1 ]
211
+ let accShift = shift
212
+ if (
213
+ numChildren >= 2 &&
214
+ nextOffset !== undefined &&
215
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
216
+ ( tree . children ! [ 0 ] ! . node . children ?. length ?? 0 ) === 0
217
+ ) {
218
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
219
+ const mid = tree . children ! [ 1 ] ! . node . meta . pos . x - 1
220
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
221
+ accShift = shift + Math . max ( 0 , mid - tree . children ! [ 0 ] ! . node . meta . pos . x )
222
+ }
223
+
224
+ for ( const [ idx , child ] of ( tree . children ?? [ ] ) . entries ( ) ) {
225
+ if ( idx === 0 ) {
226
+ _cousinsEvenSpacing ( child . node , offsets , tracer , depth + 1 , accShift )
227
+ } else {
228
+ _cousinsEvenSpacing ( child . node , offsets , tracer , depth + 1 , shift )
229
+ }
230
+ }
231
+
232
+ _inPlaceEvenSpacingUpdate ( numChildren , tree , shift , offsets , depth , tracer )
233
+ }
234
+
235
+ export const computeCenter3Layout = (
107
236
tree : Readonly < Tree > ,
108
237
) : Readonly < WrappedTreeWithLayout > => {
109
238
const offsets : number [ ] = [ ]
110
- const t = _computeCenter2Layout ( tree , 0 , offsets )
111
-
112
239
const tracer = { maxX : 0 }
240
+
241
+ const t = _computeCenter2Layout ( tree , 0 , offsets , tracer )
113
242
_addMods ( t , 0 , tracer )
114
243
244
+ _cousinsEvenSpacing ( t , [ ] , tracer )
245
+ _siblingsEvenSpacing ( t , [ ] , tracer )
246
+
115
247
return {
116
248
tree : t ,
117
249
maxY : offsets . length - 1 ,
0 commit comments