Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 33 additions & 14 deletions @beautiful-tree/react/src/BeautifulTree.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import {
computeAxesCoefAndNodeDimension,
coordinateCreators,
} from './treePosition'
import {
computeSmartLayout,
edgesIterator,
postOrderIterator,
} from '@beautiful-tree/algorithms'
import { Fragment } from 'react'
import type { Orientation } from './treePosition'
import type { Tree } from '@beautiful-tree/types'
import type { WrappedTreeWithLayout } from '@beautiful-tree/algorithms'
export {
Expand Down Expand Up @@ -33,6 +38,7 @@ export interface BeautifulTreeProps {
readonly nodeShape?: 'circle' | 'rect'
readonly hCoef?: number
readonly tree: Tree
readonly orientation?: Orientation
readonly computeLayout?:
| ((tree: Readonly<Tree>) => Readonly<WrappedTreeWithLayout>)
| undefined
Expand Down Expand Up @@ -63,6 +69,7 @@ export function BeautifulTree({
nodeShape,
hCoef = 1,
tree,
orientation = 'T-D',
computeLayout,
getNodeClass,
getNodeShape,
Expand All @@ -74,14 +81,32 @@ export function BeautifulTree({
const { tree: treeWithLayout, mX, mY } = computeLayout(tree)
const { width, height, sizeUnit = 'px' } = svgProps

const xCoef = width / (mX + 2)
const yCoef = height / (mY + 2)
const maxNodeWidth = xCoef * 0.5
const maxNodeHeight = Math.min(yCoef * 0.5, maxNodeWidth * hCoef)
const { xCoef, yCoef, maxNodeHeight, maxNodeWidth } =
computeAxesCoefAndNodeDimension(orientation, {
width,
height,
hCoef,
mX,
mY,
})

const widthCenterShift = maxNodeWidth * 0.5
const heightCenterShift = maxNodeHeight * 0.5
const maxNodeRadius = maxNodeHeight * 0.5

const {
circleCoordinateCreator,
lineCoordinateCreator,
rectCoordinateCreator,
} = coordinateCreators(orientation, {
width,
height,
xCoef,
yCoef,
heightCenterShift,
widthCenterShift,
})

return (
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -108,10 +133,7 @@ export function BeautifulTree({
getEdgeClass,
edge.eData,
)}`}
x1={(edge.start.x + 1) * xCoef}
y1={(edge.start.y + 1) * yCoef}
x2={(edge.end.x + 1) * xCoef}
y2={(edge.end.y + 1) * yCoef}
{...lineCoordinateCreator(edge)}
/>
)
})}
Expand All @@ -134,25 +156,22 @@ export function BeautifulTree({
getNodeClass,
node.data,
)}`}
x={(nm.pos.x + 1) * xCoef - widthCenterShift}
y={(nm.pos.y + 1) * yCoef - heightCenterShift}
{...rectCoordinateCreator(nm)}
width={maxNodeWidth}
height={maxNodeHeight}
/>
) : (
<circle
key={`${id}-node-c-${idx}`}
className={`beautiful-tree-node${_nodeClass}`}
cx={(nm.pos.x + 1) * xCoef}
cy={(nm.pos.y + 1) * yCoef}
{...circleCoordinateCreator(nm)}
r={maxNodeRadius}
/>
)}
{getNodeContent ? (
<foreignObject
key={`${id}-node-fo-${idx}`}
x={(nm.pos.x + 1) * xCoef - widthCenterShift}
y={(nm.pos.y + 1) * yCoef - heightCenterShift}
{...rectCoordinateCreator(nm)}
width={maxNodeWidth}
height={maxNodeHeight}
>
Expand Down
97 changes: 97 additions & 0 deletions @beautiful-tree/react/src/stories/BeautifulTree.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,100 @@ export const Centered3_Wide_Tree_Random: Story = {
getEdgeClass: getCssFromEdgeData,
},
}

export const Normal_Orientation_Small_Tree: Story = {
args: {
id: 'normal_orientation_small_tree',
svgProps: {
width: 400,
height: 400,
},
tree: smallTree,
orientation: 'T-D',
getNodeContent: (data) => data?.['v']?.toString() ?? '',
},
}

export const LR_Orientation_Small_Tree: Story = {
args: {
id: 'lr_orientation_small_tree',
svgProps: {
width: 400,
height: 400,
},
tree: smallTree,
orientation: 'L-R',
getNodeContent: (data) => data?.['v']?.toString() ?? '',
},
}

export const RL_Orientation_Small_Tree: Story = {
args: {
id: 'rl_orientation_small_tree',
svgProps: {
width: 400,
height: 400,
},
tree: smallTree,
orientation: 'R-L',
computeLayout: computeSmartLayout,
getNodeContent: (data) => data?.['v']?.toString() ?? '',
},
}

export const DT_Orientation_Small_Tree: Story = {
args: {
id: 'dt_orientation_small_tree',
svgProps: {
width: 400,
height: 400,
},
tree: smallTree,
orientation: 'D-T',
computeLayout: computeSmartLayout,
getNodeContent: (data) => data?.['v']?.toString() ?? '',
},
}

export const LR_Orientation_Wide_Tree_A_On_Rectangle: Story = {
args: {
id: 'lr_orientation_wide_tree_a_on_rectangle',
svgProps: {
width: 250,
height: 450,
},
tree: wideTree_A,
orientation: 'L-R',
computeLayout: computeSmartLayout,
getNodeClass: getCssFromNodeData,
getEdgeClass: getCssFromEdgeData,
},
}

export const RL_Orientation_Wide_Tree_Bm_On_Rectangle: Story = {
args: {
id: 'rl_orientation_wide_tree_bm_on_rectangle',
svgProps: {
width: 250,
height: 450,
},
tree: smallTree,
orientation: 'R-L',
computeLayout: computeSmartLayout,
getNodeContent: (data) => data?.['v']?.toString() ?? '',
},
}

export const DT_Orientation_Wide_Tree_D_On_Rectangle: Story = {
args: {
id: 'dt_orientation_wide_tree_d_on_rectangle',
svgProps: {
width: 250,
height: 450,
},
tree: smallTree,
orientation: 'D-T',
computeLayout: computeSmartLayout,
getNodeContent: (data) => data?.['v']?.toString() ?? '',
},
}
71 changes: 71 additions & 0 deletions @beautiful-tree/react/src/tests/BeautifulTree.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,75 @@ describe('BeautifulTree : Smart Layout', () => {

expect(rendered).toMatchSnapshot()
})

it('renders small tree, with T-D orientation', () => {
const rendered = render(
<BeautifulTree
id="smart-small-tree_T-D-orientation"
svgProps={{
width: 400,
height: 400,
}}
tree={smallTree}
orientation="T-D"
computeLayout={computeSmartLayout}
/>,
)

expect(rendered).toMatchSnapshot()
})

it('renders small tree, with L-R orientation', () => {
const rendered = render(
<BeautifulTree
id="smart-small-tree_L-R-orientation"
svgProps={{
width: 400,
height: 400,
}}
tree={smallTree}
orientation="L-R"
computeLayout={computeSmartLayout}
getNodeContent={(data): string => data?.['v']?.toString() ?? ''}
/>,
)

expect(rendered).toMatchSnapshot()
})

it('renders small tree, with R-L orientation', () => {
const rendered = render(
<BeautifulTree
id="smart-small-tree_R-L-orientation"
svgProps={{
width: 400,
height: 400,
}}
tree={smallTree}
orientation="R-L"
computeLayout={computeSmartLayout}
getNodeContent={(data): string => data?.['v']?.toString() ?? ''}
/>,
)

expect(rendered).toMatchSnapshot()
})

it('renders small tree, with D-T orientation', () => {
const rendered = render(
<BeautifulTree
id="smart-small-tree_D-T-orientation"
svgProps={{
width: 400,
height: 400,
}}
tree={smallTree}
orientation="D-T"
computeLayout={computeSmartLayout}
getNodeContent={(data): string => data?.['v']?.toString() ?? ''}
/>,
)

expect(rendered).toMatchSnapshot()
})
})
Loading