Skip to content

Commit 0ede9fe

Browse files
committed
feat: allow the addition of or overiding of layout options
so layouts can be made to use the none default options and variants can be offered
1 parent b4b9d0b commit 0ede9fe

File tree

22 files changed

+269
-156
lines changed

22 files changed

+269
-156
lines changed

apps/docs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
},
2323
"devDependencies": {
2424
"@committed/config": "*",
25+
"@faker-js/faker": "^7.6.0",
2526
"@storybook/addon-docs": "^6.5.12",
2627
"@storybook/addon-essentials": "^6.5.12",
2728
"@storybook/addons": "^6.5.12",

apps/docs/src/Decoration.stories.tsx

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
NodeDecoration,
66
sizeNodeBy
77
} from '@committed/components-graph'
8+
import { faker } from '@faker-js/faker'
89
import { Meta } from '@storybook/react'
910
import React, { useState } from 'react'
1011
import { exampleGraphData } from './exampleData'
@@ -82,91 +83,97 @@ export const CustomIcons: React.FC = () => {
8283
GraphModel.createWithContent(
8384
new ContentModel(
8485
{
85-
chris: {
86-
id: 'chris',
86+
n1: {
87+
id: 'n1',
8788
attributes: {},
88-
label: 'Chris Flatley',
89-
icon: 'https://committed.io/static/chris-4f65af02b0d026c76bfbac1aa90461c3.jpg',
89+
label: faker.name.fullName(),
90+
icon: 'https://i.pravatar.cc/100',
9091
size: 100,
9192
},
92-
stuart: {
93-
id: 'stuart',
93+
n2: {
94+
id: 'n2',
9495
attributes: {},
95-
label: 'Stuart Hendren',
96-
icon: 'https://committed.io/static/stuart-c12a4df0a720f9252abb8279ffa9f7c8.png',
96+
label: faker.name.fullName(),
97+
icon: 'https://i.pravatar.cc/100',
9798
size: 100,
9899
},
99-
jon: {
100-
id: 'jon',
100+
n3: {
101+
id: 'n3',
101102
attributes: {},
102-
label: 'Jon Elliot',
103-
icon: 'https://committed.io/static/jon-4f56f1e3f4369e4d115d3a88195a2f4a.png',
103+
label: faker.name.fullName(),
104104
size: 100,
105105
},
106-
steve: {
107-
id: 'steve',
106+
n4: {
107+
id: 'n4',
108108
attributes: {},
109-
label: 'Steven Taylor',
110-
icon: 'https://committed.io/static/steve-282e9f5032489e7a4274ee5eec6fd206.jpg',
109+
label: faker.name.fullName(),
110+
icon: 'https://i.pravatar.cc/100',
111111
size: 100,
112112
},
113-
matt: {
114-
id: 'matt',
113+
n5: {
114+
id: 'n5',
115115
attributes: {},
116-
label: 'Matt Copas',
117-
icon: 'https://committed.io/static/matt-e622c816a3d4f6c831346da257ed6500.jpg',
116+
label: faker.name.fullName(),
117+
icon: 'https://i.pravatar.cc/100',
118118
size: 100,
119119
},
120-
kristian: {
121-
id: 'kristian',
120+
n6: {
121+
id: 'n6',
122122
attributes: {},
123-
label: 'Kristian Aspinall',
124-
icon: 'https://committed.io/static/kristian-d0ae8e222bf08ea15acba90d5a41b2aa.jpg',
123+
label: faker.name.fullName(),
124+
icon: 'https://i.pravatar.cc/100',
125125
size: 100,
126126
},
127127
},
128128
{
129129
e1: {
130130
id: 'e1',
131+
label: '',
131132
attributes: {},
132-
source: 'chris',
133-
target: 'stuart',
133+
source: 'n1',
134+
target: 'n2',
134135
},
135136
e2: {
136137
id: 'e2',
138+
label: '',
137139
attributes: {},
138-
source: 'stuart',
139-
target: 'jon',
140+
source: 'n2',
141+
target: 'n3',
140142
},
141143
e3: {
142144
id: 'e3',
145+
label: '',
143146
attributes: {},
144-
source: 'kristian',
145-
target: 'steve',
147+
source: 'n6',
148+
target: 'n4',
146149
},
147150
e4: {
148151
id: 'e4',
152+
label: '',
149153
attributes: {},
150-
source: 'matt',
151-
target: 'kristian',
154+
source: 'n5',
155+
target: 'n6',
152156
},
153157
e5: {
154158
id: 'e5',
159+
label: '',
155160
attributes: {},
156-
source: 'jon',
157-
target: 'matt',
161+
source: 'n3',
162+
target: 'n5',
158163
},
159164
e6: {
160165
id: 'e6',
166+
label: '',
161167
attributes: {},
162-
source: 'jon',
163-
target: 'steve',
168+
source: 'n3',
169+
target: 'n4',
164170
},
165171
e7: {
166172
id: 'e7',
173+
label: '',
167174
attributes: {},
168-
source: 'chris',
169-
target: 'steve',
175+
source: 'n1',
176+
target: 'n4',
170177
},
171178
}
172179
)

apps/docs/src/Layout.stories.tsx

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Graph, GraphModel } from '@committed/components-graph'
1+
import { Graph, GraphModel, GraphToolbar, LayoutOptions, defaultLayouts, ContentModel, Generator } from '@committed/components-graph'
22
import { Meta } from '@storybook/react'
33
import React, { useState } from 'react'
44
import { exampleModel, Template } from './StoryUtil'
@@ -23,7 +23,7 @@ export const CircleLayout: React.FC = () => {
2323
const [model, setModel] = useState(
2424
GraphModel.applyLayout(
2525
exampleModel,
26-
exampleModel.getCurrentLayout().presetLayout('circle')
26+
exampleModel.getCurrentLayout().setLayout('circle')
2727
)
2828
)
2929
return <Template model={model} onModelChange={setModel} />
@@ -33,7 +33,7 @@ export const ColaForceDirectedLayout: React.FC = () => {
3333
const [model, setModel] = useState(
3434
GraphModel.applyLayout(
3535
exampleModel,
36-
exampleModel.getCurrentLayout().presetLayout('cola')
36+
exampleModel.getCurrentLayout().setLayout('cola')
3737
)
3838
)
3939
return <Template model={model} onModelChange={setModel} />
@@ -43,7 +43,7 @@ export const GridLayout: React.FC = () => {
4343
const [model, setModel] = useState(
4444
GraphModel.applyLayout(
4545
exampleModel,
46-
exampleModel.getCurrentLayout().presetLayout('grid')
46+
exampleModel.getCurrentLayout().setLayout('grid')
4747
)
4848
)
4949
return <Template model={model} onModelChange={setModel} />
@@ -53,7 +53,7 @@ export const HierarchicalLayout: React.FC = () => {
5353
const [model, setModel] = useState(
5454
GraphModel.applyLayout(
5555
exampleModel,
56-
exampleModel.getCurrentLayout().presetLayout('hierarchical')
56+
exampleModel.getCurrentLayout().setLayout('hierarchical')
5757
)
5858
)
5959
return <Template model={model} onModelChange={setModel} />
@@ -63,7 +63,7 @@ export const ConcentricLayout: React.FC = () => {
6363
const [model, setModel] = useState(
6464
GraphModel.applyLayout(
6565
exampleModel,
66-
exampleModel.getCurrentLayout().presetLayout('concentric')
66+
exampleModel.getCurrentLayout().setLayout('concentric')
6767
)
6868
)
6969
return <Template model={model} onModelChange={setModel} />
@@ -73,7 +73,7 @@ export const BreadthfirstLayout: React.FC = () => {
7373
const [model, setModel] = useState(
7474
GraphModel.applyLayout(
7575
exampleModel,
76-
exampleModel.getCurrentLayout().presetLayout('breadth-first')
76+
exampleModel.getCurrentLayout().setLayout('breadth-first')
7777
)
7878
)
7979
return <Template model={model} onModelChange={setModel} />
@@ -84,7 +84,7 @@ export const CoseLayout: React.FC = () => {
8484
const [model, setModel] = useState(
8585
GraphModel.applyLayout(
8686
exampleModel,
87-
exampleModel.getCurrentLayout().presetLayout('cose')
87+
exampleModel.getCurrentLayout().setLayout('cose')
8888
)
8989
)
9090
return <Template model={model} onModelChange={setModel} />
@@ -94,7 +94,7 @@ export const CustomLayout: React.FC = () => {
9494
const [model, setModel] = useState(
9595
GraphModel.applyLayout(
9696
exampleModel,
97-
exampleModel.getCurrentLayout().customLayout({
97+
exampleModel.getCurrentLayout().setLayout({
9898
name: 'Alphabetical',
9999
runLayout: (m) => {
100100
return m.nodes.reduce<Record<string, cytoscape.Position>>(
@@ -114,3 +114,27 @@ export const CustomLayout: React.FC = () => {
114114
)
115115
return <Template model={model} onModelChange={setModel} />
116116
}
117+
118+
119+
export const OverrideLayout: React.FC = () => {
120+
const [model, setModel] = useState(
121+
GraphModel.applyLayout(
122+
Generator.randomGraph(100, 100),
123+
exampleModel.getCurrentLayout().setLayout('network-simplex')
124+
)
125+
)
126+
const layoutOptions: Record<string, LayoutOptions> = {
127+
'network-simplex': { ...defaultLayouts.hierarchical, ranker: 'network-simplex'} as LayoutOptions,
128+
'inverted': { ...defaultLayouts.hierarchical, ranker: 'network-simplex', transform: (node, position) => {
129+
return {x: position.x, y: -position.y }
130+
}} as LayoutOptions,
131+
'tight-tree': { ...defaultLayouts.hierarchical, ranker: 'tight-tree' }as LayoutOptions,
132+
'longest-path': { ...defaultLayouts.hierarchical, ranker: 'longest-path' }as LayoutOptions,
133+
'radial': { ...defaultLayouts['breadth-first'], circle: true }as LayoutOptions,
134+
135+
}
136+
137+
return <Template model={model} onModelChange={setModel} options={{height: 600, renderOptions: { layoutOptions }}} >
138+
<GraphToolbar direction='row' model={model} onModelChange={setModel} layouts={[ 'network-simplex', 'inverted', 'tight-tree', 'breadth-first', 'concentric', 'radial']}/>
139+
</Template>
140+
}

apps/docs/src/StoryUtil.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { cytoscapeRenderer, Graph, GraphRendererOptions } from '@committed/components-graph'
1+
import { CyGraphRendererOptions, cytoscapeRenderer, Graph } from '@committed/components-graph'
22
import { Generator, GraphModel } from '@committed/graph'
33
import React from 'react'
44

@@ -9,14 +9,16 @@ export const Template: React.FC<{
99
onModelChange: (
1010
model: GraphModel | ((model2: GraphModel) => GraphModel)
1111
) => void
12-
height?: GraphRendererOptions['height']
13-
}> = ({ model, onModelChange, height }) => {
14-
return (
15-
<Graph
16-
model={model}
17-
onModelChange={onModelChange}
18-
renderer={cytoscapeRenderer}
19-
options={{ height: height ?? 600 }}
20-
/>
12+
options?: CyGraphRendererOptions
13+
}> = ({ model, onModelChange, options, children }) => {
14+
return (<>
15+
{children}
16+
<Graph
17+
model={model}
18+
onModelChange={onModelChange}
19+
renderer={cytoscapeRenderer}
20+
options={{ height: 600, ...options }}
21+
/>
22+
</>
2123
)
2224
}

package-lock.json

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/graph/src/graph/LayoutModel.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,29 @@ beforeEach(() => {
1717

1818
it('Gets layout', () => {
1919
const layout: GraphLayout = 'grid'
20-
expect(layoutModel.presetLayout(layout).getLayout()).toBe(layout)
20+
expect(layoutModel.setLayout(layout).getLayout()).toBe(layout)
2121
})
2222

2323
it('Layout algorithm defined when custom layout specified', () => {
24-
expect(layoutModel.customLayout(layoutAlgorithm).getLayout()).toBe(
24+
expect(layoutModel.setLayout(layoutAlgorithm).getLayout()).toBe(
2525
layoutAlgorithm
2626
)
2727
})
2828

2929
it('Changing the layout invalidates the layout', () => {
30-
expect(layoutModel.presetLayout('grid').isDirty()).toBe(true)
30+
expect(layoutModel.setLayout('grid').isDirty()).toBe(true)
3131
})
3232

3333
it('Validating an invalidated layout', () => {
34-
expect(layoutModel.presetLayout('grid').validate().isDirty()).toBe(false)
34+
expect(layoutModel.setLayout('grid').validate().isDirty()).toBe(false)
3535
})
3636

3737
it('Invalidating an validated layout', () => {
38-
const model = layoutModel.presetLayout('grid').validate()
38+
const model = layoutModel.setLayout('grid').validate()
3939
expect(model.invalidate().isDirty()).toBe(true)
4040
})
4141

4242
it('Validating an validated layout does nothing', () => {
43-
const model = layoutModel.presetLayout('grid').validate()
43+
const model = layoutModel.setLayout('grid').validate()
4444
expect(model.validate()).toBe(model)
4545
})

packages/graph/src/graph/LayoutModel.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,21 @@ export class LayoutModel {
3737
}
3838
}
3939

40-
presetLayout(layout: PresetGraphLayout): LayoutModel {
40+
setLayout(layout: GraphLayout): LayoutModel {
4141
return new LayoutModel(layout, true)
4242
}
4343

44+
/**
45+
* @deprecated use setLayout
46+
*/
47+
presetLayout(layout: PresetGraphLayout): LayoutModel {
48+
return this.setLayout(layout)
49+
}
50+
51+
/**
52+
* @deprecated use setLayout
53+
*/
4454
customLayout(layout: CustomGraphLayout): LayoutModel {
45-
return new LayoutModel(layout, true)
55+
return this.setLayout(layout)
4656
}
4757
}

0 commit comments

Comments
 (0)