Skip to content

Commit 2687851

Browse files
authored
feat: nodes drawing for naive layout (#10)
2 parents 593f264 + 8b1ccc7 commit 2687851

File tree

11 files changed

+315
-82
lines changed

11 files changed

+315
-82
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ jobs:
4141
- name: Build Library
4242
run: pnpm build
4343
- name: Run Tests
44-
run: pnpm test
44+
run: pnpm test:coverage

.hooks/pre-push

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ set -o pipefail
55

66
pnpm run lint
77
pnpm publint
8-
pnpm test
8+
pnpm test:coverage

src/BeautifulTree.tsx

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import type { Tree } from './core'
1+
import type { Tree } from './types'
2+
import { computeLeftShiftLayout } from './layouts'
3+
import { postOrderIterator } from './traversal'
24

35
export interface BeautifulTreeProps {
46
readonly id: string
@@ -12,12 +14,45 @@ export interface BeautifulTreeProps {
1214
export function BeautifulTree(
1315
props: Readonly<BeautifulTreeProps>,
1416
): JSX.Element {
17+
const treeWithLayout = computeLeftShiftLayout(props.tree)
18+
const orderedNodes = [...postOrderIterator(treeWithLayout)]
19+
20+
let maxX = 0
21+
let maxY = 0
22+
for (const node of orderedNodes) {
23+
if (node.meta.abstractPosition.x > maxX) {
24+
maxX = node.meta.abstractPosition.x
25+
}
26+
if (node.meta.abstractPosition.y > maxY) {
27+
maxY = node.meta.abstractPosition.y
28+
}
29+
}
30+
1531
return (
1632
<svg
1733
xmlns="http://www.w3.org/2000/svg"
1834
id={props.id}
1935
viewBox={`0 0 ${props.svgProps.width} ${props.svgProps.height}`}
36+
style={{
37+
width: `${props.svgProps.width}px`,
38+
height: `${props.svgProps.height}px`,
39+
}}
2040
className={'beautiful-tree-react'}
21-
></svg>
41+
>
42+
{orderedNodes.map((node, idx) => {
43+
const aX = node.meta.abstractPosition.x
44+
const aY = node.meta.abstractPosition.y
45+
return (
46+
<circle
47+
key={`${props.id}-node-${idx}`}
48+
cx={((aX + 1) * props.svgProps.width) / (maxX + 2)}
49+
cy={((aY + 1) * props.svgProps.height) / (maxY + 2)}
50+
stroke="blue"
51+
fill="purple"
52+
r="5"
53+
/>
54+
)
55+
})}
56+
</svg>
2257
)
2358
}

src/core.ts

Lines changed: 0 additions & 52 deletions
This file was deleted.

src/layouts.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { Tree, TreeChild, TreeWithLayout } from './types'
2+
3+
const _computeLeftShiftLayout = (
4+
tree: Tree,
5+
depth = 0,
6+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
7+
counters?: number[][],
8+
): TreeWithLayout => {
9+
counters ??= []
10+
11+
if (counters[depth] === undefined) {
12+
counters[depth] = []
13+
}
14+
const x = (counters[depth]?.at(-1) ?? -1) + 1
15+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16+
counters[depth]!.push(x)
17+
18+
return {
19+
data: tree.data,
20+
children: tree.children?.map((child: Readonly<TreeChild>) => ({
21+
edgeData: child.edgeData,
22+
node: _computeLeftShiftLayout(child.node, depth + 1, counters),
23+
})),
24+
meta: {
25+
isRoot: depth === 0,
26+
isLeaf: tree.children === undefined || tree.children.length === 0,
27+
abstractPosition: { x, y: depth },
28+
},
29+
} satisfies TreeWithLayout
30+
}
31+
32+
export const computeLeftShiftLayout: (tree: Tree) => TreeWithLayout =
33+
_computeLeftShiftLayout

src/stories/BeautifulTree.stories.ts

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,47 @@ export default meta
1818

1919
type Story = StoryObj<typeof meta>
2020

21-
export const Empty: Story = {
21+
const testTree = {
22+
data: { v: 42 },
23+
children: [
24+
{
25+
edgeData: {},
26+
node: {
27+
data: { v: 43 },
28+
children: [
29+
{
30+
edgeData: {},
31+
node: { data: { v: 45 } },
32+
},
33+
],
34+
},
35+
},
36+
{
37+
edgeData: {},
38+
node: {
39+
data: { v: 44 },
40+
children: [
41+
{
42+
edgeData: {},
43+
node: { data: { v: 46 } },
44+
},
45+
{
46+
edgeData: {},
47+
node: { data: { v: 47 } },
48+
},
49+
],
50+
},
51+
},
52+
],
53+
}
54+
55+
export const SimpleTree: Story = {
2256
args: {
23-
id: 'empty-beautiful-tree',
57+
id: 'simple-beautiful-tree',
2458
svgProps: {
2559
width: 100,
2660
height: 100,
2761
},
28-
tree: {
29-
data: {},
30-
children: [],
31-
},
62+
tree: testTree,
3263
},
3364
}

0 commit comments

Comments
 (0)