@@ -32,7 +32,7 @@ your nodes; the library computes optimal (x, y) coordinates for every node in th
3232``` kotlin
3333// build.gradle.kts
3434dependencies {
35- implementation(" io.github.linde9821:treelayout-kmp:0.2.1 " )
35+ implementation(" io.github.linde9821:treelayout-kmp:0.3.0 " )
3636}
3737```
3838
@@ -158,6 +158,83 @@ val result = WalkerTreeLayout(adapter, config).layout()
158158
159159Available orientations: ` TopToBottom ` , ` BottomToTop ` , ` LeftToRight ` , ` RightToLeft ` .
160160
161+ ## Radial Layouts
162+
163+ In addition to the linear Walker layout, the library includes two ** radial layout algorithms** that arrange nodes in
164+ concentric circles around the root. These are useful when you want a compact, center-outward visualization — common for
165+ org charts, file explorers, and dependency graphs.
166+
167+ ### Radial Walker Layout
168+
169+ ** Package:** ` io.github.linde9821.treelayout.radial.walker `
170+
171+ This algorithm runs the Walker algorithm internally to determine sibling ordering and spacing, then maps the across-axis
172+ (horizontal positions) to angular positions on concentric rings. Each depth level becomes a ring at radius
173+ ` depth × layerDistance ` .
174+
175+ ``` kotlin
176+ import io.github.linde9821.treelayout.radial.walker.RadialWalkerTreeLayout
177+ import io.github.linde9821.treelayout.radial.walker.RadialWalkerLayoutConfiguration
178+
179+ val config = RadialWalkerLayoutConfiguration (
180+ layerDistance = 80f ,
181+ margin = 0.5f , // radians subtracted from full circle to create a gap
182+ rotation = 0.0f , // angular offset in radians
183+ )
184+
185+ val result = RadialWalkerTreeLayout (
186+ adapter = OrgTreeAdapter (ceo),
187+ configuration = config,
188+ ).layout()
189+
190+ result.getPositions().forEach { (node, point) ->
191+ println (" ${node.name} -> (${point.x} , ${point.y} )" )
192+ }
193+ ```
194+
195+ The constructor accepts an optional ` nodeExtentProvider ` parameter, which is forwarded to the internal Walker pass for
196+ variable-width node spacing:
197+
198+ ``` kotlin
199+ val result = RadialWalkerTreeLayout (
200+ adapter = OrgTreeAdapter (ceo),
201+ configuration = config,
202+ nodeExtentProvider = OrgExtentProvider (),
203+ ).layout()
204+ ```
205+
206+ ### Direct Angular Placement Layout
207+
208+ ** Package:** ` io.github.linde9821.treelayout.radial.angular `
209+
210+ This algorithm recursively partitions angular space among children proportional to their ** subtree weight** (total number
211+ of descendants including the child itself). It runs in ** O(n)** — one pass to compute weights, one pass to assign
212+ positions. This produces evenly distributed layouts where larger subtrees receive proportionally more angular space.
213+
214+ ``` kotlin
215+ import io.github.linde9821.treelayout.radial.angular.DirectAngularPlacementLayout
216+ import io.github.linde9821.treelayout.radial.angular.DirectAngularPlacementConfiguration
217+
218+ val config = DirectAngularPlacementConfiguration (
219+ layerDistance = 80f ,
220+ rotation = 0.0f , // angular offset in radians
221+ )
222+
223+ val result = DirectAngularPlacementLayout (
224+ adapter = OrgTreeAdapter (ceo),
225+ configuration = config,
226+ ).layout()
227+
228+ result.getPositions().forEach { (node, point) ->
229+ println (" ${node.name} -> (${point.x} , ${point.y} )" )
230+ }
231+ ```
232+
233+ > ** When to choose which?**
234+ > Use ** Radial Walker** when you want the Walker algorithm's aesthetic guarantees (symmetry, minimal width) projected
235+ > onto a circle. Use ** Direct Angular Placement** when you want a simpler, weight-proportional distribution with no
236+ > dependency on the Walker pass.
237+
161238## API Reference
162239
163240### ` TreeAdapter<T> `
@@ -202,6 +279,38 @@ Available orientations: `TopToBottom`, `BottomToTop`, `LeftToRight`, `RightToLef
202279Constructor accepts an optional ` nodeExtentProvider ` parameter. When omitted, nodes are treated as dimensionless points
203280(backward compatible).
204281
282+ ### ` RadialWalkerLayoutConfiguration `
283+
284+ | Property | Type | Default | Description |
285+ | -----------------| ---------| ---------| ----------------------------------------------------------------|
286+ | ` layerDistance ` | ` Float ` | ` 1.0f ` | Radial distance between concentric depth rings. |
287+ | ` margin ` | ` Float ` | ` 0.0f ` | Angular margin (in radians) subtracted from the full circle. |
288+ | ` rotation ` | ` Float ` | ` 0.0f ` | Angular offset (in radians) applied to all node positions. |
289+
290+ ### ` RadialWalkerTreeLayout<T> `
291+
292+ | Method | Description |
293+ | ---------------------------------| ------------------------------------------------------|
294+ | ` layout(): TreeLayoutResult<T> ` | Executes the algorithm and returns positioned nodes. |
295+
296+ Constructor parameters: ` adapter: TreeAdapter<T> ` , ` configuration: RadialWalkerLayoutConfiguration ` ,
297+ ` nodeExtentProvider: NodeExtentProvider<T> ` (optional, defaults to dimensionless points).
298+
299+ ### ` DirectAngularPlacementConfiguration `
300+
301+ | Property | Type | Default | Description |
302+ | -----------------| ---------| ---------| -------------------------------------------------------------|
303+ | ` layerDistance ` | ` Float ` | ` 1.0f ` | Radial distance between concentric depth rings. |
304+ | ` rotation ` | ` Float ` | ` 0.0f ` | Angular offset (in radians) applied to all node positions. |
305+
306+ ### ` DirectAngularPlacementLayout<T> `
307+
308+ | Method | Description |
309+ | ---------------------------------| ------------------------------------------------------|
310+ | ` layout(): TreeLayoutResult<T> ` | Executes the algorithm and returns positioned nodes. |
311+
312+ Constructor parameters: ` adapter: TreeAdapter<T> ` , ` configuration: DirectAngularPlacementConfiguration ` .
313+
205314### ` TreeLayoutResult<T> `
206315
207316| Method | Description |
@@ -242,7 +351,9 @@ Run the benchmark yourself:
242351## Running the Samples
243352
244353The ` sample/ ` module is a Compose Multiplatform application that visualizes a ** prefix tree** built from user-provided
245- words. It demonstrates variable node sizes, all four orientations, and interactive layout controls.
354+ words. It features a dark-themed UI with a ** layout type selector** (Walker / RadialWalker / DirectAngular) and
355+ context-sensitive controls for each algorithm — orientation for Walker, margin and rotation for radial layouts. It
356+ demonstrates variable node sizes and interactive layout controls.
246357
247358### Desktop (JVM)
248359
0 commit comments