Skip to content

Commit efe811b

Browse files
committed
feat: support layout settings
1 parent c537055 commit efe811b

File tree

6 files changed

+221
-32
lines changed

6 files changed

+221
-32
lines changed

packages/studio-explore/src/app.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
LayoutSwitch,
2929
ZoomStatus,
3030
registerIcons,
31+
LayoutSetting,
3132
} from '@graphscope/studio-graph';
3233

3334
import { ToogleLeftButton, ToogleRightButton } from './components/ToggleButton';
@@ -52,6 +53,8 @@ import {
5253
CodeOutlined,
5354
CodeTwoTone,
5455
TabletOutlined,
56+
BranchesOutlined,
57+
CopyrightOutlined,
5558
} from '@ant-design/icons';
5659
import { Divider, Flex, theme, Segmented, Tabs, Typography } from 'antd';
5760
import { getDefaultServices } from './services';
@@ -138,21 +141,28 @@ const Explore: React.FunctionComponent<ExploreProps> = props => {
138141
},
139142
{
140143
label: <Typography.Title level={3}>Cluster Analysis</Typography.Title>,
141-
icon: <GroupOutlined />,
144+
icon: <CopyrightOutlined />,
142145
children: <ClusterAnalysis />,
143146
key: 'ClusterAnalysis',
144147
},
148+
149+
{
150+
label: <Typography.Title level={3}>Cypher Query</Typography.Title>,
151+
icon: <CodeOutlined />,
152+
children: <CypherQuery />,
153+
key: 'CypherQuery',
154+
},
145155
{
146156
label: <Typography.Title level={3}>Style Setting</Typography.Title>,
147157
icon: <BgColorsOutlined />,
148158
children: <StyleSetting />,
149159
key: 'StyleSetting',
150160
},
151161
{
152-
label: <Typography.Title level={3}>Cypher Query</Typography.Title>,
153-
icon: <CodeOutlined />,
154-
children: <CypherQuery />,
155-
key: 'CypherQuery',
162+
label: <Typography.Title level={3}>Layout Setting</Typography.Title>,
163+
icon: <BranchesOutlined />,
164+
children: <LayoutSetting />,
165+
key: 'LayoutSetting',
156166
},
157167
]}
158168
tools={
@@ -163,10 +173,8 @@ const Explore: React.FunctionComponent<ExploreProps> = props => {
163173
<ZoomFit />
164174
<Brush />
165175
<FixedMode />
166-
<Divider style={{ margin: '0px' }} />
167-
<CurvatureLinks />
168-
<DagreMode />
169-
<LayoutSwitch />
176+
{/* <Divider style={{ margin: '0px' }} />
177+
<CurvatureLinks /> */}
170178
<Divider style={{ margin: '0px' }} />
171179
<SwitchEngine />
172180
<RunCluster />

packages/studio-explore/src/components/CypherQuery/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ const CypherQuery: React.FunctionComponent<IStatementQueryProps> = props => {
2222
return (
2323
<Flex vertical gap={12}>
2424
<Typography.Text italic>You can write Cypher queries here to retrieve data.</Typography.Text>
25-
<Input.TextArea rows={10} ref={inputRef} defaultValue={`Match (n) return n limit 100`}></Input.TextArea>
25+
<Input.TextArea
26+
rows={10}
27+
ref={inputRef}
28+
defaultValue={`Match (a)-[r]-(b) return a,r,b limit 100`}
29+
></Input.TextArea>
2630
<Space>
2731
<Button icon={<PlayCircleOutlined />} block onClick={handleQuery}>
2832
Query

packages/studio-explore/src/components/TableView/index.tsx

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import React, { useEffect, useState } from 'react';
2-
import { Table, TableProps } from 'antd';
2+
import { Table, TableProps, Flex, Typography, Button, Popover, Select } from 'antd';
33
import { useContext } from '@graphscope/studio-graph';
44
import { getTable } from './getTableData';
5+
import { ControlOutlined } from '@ant-design/icons';
6+
import { Utils } from '@graphscope/studio-components';
57
interface ITableViewProps {}
68

79
const TableView: React.FunctionComponent<ITableViewProps> = props => {
@@ -11,6 +13,10 @@ const TableView: React.FunctionComponent<ITableViewProps> = props => {
1113
const selectKeys = selectNodes.map(item => item.id);
1214
const keys = selectKeys.join('__');
1315
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>(selectKeys);
16+
const [state, setState] = useState({
17+
columnIds: (Utils.storage.get('explore_table_view_column_ids') as string[]) || columns.map(item => item.key),
18+
});
19+
const { columnIds } = state;
1420

1521
useEffect(() => {
1622
const ids = keys.split('__');
@@ -37,13 +43,56 @@ const TableView: React.FunctionComponent<ITableViewProps> = props => {
3743
onChange: onSelectChange,
3844
};
3945

46+
const content = <div>ddd</div>;
47+
const handleChangeColumns = value => {
48+
console.log('value', value);
49+
setState(preState => {
50+
return {
51+
...preState,
52+
columnIds: value,
53+
};
54+
});
55+
Utils.storage.set('explore_table_view_column_ids', value);
56+
};
57+
const options = columns.map(item => {
58+
return {
59+
label: item.key,
60+
value: item.key,
61+
};
62+
});
63+
const tableColumns = columnIds.map(key => {
64+
return {
65+
title: key,
66+
dataIndex: key,
67+
key: key,
68+
sorter: (a, b) => a[key] - b[key],
69+
};
70+
});
71+
4072
return (
41-
<div>
73+
<Flex vertical gap={12}>
74+
<Flex justify="space-between" align="center">
75+
<Typography.Text type="secondary">{data.nodes.length + data.edges.length} records</Typography.Text>
76+
<Select
77+
suffixIcon={<ControlOutlined />}
78+
maxTagCount="responsive"
79+
mode="multiple"
80+
allowClear
81+
style={{ width: '160px' }}
82+
placeholder="Adjust Columns"
83+
value={columnIds}
84+
onChange={handleChangeColumns}
85+
options={options}
86+
/>
87+
{/* <Popover placement="bottomRight" title={'x'} content={content} trigger="click">
88+
<Button icon={<SettingOutlined />} type="text"></Button>
89+
</Popover> */}
90+
</Flex>
4291
<Table
4392
rowSelection={rowSelection}
4493
size="large"
4594
dataSource={dataSource}
46-
columns={columns}
95+
columns={tableColumns}
4796
bordered
4897
// scroll={{ x: 'max-content' }}
4998
pagination={{
@@ -53,7 +102,7 @@ const TableView: React.FunctionComponent<ITableViewProps> = props => {
53102
}}
54103
// scroll={{ x: 10000, y: 800 }}
55104
/>
56-
</div>
105+
</Flex>
57106
);
58107
};
59108

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { Slider, Button, Typography, Flex, Select, Input, InputNumber } from 'antd';
3+
import { useContext } from '../../';
4+
5+
interface ILayoutParamsProps {}
6+
7+
const LayoutParams: React.FunctionComponent<ILayoutParamsProps> = props => {
8+
const { store, updateStore } = useContext();
9+
const { graph, data, layout } = store;
10+
const { type, options } = layout;
11+
const handleChange = (key, value) => {
12+
updateStore(draft => {
13+
if (draft.layout.options[key] !== value) {
14+
draft.layout.options = { ...draft.layout.options, [key]: value };
15+
}
16+
});
17+
};
18+
if (type === 'force') {
19+
const { linkDistance = 35, centerStrength = 1 } = options;
20+
return (
21+
<Flex vertical gap={12}>
22+
<Typography.Text strong>Link distance</Typography.Text>
23+
<Input
24+
defaultValue={linkDistance}
25+
onBlur={e => {
26+
console.log(e.target.value);
27+
handleChange('linkDistance', e.target.value);
28+
}}
29+
></Input>
30+
<Typography.Text strong>Center Strength</Typography.Text>
31+
<InputNumber
32+
style={{ width: '100%' }}
33+
min={0}
34+
max={1}
35+
defaultValue={centerStrength}
36+
onBlur={e => {
37+
console.log(e.target.value);
38+
handleChange('centerStrength', e.target.value);
39+
}}
40+
></InputNumber>
41+
</Flex>
42+
);
43+
}
44+
if (type === 'force-dagre') {
45+
const { direction = 'lr' } = options;
46+
return (
47+
<Flex vertical gap={12}>
48+
<Typography.Text strong>Direction</Typography.Text>
49+
<Select
50+
options={[
51+
{
52+
label: 'top-down',
53+
value: 'td',
54+
},
55+
{
56+
label: 'left-right',
57+
value: 'lr',
58+
},
59+
{
60+
label: 'bottom-up',
61+
value: 'bu',
62+
},
63+
{
64+
label: 'right-left',
65+
value: 'rl',
66+
},
67+
{
68+
lable: 'inwards-radially',
69+
value: 'radialin',
70+
},
71+
{
72+
label: 'outwards-radially',
73+
value: 'radialout',
74+
},
75+
]}
76+
value={direction}
77+
onChange={value => {
78+
handleChange('direction', value);
79+
}}
80+
></Select>
81+
</Flex>
82+
);
83+
}
84+
85+
return <div></div>;
86+
};
87+
88+
export default LayoutParams;

packages/studio-graph/src/components/LayoutSetting/index.tsx

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,47 @@
11
import React, { useEffect, useState } from 'react';
2-
import { Slider, Button, Typography } from 'antd';
2+
import { Slider, Button, Typography, Flex, Select } from 'antd';
33
import { useContext } from '../../';
44
import * as d3 from 'd3-force-3d';
55
import { Utils } from '@graphscope/studio-components';
6-
6+
import LayoutParams from './Params';
77
interface ILayoutSettingProps {}
88

9+
const layouts = [
10+
{
11+
type: 'force',
12+
options: {},
13+
},
14+
{
15+
type: 'force-combo',
16+
options: {},
17+
},
18+
{
19+
type: 'force-dagre',
20+
options: {},
21+
},
22+
{
23+
type: 'dagre',
24+
options: {},
25+
},
26+
{
27+
type: 'circle-pack',
28+
options: {},
29+
},
30+
{
31+
type: 'preset',
32+
options: {},
33+
},
34+
];
35+
const layoutOptions = layouts.map(item => {
36+
return {
37+
label: item.type,
38+
value: item.type,
39+
};
40+
});
941
const LayoutSetting: React.FunctionComponent<ILayoutSettingProps> = props => {
10-
const { store } = useContext();
11-
const { graph, data } = store;
12-
const [state, setState] = useState({
13-
linkStrength: 1,
14-
linkDistance: 100,
15-
});
16-
17-
const { linkStrength } = state;
42+
const { store, updateStore } = useContext();
43+
const { graph, data, layout } = store;
44+
const { type, options } = layout;
1845

1946
const onChangeForcelink = strength => {
2047
if (graph) {
@@ -47,13 +74,26 @@ const LayoutSetting: React.FunctionComponent<ILayoutSettingProps> = props => {
4774
graph.d3ReheatSimulation();
4875
}
4976
};
77+
const onChangeType = value => {
78+
updateStore(draft => {
79+
draft.layout = {
80+
type: value,
81+
options: {},
82+
};
83+
});
84+
};
5085

5186
return (
52-
<div>
53-
<Typography.Text>Force Link</Typography.Text>
54-
<Slider defaultValue={0.5} max={1} min={0} step={0.01} onChangeComplete={onChangeForcelink} />
55-
<Button onClick={onReset}>reset</Button>
56-
</div>
87+
<Flex vertical gap={12}>
88+
<Typography.Text type="secondary" italic>
89+
you can fine-tune the layout parameters here to optimize the graph display.
90+
</Typography.Text>
91+
92+
<Typography.Text strong>Layout Algorithm</Typography.Text>
93+
<Select options={layoutOptions} value={type} onChange={onChangeType} />
94+
95+
<LayoutParams />
96+
</Flex>
5797
);
5898
};
5999

packages/studio-graph/src/graph/hooks/useDataAndLayout.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ export const useDataAndLayout = () => {
6161
graph.cooldownTime(renderTime);
6262
if (type === 'force') {
6363
(graph as ForceGraphInstance)
64-
.d3Force('center', d3ForceCenter().strength(1))
64+
.d3Force('center', d3ForceCenter().strength(options.centerStrength || 1))
6565
.d3Force('charge', d3ForceManyBody())
66-
.d3Force('link', d3ForceLink().distance(35))
66+
.d3Force('link', d3ForceLink().distance(options.linkDistance || 35))
6767
.d3Force(
6868
'collide',
6969
d3ForceCollide().radius(node => {
@@ -76,7 +76,7 @@ export const useDataAndLayout = () => {
7676
graph.d3ReheatSimulation();
7777
}
7878
if (type === 'force-dagre') {
79-
graph.dagMode('lr');
79+
graph.dagMode(options.direction || 'lr');
8080
graph.graphData({ nodes, links });
8181
}
8282
if (type === 'force-combo') {

0 commit comments

Comments
 (0)