|
@@ -1,128 +1,127 @@
|
|
-import React from 'react'
|
|
|
|
-import { Graph, Addon, Path, Cell, Model, Node } from '@antv/x6'
|
|
|
|
-import { Drawer } from 'antd'
|
|
|
|
-import AlgoNode from './AlgoNode'
|
|
|
|
-import ToolBar from './ToolBar'
|
|
|
|
-import DatasourceNodeInfo from './DatasourceNodeInfo'
|
|
|
|
-import ScriptNodeInfo from './ScriptNodeInfo'
|
|
|
|
|
|
+import React from 'react';
|
|
|
|
+import { Graph, Addon, Path, Cell, Model, Node } from '@antv/x6';
|
|
|
|
+import { Drawer } from 'antd';
|
|
|
|
+import AlgoNode from './AlgoNode';
|
|
|
|
+import ToolBar from './ToolBar';
|
|
|
|
+import DatasourceNodeInfo from './DatasourceNodeInfo';
|
|
|
|
+import ScriptNodeInfo from './ScriptNodeInfo';
|
|
|
|
+import ContextMenuView from './ContextMenu';
|
|
|
|
|
|
// 侧边栏UI组件
|
|
// 侧边栏UI组件
|
|
-const { Stencil } = Addon
|
|
|
|
|
|
+const { Stencil } = Addon;
|
|
|
|
|
|
// 节点状态接口
|
|
// 节点状态接口
|
|
interface NodeStatus {
|
|
interface NodeStatus {
|
|
- id: string
|
|
|
|
- status: 'default' | 'success' | 'failed' | 'running'
|
|
|
|
- type: 'script' | 'datasource'
|
|
|
|
- label?: string
|
|
|
|
|
|
+ id: string;
|
|
|
|
+ status: 'default' | 'success' | 'failed' | 'running';
|
|
|
|
+ type: 'script' | 'datasource';
|
|
|
|
+ label?: string;
|
|
}
|
|
}
|
|
|
|
|
|
// 数据源节点
|
|
// 数据源节点
|
|
const dataSourceNodes = [
|
|
const dataSourceNodes = [
|
|
{
|
|
{
|
|
- "id": "0",
|
|
|
|
- "shape": "dag-node",
|
|
|
|
- "height": 80,
|
|
|
|
- "width": 180,
|
|
|
|
- "data": {
|
|
|
|
- "label": "DataSource",
|
|
|
|
- "status": "default",
|
|
|
|
- "type": 'datasource'
|
|
|
|
|
|
+ id: '0',
|
|
|
|
+ shape: 'dag-node',
|
|
|
|
+ height: 80,
|
|
|
|
+ width: 180,
|
|
|
|
+ data: {
|
|
|
|
+ label: 'DataSource',
|
|
|
|
+ status: 'default',
|
|
|
|
+ type: 'datasource'
|
|
},
|
|
},
|
|
- "ports": {
|
|
|
|
- "items": [
|
|
|
|
- {"id": 'bottomPort', "group": 'bottom'},
|
|
|
|
- ]
|
|
|
|
|
|
+ ports: {
|
|
|
|
+ items: [{ id: 'bottomPort', group: 'bottom' }]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-]
|
|
|
|
|
|
+];
|
|
|
|
|
|
// 数据处理节点
|
|
// 数据处理节点
|
|
const dataHandleNodes = [
|
|
const dataHandleNodes = [
|
|
{
|
|
{
|
|
- "id": "1",
|
|
|
|
- "shape": "dag-node",
|
|
|
|
- "data": {
|
|
|
|
- "label": "数据处理节点",
|
|
|
|
- "status": "default",
|
|
|
|
- "type": 'script'
|
|
|
|
|
|
+ id: '1',
|
|
|
|
+ shape: 'dag-node',
|
|
|
|
+ data: {
|
|
|
|
+ label: '数据处理节点',
|
|
|
|
+ status: 'default',
|
|
|
|
+ type: 'script'
|
|
},
|
|
},
|
|
- "ports": {
|
|
|
|
- "items": [
|
|
|
|
- {"id": 'topPort', "group": 'top'},
|
|
|
|
- {"id": 'bottomPort', "group": 'bottom'},
|
|
|
|
|
|
+ ports: {
|
|
|
|
+ items: [
|
|
|
|
+ { id: 'topPort', group: 'top' },
|
|
|
|
+ { id: 'bottomPort', group: 'bottom' }
|
|
]
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-]
|
|
|
|
|
|
+];
|
|
|
|
|
|
// 其它节点
|
|
// 其它节点
|
|
const otherScriptNodes = [
|
|
const otherScriptNodes = [
|
|
{
|
|
{
|
|
- "id": "2",
|
|
|
|
- "shape": "dag-node",
|
|
|
|
- "data": {
|
|
|
|
- "label": "其它节点",
|
|
|
|
- "status": "default",
|
|
|
|
- "type": 'script'
|
|
|
|
|
|
+ id: '2',
|
|
|
|
+ shape: 'dag-node',
|
|
|
|
+ data: {
|
|
|
|
+ label: '其它节点',
|
|
|
|
+ status: 'default',
|
|
|
|
+ type: 'script'
|
|
},
|
|
},
|
|
- "ports": {
|
|
|
|
- "items": [
|
|
|
|
- {"id": 'topPort', "group": 'top'},
|
|
|
|
- {"id": 'bottomPort', "group": 'bottom'},
|
|
|
|
|
|
+ ports: {
|
|
|
|
+ items: [
|
|
|
|
+ { id: 'topPort', group: 'top' },
|
|
|
|
+ { id: 'bottomPort', group: 'bottom' }
|
|
]
|
|
]
|
|
}
|
|
}
|
|
- },
|
|
|
|
-]
|
|
|
|
|
|
+ }
|
|
|
|
+];
|
|
|
|
|
|
// 用户自定义脚本节点
|
|
// 用户自定义脚本节点
|
|
const customScriptNodes = [
|
|
const customScriptNodes = [
|
|
{
|
|
{
|
|
- "id": "5",
|
|
|
|
- "shape": "dag-node",
|
|
|
|
- "data": {
|
|
|
|
- "label": "SQL",
|
|
|
|
- "status": "default",
|
|
|
|
- "type": 'script'
|
|
|
|
|
|
+ id: '5',
|
|
|
|
+ shape: 'dag-node',
|
|
|
|
+ data: {
|
|
|
|
+ label: 'SQL',
|
|
|
|
+ status: 'default',
|
|
|
|
+ type: 'script'
|
|
},
|
|
},
|
|
- "ports": {
|
|
|
|
- "items": [
|
|
|
|
- {"id": 'topPort', "group": 'top'},
|
|
|
|
- {"id": 'bottomPort', "group": 'bottom'},
|
|
|
|
|
|
+ ports: {
|
|
|
|
+ items: [
|
|
|
|
+ { id: 'topPort', group: 'top' },
|
|
|
|
+ { id: 'bottomPort', group: 'bottom' }
|
|
]
|
|
]
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- "id": "6",
|
|
|
|
- "shape": "dag-node",
|
|
|
|
- "data": {
|
|
|
|
- "label": "PySpark",
|
|
|
|
- "status": "default",
|
|
|
|
- "type": 'script'
|
|
|
|
|
|
+ id: '6',
|
|
|
|
+ shape: 'dag-node',
|
|
|
|
+ data: {
|
|
|
|
+ label: 'PySpark',
|
|
|
|
+ status: 'default',
|
|
|
|
+ type: 'script'
|
|
},
|
|
},
|
|
- "ports": {
|
|
|
|
- "items": [
|
|
|
|
- {"id": 'topPort', "group": 'top'},
|
|
|
|
- {"id": 'bottomPort', "group": 'bottom'},
|
|
|
|
|
|
+ ports: {
|
|
|
|
+ items: [
|
|
|
|
+ { id: 'topPort', group: 'top' },
|
|
|
|
+ { id: 'bottomPort', group: 'bottom' }
|
|
]
|
|
]
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- "id": "7",
|
|
|
|
- "shape": "dag-node",
|
|
|
|
- "data": {
|
|
|
|
- "label": "Python",
|
|
|
|
- "status": "default",
|
|
|
|
- "type": 'script'
|
|
|
|
|
|
+ id: '7',
|
|
|
|
+ shape: 'dag-node',
|
|
|
|
+ data: {
|
|
|
|
+ label: 'Python',
|
|
|
|
+ status: 'default',
|
|
|
|
+ type: 'script'
|
|
},
|
|
},
|
|
- "ports": {
|
|
|
|
- "items": [
|
|
|
|
- {"id": 'topPort', "group": 'top'},
|
|
|
|
- {"id": 'bottomPort', "group": 'bottom'},
|
|
|
|
|
|
+ ports: {
|
|
|
|
+ items: [
|
|
|
|
+ { id: 'topPort', group: 'top' },
|
|
|
|
+ { id: 'bottomPort', group: 'bottom' }
|
|
]
|
|
]
|
|
}
|
|
}
|
|
- },
|
|
|
|
-]
|
|
|
|
|
|
+ }
|
|
|
|
+];
|
|
|
|
|
|
// 注册算子节点
|
|
// 注册算子节点
|
|
Graph.registerNode(
|
|
Graph.registerNode(
|
|
@@ -142,9 +141,9 @@ Graph.registerNode(
|
|
magnet: true,
|
|
magnet: true,
|
|
stroke: '#C2C8D5',
|
|
stroke: '#C2C8D5',
|
|
strokeWidth: 1,
|
|
strokeWidth: 1,
|
|
- fill: '#fff',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
|
|
+ fill: '#fff'
|
|
|
|
+ }
|
|
|
|
+ }
|
|
},
|
|
},
|
|
bottom: {
|
|
bottom: {
|
|
position: 'bottom',
|
|
position: 'bottom',
|
|
@@ -154,15 +153,15 @@ Graph.registerNode(
|
|
magnet: true,
|
|
magnet: true,
|
|
stroke: '#C2C8D5',
|
|
stroke: '#C2C8D5',
|
|
strokeWidth: 1,
|
|
strokeWidth: 1,
|
|
- fill: '#fff',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
|
|
+ fill: '#fff'
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
},
|
|
},
|
|
- true,
|
|
|
|
-)
|
|
|
|
|
|
+ true
|
|
|
|
+);
|
|
|
|
|
|
// 注册边
|
|
// 注册边
|
|
Graph.registerEdge(
|
|
Graph.registerEdge(
|
|
@@ -173,61 +172,76 @@ Graph.registerEdge(
|
|
line: {
|
|
line: {
|
|
stroke: '#C2C8D5',
|
|
stroke: '#C2C8D5',
|
|
strokeWidth: 1,
|
|
strokeWidth: 1,
|
|
- targetMarker: 'block',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
|
|
+ targetMarker: 'block'
|
|
|
|
+ }
|
|
|
|
+ }
|
|
},
|
|
},
|
|
- true,
|
|
|
|
-)
|
|
|
|
|
|
+ true
|
|
|
|
+);
|
|
|
|
|
|
// 注册连接
|
|
// 注册连接
|
|
Graph.registerConnector(
|
|
Graph.registerConnector(
|
|
'algo-connector',
|
|
'algo-connector',
|
|
(s, e) => {
|
|
(s, e) => {
|
|
- const offset = 4
|
|
|
|
- const deltaY = Math.abs(e.y - s.y)
|
|
|
|
- const control = Math.floor((deltaY / 3) * 2)
|
|
|
|
|
|
+ const offset = 4;
|
|
|
|
+ const deltaY = Math.abs(e.y - s.y);
|
|
|
|
+ const control = Math.floor((deltaY / 3) * 2);
|
|
|
|
|
|
- const v1 = { x: s.x, y: s.y + offset + control }
|
|
|
|
- const v2 = { x: e.x, y: e.y - offset - control }
|
|
|
|
|
|
+ const v1 = { x: s.x, y: s.y + offset + control };
|
|
|
|
+ const v2 = { x: e.x, y: e.y - offset - control };
|
|
|
|
|
|
return Path.normalize(
|
|
return Path.normalize(
|
|
`M ${s.x} ${s.y}
|
|
`M ${s.x} ${s.y}
|
|
L ${s.x} ${s.y + offset}
|
|
L ${s.x} ${s.y + offset}
|
|
C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
|
|
C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
|
|
L ${e.x} ${e.y}
|
|
L ${e.x} ${e.y}
|
|
- `,
|
|
|
|
- )
|
|
|
|
|
|
+ `
|
|
|
|
+ );
|
|
},
|
|
},
|
|
- true,
|
|
|
|
-)
|
|
|
|
|
|
+ true
|
|
|
|
+);
|
|
|
|
|
|
// 存储边
|
|
// 存储边
|
|
-const dagEdges: Array<any> = []
|
|
|
|
|
|
+const dagEdges: Array<any> = [];
|
|
export default class Dag extends React.Component<any, any> {
|
|
export default class Dag extends React.Component<any, any> {
|
|
// 容器DIV
|
|
// 容器DIV
|
|
- private container: any
|
|
|
|
|
|
+ private container: any;
|
|
// 侧边栏UI容器
|
|
// 侧边栏UI容器
|
|
- private stencilContainer: any
|
|
|
|
|
|
+ private stencilContainer: any;
|
|
// 构造函数
|
|
// 构造函数
|
|
constructor(props: any) {
|
|
constructor(props: any) {
|
|
super(props);
|
|
super(props);
|
|
this.state = {
|
|
this.state = {
|
|
nodeInfoVisible: false,
|
|
nodeInfoVisible: false,
|
|
dagGraph: null,
|
|
dagGraph: null,
|
|
- selectedNodeData: {}
|
|
|
|
|
|
+ selectedNodeData: {},
|
|
|
|
+ contextMenu: null
|
|
};
|
|
};
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
// 展示node节点信息
|
|
// 展示node节点信息
|
|
showNodeInfo = () => {
|
|
showNodeInfo = () => {
|
|
- this.setState({nodeInfoVisible: true})
|
|
|
|
- }
|
|
|
|
|
|
+ this.setState({ nodeInfoVisible: true });
|
|
|
|
+ };
|
|
|
|
|
|
// 隐藏node节点信息
|
|
// 隐藏node节点信息
|
|
hideNodeInfo = () => {
|
|
hideNodeInfo = () => {
|
|
- this.setState({nodeInfoVisible: false})
|
|
|
|
- }
|
|
|
|
|
|
+ this.setState({ nodeInfoVisible: false });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // 右键菜单
|
|
|
|
+ handleContextMenu = (event: React.MouseEvent) => {
|
|
|
|
+ event.preventDefault();
|
|
|
|
+ this.setState({
|
|
|
|
+ contextMenu:
|
|
|
|
+ this.state.contextMenu === null
|
|
|
|
+ ? {
|
|
|
|
+ mouseX: event.clientX + 2,
|
|
|
|
+ mouseY: event.clientY - 6
|
|
|
|
+ }
|
|
|
|
+ : null
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
|
|
// 挂载
|
|
// 挂载
|
|
componentDidMount(): void {
|
|
componentDidMount(): void {
|
|
@@ -243,7 +257,7 @@ export default class Dag extends React.Component<any, any> {
|
|
// 拖动
|
|
// 拖动
|
|
panning: {
|
|
panning: {
|
|
enabled: true,
|
|
enabled: true,
|
|
- eventTypes: ['leftMouseDown', 'mouseWheel'],
|
|
|
|
|
|
+ eventTypes: ['leftMouseDown', 'mouseWheel']
|
|
},
|
|
},
|
|
// 放大缩小
|
|
// 放大缩小
|
|
mousewheel: {
|
|
mousewheel: {
|
|
@@ -251,7 +265,7 @@ export default class Dag extends React.Component<any, any> {
|
|
modifiers: 'ctrl',
|
|
modifiers: 'ctrl',
|
|
factor: 1.1,
|
|
factor: 1.1,
|
|
maxScale: 1.5,
|
|
maxScale: 1.5,
|
|
- minScale: 0.5,
|
|
|
|
|
|
+ minScale: 0.5
|
|
},
|
|
},
|
|
// 交互触发高亮
|
|
// 交互触发高亮
|
|
highlighting: {
|
|
highlighting: {
|
|
@@ -261,10 +275,10 @@ export default class Dag extends React.Component<any, any> {
|
|
attrs: {
|
|
attrs: {
|
|
fill: '#fff',
|
|
fill: '#fff',
|
|
stroke: '#31d0c6',
|
|
stroke: '#31d0c6',
|
|
- strokeWidth: 4,
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
|
|
+ strokeWidth: 4
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
},
|
|
},
|
|
// 连接
|
|
// 连接
|
|
connecting: {
|
|
connecting: {
|
|
@@ -276,27 +290,30 @@ export default class Dag extends React.Component<any, any> {
|
|
connectionPoint: 'anchor',
|
|
connectionPoint: 'anchor',
|
|
anchor: 'center',
|
|
anchor: 'center',
|
|
// 验证
|
|
// 验证
|
|
- validateMagnet({ magnet }) {
|
|
|
|
- return magnet.getAttribute('port-group') !== 'top'
|
|
|
|
|
|
+ validateMagnet({ magnet }) {
|
|
|
|
+ return magnet.getAttribute('port-group') !== 'top';
|
|
},
|
|
},
|
|
- validateConnection({targetPort, sourceCell, targetCell}) {
|
|
|
|
- const jugeEdge = dagEdges.find((item: any) => (item?.source === sourceCell?.id) && (item?.target === targetCell?.id))
|
|
|
|
|
|
+ validateConnection({ targetPort, sourceCell, targetCell }) {
|
|
|
|
+ const jugeEdge = dagEdges.find(
|
|
|
|
+ (item: any) =>
|
|
|
|
+ item?.source === sourceCell?.id && item?.target === targetCell?.id
|
|
|
|
+ );
|
|
if (jugeEdge) {
|
|
if (jugeEdge) {
|
|
- return false
|
|
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
- return targetPort === 'topPort'
|
|
|
|
|
|
+ return targetPort === 'topPort';
|
|
},
|
|
},
|
|
createEdge() {
|
|
createEdge() {
|
|
return graph.createEdge({
|
|
return graph.createEdge({
|
|
shape: 'dag-edge',
|
|
shape: 'dag-edge',
|
|
attrs: {
|
|
attrs: {
|
|
line: {
|
|
line: {
|
|
- strokeDasharray: '5 5',
|
|
|
|
- },
|
|
|
|
|
|
+ strokeDasharray: '5 5'
|
|
|
|
+ }
|
|
},
|
|
},
|
|
- zIndex: -1,
|
|
|
|
- })
|
|
|
|
- },
|
|
|
|
|
|
+ zIndex: -1
|
|
|
|
+ });
|
|
|
|
+ }
|
|
},
|
|
},
|
|
// 选择
|
|
// 选择
|
|
selecting: {
|
|
selecting: {
|
|
@@ -305,98 +322,103 @@ export default class Dag extends React.Component<any, any> {
|
|
rubberEdge: true,
|
|
rubberEdge: true,
|
|
rubberNode: true,
|
|
rubberNode: true,
|
|
modifiers: 'shift',
|
|
modifiers: 'shift',
|
|
- rubberband: true,
|
|
|
|
|
|
+ rubberband: true
|
|
},
|
|
},
|
|
// 快捷键
|
|
// 快捷键
|
|
keyboard: {
|
|
keyboard: {
|
|
enabled: true,
|
|
enabled: true,
|
|
- global: true,
|
|
|
|
- },
|
|
|
|
- })
|
|
|
|
|
|
+ global: true
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
|
|
// 删除节点
|
|
// 删除节点
|
|
graph.bindKey(['delete', 'backspace'], () => {
|
|
graph.bindKey(['delete', 'backspace'], () => {
|
|
graph.getSelectedCells().forEach((item: any) => {
|
|
graph.getSelectedCells().forEach((item: any) => {
|
|
- item.remove()
|
|
|
|
- })
|
|
|
|
- })
|
|
|
|
|
|
+ item.remove();
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
|
|
// 监听边连接
|
|
// 监听边连接
|
|
graph.on('edge:connected', ({ edge }) => {
|
|
graph.on('edge:connected', ({ edge }) => {
|
|
-
|
|
|
|
- dagEdges.push({source: edge.getSourceCell()?.id, target: edge.getTargetCell()?.id})
|
|
|
|
- const targetNodeData = edge.getTargetCell()?.data
|
|
|
|
- targetNodeData.inputNumber += 1
|
|
|
|
|
|
+ dagEdges.push({
|
|
|
|
+ source: edge.getSourceCell()?.id,
|
|
|
|
+ target: edge.getTargetCell()?.id
|
|
|
|
+ });
|
|
|
|
+ const targetNodeData = edge.getTargetCell()?.data;
|
|
|
|
+ targetNodeData.inputNumber += 1;
|
|
edge.attr({
|
|
edge.attr({
|
|
line: {
|
|
line: {
|
|
- strokeDasharray: '',
|
|
|
|
- },
|
|
|
|
- })
|
|
|
|
- })
|
|
|
|
|
|
+ strokeDasharray: ''
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ graph.on('edge:removed', ({ edge }) => {
|
|
|
|
+ const sourceNodeId = (edge as any).store.data.source.cell;
|
|
|
|
+ const targetNodeId = (edge as any).store.data.target.cell;
|
|
|
|
|
|
- graph.on('edge:removed', ({edge}) => {
|
|
|
|
- const sourceNodeId = (edge as any).store.data.source.cell
|
|
|
|
- const targetNodeId = (edge as any).store.data.target.cell
|
|
|
|
-
|
|
|
|
const index = dagEdges.indexOf({
|
|
const index = dagEdges.indexOf({
|
|
source: sourceNodeId,
|
|
source: sourceNodeId,
|
|
target: targetNodeId
|
|
target: targetNodeId
|
|
- })
|
|
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ const targetNode = this.state.dagGraph.getCellById(targetNodeId);
|
|
|
|
|
|
- const targetNode = this.state.dagGraph.getCellById(targetNodeId)
|
|
|
|
-
|
|
|
|
if (targetNode) {
|
|
if (targetNode) {
|
|
- targetNode.data.inputNumber -= 1
|
|
|
|
|
|
+ targetNode.data.inputNumber -= 1;
|
|
}
|
|
}
|
|
|
|
|
|
- dagEdges.splice(index, 1)
|
|
|
|
-
|
|
|
|
- })
|
|
|
|
|
|
+ dagEdges.splice(index, 1);
|
|
|
|
+ });
|
|
|
|
|
|
// 监听状态改变
|
|
// 监听状态改变
|
|
graph.on('node:change:data', ({ node }) => {
|
|
graph.on('node:change:data', ({ node }) => {
|
|
- const edges = graph.getIncomingEdges(node)
|
|
|
|
- const { status } = node.getData() as NodeStatus
|
|
|
|
- edges?.forEach((edge) => {
|
|
|
|
|
|
+ const edges = graph.getIncomingEdges(node);
|
|
|
|
+ const { status } = node.getData() as NodeStatus;
|
|
|
|
+ edges?.forEach(edge => {
|
|
if (status === 'running') {
|
|
if (status === 'running') {
|
|
- edge.attr('line/strokeDasharray', 5)
|
|
|
|
- edge.attr('line/style/animation', 'running-line 30s infinite linear')
|
|
|
|
|
|
+ edge.attr('line/strokeDasharray', 5);
|
|
|
|
+ edge.attr('line/style/animation', 'running-line 30s infinite linear');
|
|
} else {
|
|
} else {
|
|
- edge.attr('line/strokeDasharray', '')
|
|
|
|
- edge.attr('line/style/animation', '')
|
|
|
|
|
|
+ edge.attr('line/strokeDasharray', '');
|
|
|
|
+ edge.attr('line/style/animation', '');
|
|
}
|
|
}
|
|
- })
|
|
|
|
- })
|
|
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
|
|
// 监听节点被双击
|
|
// 监听节点被双击
|
|
- graph.on('node:dblclick', (args: {
|
|
|
|
- cell: Cell
|
|
|
|
- node: Node
|
|
|
|
- options: Model.SetOptions
|
|
|
|
- }) => {
|
|
|
|
- const nodeData = args.cell.data
|
|
|
|
- this.setState({selectedNodeData: nodeData})
|
|
|
|
- this.showNodeInfo()
|
|
|
|
- })
|
|
|
|
-
|
|
|
|
- const text = this.props.context.current
|
|
|
|
|
|
+ graph.on(
|
|
|
|
+ 'node:dblclick',
|
|
|
|
+ (args: { cell: Cell; node: Node; options: Model.SetOptions }) => {
|
|
|
|
+ const nodeData = args.cell.data;
|
|
|
|
+ this.setState({ selectedNodeData: nodeData });
|
|
|
|
+ this.showNodeInfo();
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ //监听右键
|
|
|
|
+ graph.on('node:contextmenu', ({ node, e }) => {
|
|
|
|
+ this.handleContextMenu(e);
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ const text = this.props.context.current;
|
|
text.ready.then(() => {
|
|
text.ready.then(() => {
|
|
const dagJson: any = text.model.toJSON();
|
|
const dagJson: any = text.model.toJSON();
|
|
if (dagJson?.graph) {
|
|
if (dagJson?.graph) {
|
|
- graph.fromJSON(dagJson.graph)
|
|
|
|
|
|
+ graph.fromJSON(dagJson.graph);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
// 内容居中
|
|
// 内容居中
|
|
- graph.centerContent()
|
|
|
|
-
|
|
|
|
|
|
+ graph.centerContent();
|
|
|
|
+
|
|
// 创建侧边栏
|
|
// 创建侧边栏
|
|
const stencil = new Stencil({
|
|
const stencil = new Stencil({
|
|
title: '算子检索',
|
|
title: '算子检索',
|
|
target: graph,
|
|
target: graph,
|
|
// 搜索
|
|
// 搜索
|
|
search(cell, keyword) {
|
|
search(cell, keyword) {
|
|
- return cell.data.label.indexOf(keyword) !== -1
|
|
|
|
|
|
+ return cell.data.label.indexOf(keyword) !== -1;
|
|
},
|
|
},
|
|
placeholder: '搜索算子',
|
|
placeholder: '搜索算子',
|
|
notFoundText: '未找到相关算子',
|
|
notFoundText: '未找到相关算子',
|
|
@@ -433,44 +455,55 @@ export default class Dag extends React.Component<any, any> {
|
|
],
|
|
],
|
|
// 拖拽事件 处理节点数据
|
|
// 拖拽事件 处理节点数据
|
|
getDropNode(draggingNode: Node): Node {
|
|
getDropNode(draggingNode: Node): Node {
|
|
- console.log(123);
|
|
|
|
-
|
|
|
|
- const newNode = draggingNode.clone()
|
|
|
|
- initNodeData(newNode)
|
|
|
|
- return newNode
|
|
|
|
- },
|
|
|
|
- })
|
|
|
|
|
|
+
|
|
|
|
+ const newNode = draggingNode.clone();
|
|
|
|
+ initNodeData(newNode);
|
|
|
|
+ return newNode;
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
|
|
// 添加到侧边栏容器内
|
|
// 添加到侧边栏容器内
|
|
- this.stencilContainer.appendChild(stencil.container)
|
|
|
|
|
|
+ this.stencilContainer.appendChild(stencil.container);
|
|
|
|
|
|
// 将可拖拽项加载到侧边栏中
|
|
// 将可拖拽项加载到侧边栏中
|
|
- stencil.load(dataSourceNodes, 'dataSource')
|
|
|
|
- stencil.load(dataHandleNodes, 'dataHandle')
|
|
|
|
- stencil.load(otherScriptNodes, 'otherScript')
|
|
|
|
- stencil.load(customScriptNodes, 'customScript')
|
|
|
|
- stencil.resizeGroup('dataSource', { width: 200, height: dataSourceNodes.length * 120 })
|
|
|
|
- stencil.resizeGroup('dataHandle', { width: 200, height: dataHandleNodes.length * 60 })
|
|
|
|
- stencil.resizeGroup('otherScript', { width: 200, height: otherScriptNodes.length * 60 })
|
|
|
|
- stencil.resizeGroup('customScript', { width: 200, height: customScriptNodes.length * 60 })
|
|
|
|
-
|
|
|
|
|
|
+ stencil.load(dataSourceNodes, 'dataSource');
|
|
|
|
+ stencil.load(dataHandleNodes, 'dataHandle');
|
|
|
|
+ stencil.load(otherScriptNodes, 'otherScript');
|
|
|
|
+ stencil.load(customScriptNodes, 'customScript');
|
|
|
|
+ stencil.resizeGroup('dataSource', {
|
|
|
|
+ width: 200,
|
|
|
|
+ height: dataSourceNodes.length * 120
|
|
|
|
+ });
|
|
|
|
+ stencil.resizeGroup('dataHandle', {
|
|
|
|
+ width: 200,
|
|
|
|
+ height: dataHandleNodes.length * 60
|
|
|
|
+ });
|
|
|
|
+ stencil.resizeGroup('otherScript', {
|
|
|
|
+ width: 200,
|
|
|
|
+ height: otherScriptNodes.length * 60
|
|
|
|
+ });
|
|
|
|
+ stencil.resizeGroup('customScript', {
|
|
|
|
+ width: 200,
|
|
|
|
+ height: customScriptNodes.length * 60
|
|
|
|
+ });
|
|
|
|
+
|
|
// 设置图
|
|
// 设置图
|
|
- this.setState({dagGraph: graph})
|
|
|
|
|
|
+ this.setState({ dagGraph: graph });
|
|
}
|
|
}
|
|
|
|
|
|
// 卸载
|
|
// 卸载
|
|
componentWillUnmount(): void {
|
|
componentWillUnmount(): void {
|
|
- this.state.dagGraph.dispose()
|
|
|
|
|
|
+ this.state.dagGraph.dispose();
|
|
}
|
|
}
|
|
// 容器
|
|
// 容器
|
|
refContainer = (container: HTMLDivElement) => {
|
|
refContainer = (container: HTMLDivElement) => {
|
|
- this.container = container
|
|
|
|
- }
|
|
|
|
|
|
+ this.container = container;
|
|
|
|
+ };
|
|
|
|
|
|
// 侧边栏
|
|
// 侧边栏
|
|
refStencil = (container: HTMLDivElement) => {
|
|
refStencil = (container: HTMLDivElement) => {
|
|
- this.stencilContainer = container
|
|
|
|
- }
|
|
|
|
|
|
+ this.stencilContainer = container;
|
|
|
|
+ };
|
|
|
|
|
|
// 最后输出模板
|
|
// 最后输出模板
|
|
render() {
|
|
render() {
|
|
@@ -479,8 +512,14 @@ export default class Dag extends React.Component<any, any> {
|
|
{/* 侧边栏 */}
|
|
{/* 侧边栏 */}
|
|
<div className="app-stencil" ref={this.refStencil} />
|
|
<div className="app-stencil" ref={this.refStencil} />
|
|
{/* 容器 */}
|
|
{/* 容器 */}
|
|
- <div className='app-content'>
|
|
|
|
|
|
+ <div className="app-content">
|
|
<div className="app-graph" ref={this.refContainer} />
|
|
<div className="app-graph" ref={this.refContainer} />
|
|
|
|
+ <ContextMenuView
|
|
|
|
+ contextData={this.state.contextMenu}
|
|
|
|
+ onSetContextData={contextData =>
|
|
|
|
+ this.setState({ contextMenu: contextData })
|
|
|
|
+ }
|
|
|
|
+ />
|
|
{/* 节点信息 */}
|
|
{/* 节点信息 */}
|
|
<Drawer
|
|
<Drawer
|
|
title={this.state.selectedNodeData?.label || 'NodeTitle'}
|
|
title={this.state.selectedNodeData?.label || 'NodeTitle'}
|
|
@@ -493,34 +532,42 @@ export default class Dag extends React.Component<any, any> {
|
|
style={{ position: 'absolute' }}
|
|
style={{ position: 'absolute' }}
|
|
>
|
|
>
|
|
{/* 数据源节点 */}
|
|
{/* 数据源节点 */}
|
|
- {this.state.selectedNodeData?.type === 'datasource' && <DatasourceNodeInfo nodeInfo={this.state.selectedNodeData}/>}
|
|
|
|
|
|
+ {this.state.selectedNodeData?.type === 'datasource' && (
|
|
|
|
+ <DatasourceNodeInfo nodeInfo={this.state.selectedNodeData} />
|
|
|
|
+ )}
|
|
{/* 脚本节点 */}
|
|
{/* 脚本节点 */}
|
|
- {this.state.selectedNodeData?.type === 'script' && <ScriptNodeInfo nodeInfo={this.state.selectedNodeData}/>}
|
|
|
|
|
|
+ {this.state.selectedNodeData?.type === 'script' && (
|
|
|
|
+ <ScriptNodeInfo nodeInfo={this.state.selectedNodeData} />
|
|
|
|
+ )}
|
|
</Drawer>
|
|
</Drawer>
|
|
{/* 工具栏 */}
|
|
{/* 工具栏 */}
|
|
- <ToolBar className="app-tool" graph={this.state.dagGraph} saveGraph={this.props.saveGraph}/>
|
|
|
|
|
|
+ <ToolBar
|
|
|
|
+ className="app-tool"
|
|
|
|
+ graph={this.state.dagGraph}
|
|
|
|
+ saveGraph={this.props.saveGraph}
|
|
|
|
+ />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- )
|
|
|
|
|
|
+ );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// 初始化节点数据
|
|
// 初始化节点数据
|
|
function initNodeData(newNode: Node<Node.Properties>) {
|
|
function initNodeData(newNode: Node<Node.Properties>) {
|
|
// 节点id
|
|
// 节点id
|
|
- newNode.data.id = newNode.id
|
|
|
|
- switch(newNode.data.type) {
|
|
|
|
|
|
+ newNode.data.id = newNode.id;
|
|
|
|
+ switch (newNode.data.type) {
|
|
case 'datasource':
|
|
case 'datasource':
|
|
- newNode.data.inputSource = undefined
|
|
|
|
- newNode.data.dataTable = undefined
|
|
|
|
- break
|
|
|
|
|
|
+ newNode.data.inputSource = undefined;
|
|
|
|
+ newNode.data.dataTable = undefined;
|
|
|
|
+ break;
|
|
case 'script':
|
|
case 'script':
|
|
- newNode.data.paramText = undefined
|
|
|
|
- newNode.data.scriptText = undefined
|
|
|
|
- newNode.data.outputData = undefined
|
|
|
|
- newNode.data.inputNumber = 0
|
|
|
|
- newNode.data.packageData = undefined
|
|
|
|
- break
|
|
|
|
|
|
+ newNode.data.paramText = undefined;
|
|
|
|
+ newNode.data.scriptText = undefined;
|
|
|
|
+ newNode.data.outputData = undefined;
|
|
|
|
+ newNode.data.inputNumber = 0;
|
|
|
|
+ newNode.data.packageData = undefined;
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
+}
|